Skip to content

Instantly share code, notes, and snippets.

@Tom-Alexander
Created October 26, 2013 08:05
Show Gist options
  • Save Tom-Alexander/7166606 to your computer and use it in GitHub Desktop.
Save Tom-Alexander/7166606 to your computer and use it in GitHub Desktop.
Weighted Linear Regression
function weightedLinearRegression(data, weights){
var sums = {xw: 0, x: 0, yw: 0, y: 0, a: 0, b: 0};
// compute the weighted averages
for(var i = 0; i < data.length; i++){
sums.xw += data[i][0] * weights[i];
sums.yw += data[i][1] * weights[i];
sums.x += data[i][0];
sums.y += data[i][1];
}
weightedX = sums.xw / sums.x;
weightedY = sums.yw / sums.y;
// compute the gradient and intercept
for(var i = 0; i < data.length; i++){
sums.a += (data[i][1] - weightedY) * (data[i][0] - weightedX) * weights[i];
sums.b += (data[i][0] - weightedX) * (data[i][0] - weightedX) * weights[i];
}
var gradient = sums.a/sums.b;
var intercept = (weightedY - weightedX) * gradient;
var string = 'y = ' + Math.round(gradient*100) / 100 + 'x + ' + Math.round(intercept*100) / 100;
var results = [];
//interpolate result
for (var i = 0, len = data.length; i < len; i++) {
var coordinate = [data[i][0], data[i][0] * gradient + intercept];
results.push(coordinate);
}
return {equation: [gradient, intercept], points: results, string: string};
}
@gustawdaniel
Copy link

I cant understand your method of calculating but it is wrong:

Below I append correct function

/**
 *
 * @param data [[x0,y0],[x2,y1],...]
 * @param weights [w0,w1,...]
 * @return {{equation: number[], points: Array, string: string}}
 */
function weightedLinearRegression(data, weights){

    let sums = {w: 0, wx: 0, wx2: 0, wy: 0, wxy: 0};

    // compute the weighted averages
    for(let i = 0; i < data.length; i++){
        sums.w += weights[i];
        sums.wx += data[i][0] * weights[i];
        sums.wx2 += data[i][0] * data[i][0] * weights[i];
        sums.wy += data[i][1] * weights[i];
        sums.wxy += data[i][0] * data[i][1] * weights[i];
    }

    const denominator = sums.w * sums.wx2 - sums.wx * sums.wx;

    let gradient = (sums.w * sums.wxy - sums.wx * sums.wy) / denominator;
    let intercept = (sums.wy * sums.wx2 - sums.wx * sums.wxy) / denominator;
    let string = 'y = ' + Math.round(gradient*100) / 100 + 'x + ' + Math.round(intercept*100) / 100;
    let results = [];

    //interpolate result
    for (let i = 0, len = data.length; i < len; i++) {
        let coordinate = [data[i][0], data[i][0] * gradient + intercept];
        results.push(coordinate);
    }

    return {equation: [gradient, intercept], points: results, string: string};

}

Source: http://mathworld.wolfram.com/LeastSquaresFitting.html

Tests:

const measurements = [
    { price: 16, weight: 1, conversion: 0.08 },
    // { price: 16, weight: 1, conversion: 0.08 },
    { price: 9.5, weight: 1, conversion: 0.37 },
    { price: 2, weight: 1, conversion: 0.45 }
];

console.log(weightedLinearRegression(measurements.map(m => {
    return [m.price, m.conversion];
}), measurements.map(m => m.weight)));

Your version gives:

{ equation: [ -0.06606873428331937, -0 ],
  points: 
   [ [ 16, -1.05709974853311 ],
     [ 9.5, -0.627652975691534 ],
     [ 2, -0.13213746856663874 ] ],
  string: 'y = -0.07x + 0' }

My version

{ equation: [ -0.026027164685908315, 0.5385823429541596 ],
  points: 
   [ [ 16, 0.1221477079796266 ],
     [ 9.5, 0.29132427843803066 ],
     [ 2, 0.486528013582343 ] ],
  string: 'y = -0.03x + 0.54' }

26 Oct 2013 you wrote in issue

Tom-Alexander/regression-js#2

that this was not tested. So I hope presended code can help somebody.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment