Regressão Linear, de Potência e Polinomial em Javascript

Eu custei a conseguir fazer funcionar e a achar na internet, então resolvi trazer pra cá.

var regression = {
    
    linear: function(x, y){
    
        var lr = {};
        var n = y.length;
        var sum_x = 0;
        var sum_y = 0;
        var sum_xy = 0;
        var sum_xx = 0;
        var sum_yy = 0;
        
        for (var i = 0; i < y.length; i++) {
            sum_x += x[i];
            sum_y += y[i];
            sum_xy += (x[i] * y[i]);
            sum_xx += (x[i] * x[i]);
            sum_yy += (y[i] * y[i]);
        } 
        
        lr['slope'] = ((n * sum_xy) - (sum_x * sum_y)) / ((n * sum_xx) - (sum_x * sum_x));
        lr['intercept'] = (sum_y - (lr.slope * sum_x)) / n;
        lr['r2'] = Math.pow((n*sum_xy - sum_x*sum_y) / Math.sqrt(((n * sum_xx) - (sum_x * sum_x)) * ((n * sum_yy) - (sum_y * sum_y))), 2);
        lr['fn'] = function (x) { 
            return this.slope * x + this.intercept; 
        };
        
        return lr;
        
    },

    power: function(data_x, data_y) {
    
        var n = data_x.length;
        if (n < 2 || n != data_y.length) {
            return false;
        }
    
        var sumX = 0;
        var sumY = 0;
        var sumXX = 0;
        var sumXY = 0;
        for (var i = 0; i < n; i++) {
            var x = Math.log(data_x[i]);
            var y = Math.log(data_y[i]);
            sumX += x;
            sumY += y;
            var xx = x * x;
            sumXX += xx;
            var xy = x * y;
            sumXY += xy;
        }
        var sxx = sumXX - (sumX * sumX) / n;
        var sxy = sumXY - (sumX * sumY) / n;
        var xbar = sumX / n;
        var ybar = sumY / n;
        
        var b = sxy / sxx;
        var a = Math.pow(Math.exp(1.0), ybar - b * xbar);
    
        return {
            a: a,
            b: b
        };
    
    },
    
    polynomial: function(data_x, data_y, order) {
        
        var itemCount = data_x.length;
        
        if (itemCount < order + 1) {
            //return false;
        }
        
        var validItems = 0;
        
        var data = {};
        var validItems = 0;
        
        var item;
        for(item = 0; item < itemCount; item++){
            
            var x = data_x[item];
            var y = data_y[item];

            if (!isNaN(x) && !isNaN(y)){
                
                if (typeof data[0] != "object") {
                    data[0] = {};
                }
                
                if (typeof data[1] != "object") {
                    data[1] = {};
                }
                
                data[0][validItems] = x;
                data[1][validItems] = y;
                
                validItems++;
                
            }
            
        }
        
        if (validItems < order + 1) {
            //return false;
        }
        
        var equations = order + 1;
        var coefficients = order + 2;
        
        var result = {};
        var matrix = {};
        
        var sumX = 0;
        var sumY = 0;
        
        for(item = 0; item < validItems; item++){
            
            sumX += data[0][item];
            sumY += data[1][item];
            
            var eq;
            for(eq = 0; eq < equations; eq++){
                
                var coe;
                for(coe = 0; coe < coefficients - 1; coe++){
                    
                    if (typeof matrix[eq] != "object") {
                        matrix[eq] = {};
                    }
                    
                    if (typeof matrix[eq][coe] == "undefined") {
                         matrix[eq][coe] = 0;
                    }
                    
                    matrix[eq][coe] += Math.pow(data[0][item], eq + coe);
                    
                }
                
                if (typeof matrix[eq][coefficients - 1] == "undefined") {
                    matrix[eq][coefficients - 1] = 0;
                }
                
                matrix[eq][coefficients - 1] += data[1][item] * Math.pow(data[0][item],eq);
                
            }
            
        }
        
        var subMatrix = regression.calculateSubMatrix(matrix);
        
        var eq;
        for (eq = 1; eq < equations; eq++) {
            
            matrix[eq][0] = 0;
            
            var coe;
            for (coe = 1; coe < coefficients; coe++) {
                matrix[eq][coe] = subMatrix[eq - 1][coe - 1];
            }
            
        }
        
        for (eq = equations - 1; eq > -1; eq--) {
            
            var value = matrix[eq][coefficients - 1];
            
            var coe;
            for (coe = eq; coe < coefficients -1; coe++) {
                value -= matrix[eq][coe] * (isNaN(result[coe]) ? 0 : result[coe]);
            }
            
            result[eq] = value / matrix[eq][eq];
            
        }
        
        var meanY = sumY / validItems;
        var yObsSquare = 0;
        var yRegSquare = 0;
        
        for (item = 0; item < validItems; item++) {
            var yCalc = 0;
            
            var eq;
            for (eq = 0; eq < equations; eq++) {
                yCalc += result[eq] * Math.pow(data[0][item],eq);
            }
            
            yRegSquare += Math.pow(yCalc - meanY, 2);
            yObsSquare += Math.pow(data[1][item] - meanY, 2);
            
        }
        var rSquare = yRegSquare / yObsSquare;
        
        result['r2'] = rSquare;
        
        return result;
        
    },
    
    calculateSubMatrix: function(matrix){
        
        var equations = (typeof matrix == "object" ? Object.keys(matrix).length : 0);
        var coefficients = (typeof matrix[0] == "object" ? Object.keys(matrix[0]).length : 0);
        
        var result = {};
        
        var eq;
        for (eq = 1; eq < equations; eq++) {
            
            var factor = matrix[0][0] / matrix[eq][0];
            
            var coe;
            for (coe = 1; coe < coefficients; coe++) {
                
                if (typeof result[eq - 1] != "object") {
                    result[eq - 1] = {};
                }
                
                result[eq - 1][coe -1] = matrix[0][coe] - matrix[eq][coe] * factor;
                
            }
            
        }
        
        if (equations == 1) {
            return result;
        }
        
        // check for zero pivot element
        if (result[0][0] == 0) {
            
            var found = false;
            
            var i;
            for (i = 0; i < result.length; i ++) {
                
                if (result[i][0] != 0) {
                    found = true;
                    var temp = result[0];
                    var j;
                    for (j = 0; j < result[i].length; j++) {
                        result[0][j] = result[i][j];
                    }
                    for (j = 0; j < temp.length; j++) {
                        result[i][j] = temp[j];
                    }
                    break;
                }
                
            }
            
            if (!found) {
                
                var i, j;
                
                var retorno = {};
                
                for (i = 0; i < equations; i++) {
                    for (j = 0; j < coefficients; j++) {
                        if (typeof retorno[i] != "object") {
                            retorno[i] = {};
                        }
                        retorno[i][j] = 0;
                    }
                }
                
                return retorno;
                
            }
            
        }
        
        var subMatrix = regression.calculateSubMatrix(result);
        
        for (eq = 1; eq < equations -  1; eq++) {
            result[eq][0] = 0;
            
            var coe;
            for (coe = 1; coe < coefficients - 1; coe++) {
                result[eq][coe] = subMatrix[eq - 1][coe - 1];
            }
            
        }
        
        return result;
        
    }
    
}

Para usar:

regression.linear(x, y);
retorno: { slope, intercept, r2, fn(x) }

regression.power(x, y);
retorno: { a, b }

regression.polynomial(x, y, order);
retorno: { 0, 1, 2, ..., r2 }

Ainda tenho que limpar o código, comentar, etc, mas já dá pra vocês usarem.

Portei o código da biblioteca Jfree de Java.


Tags: , , , , , , , , , ,
This entry was posted on terça-feira, setembro 11th, 2012 at 11:06 and is filed under Uncategorized. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.