我用JavaScript编写了一个梯度下降的线性回归模型,我几乎做到了,没有错误,但是有些错误,因为回归线不在正确的位置,并且一段时间之后线开始从这些观点走得更远 . 我正在使用安德鲁的Ng Coursera课程中的公式 . 我做错了什么?
这是我的代码:
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
width = canvas.width = 650,
height = canvas.height = 650,
stop = false;
let data;
let graph;
let n;
let off;
let theta;
let X,Y;
let alpha;
let timer;
setup();
draw();
function setup(){
console.clear();
console.log('ready');
data = [];
graph = false;
n = 11;
off = Math.floor(width/n);
theta = [0,1];
X = [];
Y = [];
alpha = 0.01;
timer = 0;
};
function draw(){
ctx.clearRect(0,0,width,height);
grid(n,n);
for(let i = 0; i < data.length; i++){
let pos = getCoor(data[i]);
arc(pos.x,pos.y,2);
if(graph){
if(data[i+1] != undefined){
let pos1 = getCoor(data[i+1]);
line(pos.x,pos.y,pos1.x,pos1.y);
}
}
}
if(timer % 50 == 0 && timer > 0){
//console.log(J(X,Y,theta));
console.log(theta);
}
if(data.length > 1){
theta = GradientDescend(X,Y,theta,alpha);
regLine();
}
timer++;
if(!stop){
requestAnimationFrame(draw);
};
};
if(stop){
cancelAnimationFrame(draw);
};
function getCoor(data){
let xx = data.x*width/n;
let yy = height-data.y*height/n;
return {x:xx,y:yy};
}
function regLine(){
let m = theta[1];
let b = theta[0];
let x1 = 0;
let y1 = height-m*x1+(b/11*width);
let x2 = width;
let y2 = height-m*x2+(b/11*width);
line(x1,y1,x2,y2);
}
function grid(cx,cy){
for(let d = 0; d < width; d+=off){
ctx.lineWidth = 0.5;
stroke(0);
line(d,0,d,height);
line(0,d,width,d);
}
};
document.addEventListener("click",function(e){
let xx = (e.clientX/width)*n;
let yy = (1-e.clientY/height)*n;
data.push({x:xx,y:yy});
X.push([1,xx]);
Y.push(yy);
});
document.addEventListener("dblclick",function(e){
graph = !graph;
});
document.addEventListener("keydown",function(e){
if(e.keyCode == 32){
data = [];
X = [];
Y = [];
}
})
function h(X,theta){
let y = 0;
for(let i = 0; i < theta.length; i++){
y += theta[i]*X[i];
}
return y;
};
function J(X,Y,theta){
let m = Y.length;
let sum = 0;
for(let i = 0; i < m; i++){
let err = h(X[i],theta)-Y[i];
sum += err*err;
}
return sum/m;
}
function GradientDescend(X,Y,theta,alpha){
let m = Y.length;
let thetaTT = theta;
for(let i = 0; i < m; i++){
for(let j = 0; j < thetaTT.length; j++){
thetaTT[j] -= alpha*(1/m)*(h(X[i],thetaTT)-Y[i])*X[i][j];
}
}
return thetaTT;
}
function arc(x, y, r,stroke){
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI*2, false);
if(stroke){
ctx.stroke();
}else{
ctx.fill();
}
}
function line(x, y, x1, y1){
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x1, y1);
ctx.stroke();
}
function stroke(r,g,b,a){
if(typeof r === 'string'){
ctx.strokeStyle = r;
}
if(!a){
ctx.strokeStyle = 'rgb('+r+','+g+','+b+')';
}
if(arguments.length == 1){
ctx.strokeStyle = 'rgb('+r+','+r+','+r+')';
}
if(arguments.length == 2){
ctx.strokeStyle = 'rgba('+r+','+r+','+r+','+g+')';
}else{
ctx.strokeStyle = 'rgba('+r+','+g+','+b+','+a+')';
}
}
#canvas {
background-color: #cccccc;
width: 650px;
height: 650px;
position: absolute;
border: solid #999999 0.5px;
}
<canvas id="canvas"></canvas>