Преобразовать взвешенный код линейной регрессии из Python в JS
Я пытаюсь преобразовать код, который user3658307 с сайта Math любезно предоставил мне (в формате Python) здесь. Я не очень хорош в математике, но я думаю, что я делаю что-то не так, поскольку мой вывод, кажется, увеличивается линейно вместо того, что должен делать исходный код Python. Что я делаю неправильно или кто-то более опытный с этим видом исчисления может помочь мне преобразовать его в Javascript? Спасибо!
Код Python:
import os, sys, numpy as np
from sklearn import linear_model
x = np.array([13,14,15,16,17,18]).reshape((6,1))
yRaw = [0.015,0.01,0.005,0.002,0.001,0.0005]
y = np.array([ np.log(v) for v in yRaw ])
w = [100] + ([1]*4) + [10] # Weight the various data points
print("Transformed data\n"+str(x)+"\n"+str(y))
# Fit linear function to transformed data
regr = linear_model.LinearRegression()
regr.fit(x,y,sample_weight=w)
print('Coefficient: \n', regr.coef_)
print('Intercept: \n', regr.intercept_)
# Look at function explicitly
a,b = regr.coef_[0],regr.intercept_
f = lambda x: np.exp( a*x + b )
print('Outputs of function')
for x in range(1,19): print(str(x)+": "+str(f(x)))
Мой код ( fiddle (использует num.js) линейная функция отсюда):
var code = function() {
var x = nj.array([13, 14, 15, 16, 17, 18]).reshape(6, 1);
var yRaw = [0.015, 0.01, 0.005, 0.002, 0.001, 0.0005];
var y = nj.array(nj.log(yRaw));
//var w = 100 + (1 * 4) + 10 // Weight the various data points
var w = [100, 1, 1, 1, 1, 10];
console.log('Transformed data', x.selection.data, y.selection.data);
var array = [];
for (var i = 0; i < 6; i++)
array.push([x.selection.data[i], y.selection.data[i]]);
var regr = weightedLinearRegression(array, w);
var a = regr.equation[0];
var b = regr.equation[1];
var f = (x) => { return a * x + b };
for (var i = 1; i <= 19; i++)
console.log(i, f(i));
}
var weightedLinearRegression = function (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];
}
var weightedX = sums.xw / sums.x;
var 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 };
}
code();
Правильный вывод Vs. Мой вывод:
MY OUTPUT (WRONG) | CORRECT OUTPUT
-------------------------------------------
1 -3.4140439207888633 | 1 51.2498600531
2 1.6212123570552457 | 2 26.0231972143
3 6.656468634899355 | 3 13.2138271705
4 11.691724912743464 | 4 6.70959940293
5 16.726981190587573 | 5 3.40694059086
6 21.76223746843168 | 6 1.72994593159
7 26.797493746275787 | 7 0.878416528378
8 31.8327500241199 | 8 0.446034516593
9 36.868006301964016 | 9 0.226483431909
10 41.903262579808114 | 10 0.115001738702
11 46.93851885765223 | 11 0.0583945580167
12 51.97377513549634 | 12 0.0296510682748
13 57.00903141334045 | 13 0.0150559552071
14 62.04428769118455 | 14 0.00764497876085
15 67.07954396902866 | 15 0.00388189918541
16 72.11480024687278 | 16 0.00197111617404
17 77.15005652471689 | 17 0.00100087580485
18 82.185312802561 | 18 0.00050821579668
Любая помощь очень ценится. Спасибо!:)
1 ответ
Хорошо, после долгих исследований мне наконец удалось это сделать! К счастью, у кого-то еще была та же проблема, что и у меня, и я создал здесь класс для C#, который я преобразовал в JS. Я оставлю это здесь для будущих читателей, которые хотят взвешенную функцию линейной регрессии в JS без каких-либо внешних библиотек. Я не уверен, что внутренности правы (я отстой в математике), но это дает мне результат, который мне нужен:)
let linearRegressionWeighted = (values) => {
let sumFn = (input) => {
var total = 0;
for (var i = 0; i < input.length; i++) {
if (isNaN(input[i])) {
continue;
}
total += Number(input[i]);
}
return total;
}
let sum = sumFn(values.map(x => x.weight));
let xAvg = sumFn(values.map(x => x.x * x.weight)) / sum;
let yAvg = sumFn(values.map(x => x.y * x.weight)) / sum;
let sumXY = sumFn(values.map(x => (x.x - xAvg) * (x.y - yAvg) * x.weight));
let sumXX = sumFn(values.map(x => Math.pow(x.x - xAvg, 2) * x.weight));
let m = sumXX == 0 ? 0 : (sumXY / sumXX);
let b = yAvg - m * xAvg;
return {
coefficient: m,
intercept: b
};
}
let r = linearRegressionWeighted(
[
{ x: 13, y: Math.log(0.015), weight: 100 },
{ x: 14, y: Math.log(0.01), weight: 1 },
{ x: 15, y: Math.log(0.005), weight: 1 },
{ x: 16, y: Math.log(0.002), weight: 1 },
{ x: 17, y: Math.log(0.001), weight: 1 },
{ x: 18, y: Math.log(0.0005), weight: 10 },
]
);
let a = r.coefficient;
let b = r.intercept;
let f = (x) => Math.exp(a * x + b);
for (let i = 1; i < 19; i++)
console.log(i, f(i));