机器学习+JavaScript
动画版机器学习
网易云课堂
JavaScript简易note
-
变量
var applecount = 3;
applecount = 5;
console.log(“变量applecont的值是” + applecount); -
对象
var apple1 = {weight:1,price:2};
var house = {area:85,price:705};
console.log(“苹果的重量是” + apple1.weight + “斤”);
apple1.price = 200;
console.log(“苹果的售价是” + apple1.price + “元”); -
数组
var apples = [{weight:1, price:2},{weight:2, price:4},{weight:3, price:6];
var answers = [2,3,4];console.log(“第一个苹果的重量是:” + apples[0].weight +“斤”);
console.log(“第二个苹果的价格是:” + apples[1].price + “元”);
apples[0].price = 200;
-
判断
console.log(“小李第一题回答是否正确?” + (answers[0] == apples[0].price));
If(answers[0] == apples[0].price){
console.log(“奖励”);
}else{
console.log(“惩罚”);
} -
循环
for(var i = 0; i<3; i++){
Console.log(“当前循环到第” + i + “个”);
} -
四则运算
线性回归模型
房屋售价(样本标签)=房屋单价×房屋面积(样本特征
)+居间服务费
y=w×x+b(线性模型)
预测结果取值连续=>预测模型为回归模型
预测结果取值离散=>预测模型为分类模型
因此,房价的取值连续=>房间预测模型为线性回归模型
录入并绘制房屋样本数据
序号 | 房子面积(单位:百平米) | 房子售价(单位:百万元) |
---|---|---|
1 | 0.85 | 7.05 |
2 | 1.03 | 8.6 |
3 | 1.118 | 9.25 |
4 | 1.17 | 9.7 |
5 | 1.19 | 9.88 |
6 | 1.25 | 10.35 |
7 | 1.309 | 10.82 |
8 | 0.92 | 7.65 |
9 | 1.08 | 8.95 |
10 | 1.15 | 9.55 |
前7套房源数据作为训练样本集,后3套作为测试样本集。
训练样本集的代码定义如下:
var trainData = [{area:0.85,money:7.05},{area:1.03,money:8.6},
{area:1.118,money:9.25},{area:1.17,money:9.7},
{area:1.19,money:9.88},{area:1.25,money:10.35},
{ares:1.309,money:10.82}];
测试样本集的代码定义如下:
var testData = [{area:0.92,money:7.65},{area:1.08,money:8.95},
{area:1.15,money:9.55},{area:1.2,money:9.95}];
打印:
console.log("训练样本集中的第一个样本的面积特征是:" + trainData[0].area + "售价标签是:" + trainData[0].money);
绘制:
plot(trainData,{x:"area",y:"money"});
函数定义与调用
function yaohe(){
console.log("买不了吃亏");
console.log("买不了上当");
}
//上地店
yaohe();
//五道口店
yaohe();
//知春路店
yaohe();
个性化:
function yaohe(music,shopName){
console.log("welcome!" + shopName);
if(music == 1){
console.log("播放背景音乐:朗格里格朗~");
}else{
console.log("播放背景音乐:咚咚锵~");
}
}
//上地店
yaohe(1,"上地店");
//五道口店
yaohe(2,"五道口店");
//知春路店
yaohe(2,"知春路店");
定义房价预测函数
function predict(x,w,b){
var yhat = w*x + b;
console.log("预测的房屋售价为:" + yhat);
}
predict(trainData[0].area,1,0);
//后续调整w,b
使用预测结果:
function predict(x,w,b){
var yhat = w*x + b;
return yhat;
}
var house1Predict = predict(trainData[0].area,1,0);
console.log("预测的第一个房屋售价为:" + house1Predict);
var house2Predict = predict(trainData[1].area,1,0);
console.log("预测的第二个房屋售价为:" + house2Predict);
//后续调整w,b
对比损失函数
yhat = w*x+b
-
L=|yhat-y| (曼哈顿距离)
-
L=(yhat-y)2(欧氏距离) √
找到合适的w,b => 梯度下降法
损失函数概述
上几节预测函数:
function predict(x,w,b){
var yhat = w*x + b;
return yhat;
}
还不知道预测函数中的w和b是多少,在找到w和b之前,应该知道怎么衡量w和b到底合不合格。假设现在有3个预测函数,对5个样本的预测结果如下:
序号 | 样本标签(标准答案) | 第一个预测函数 | 第二个预测函数 | 第三个预测函数 |
---|---|---|---|---|
1 | 10 | 6 | 6 | 8 |
2 | 10 | 9 | 9 | 8 |
3 | 10 | 10 | 9 | 8 |
4 | 10 | 11 | 9 | 8 |
5 | 10 | 14 | 7 | 8 |
现将数据录入:
var labels = [10,10,10,10,10];
var answers1 = [6,9,10,11,14];
var answers2 = [6,9,9,9,7];
var answers3 = [8,8,8,8,8];
console.log("5个样本的样本标签是:" + labels);
预测结果直接减去样本标签?
var loss = 0;
//labels.length表示labels数组中元素的个数,数组自带属性
for(var i = 0; i < labels.length; i++){
loss1 = loss1 + answers1[i] - labels[i];
loss2 = loss2 + answers2[i] - labels[i];
loss3 = loss3 + answers3[i] - labels[i];
}
console.log("第一个预测函数的总误差是:" + loss1);//0
console.log("第二个预测函数的总误差是:" + loss2);//-10
console.log("第三个预测函数的总误差是:" + loss3);//-10
损失函数——曼哈顿距离
console.log("-2的绝对值是:" + Math.abs(-2));
曼哈顿:差值的绝对值作为损失大小
预测结果减样本标签的绝对值?
var loss = 0;
//labels.length表示labels数组中元素的个数,数组自带属性
for(var i = 0; i < labels.length; i++){
loss1 = loss1 + Math.abs(answers1[i] - labels[i]);
loss2 = loss2 + Math.abs(answers2[i] - labels[i]);
loss3 = loss3 + Math.abs(answers3[i] - labels[i]);
}
console.log("第一个预测函数的总误差是:" + loss1);//10
console.log("第二个预测函数的总误差是:" + loss2);//10
console.log("第三个预测函数的总误差是:" + loss3);//10
损失函数——欧氏距离
console.log("-2的平方是:" + Math.pow(-2,2));
console.log("-2的立方是:" + Math.pow(-2,3));
欧几里得距离:差值的平方作为损失大小
var loss = 0;
//labels.length表示labels数组中元素的个数,数组自带属性
for(var i = 0; i < labels.length; i++){
loss1 = loss1 + Math.pow((answers1[i] - labels[i]),2);
loss2 = loss2 + Math.pow((answers2[i] - labels[i]),2);
loss3 = loss3 + Math.pow((answers3[i] - labels[i]),2);
}
console.log("第一个预测函数的总损失是:" + loss1);//34
console.log("第二个预测函数的总损失是:" + loss2);//28
console.log("第三个预测函数的总损失是:" + loss3);//20 √
一般, 由于平方求导多一个2,会先乘一个1/2(让后面的梯度下降公式更加清晰):
var loss = 0;
//labels.length表示labels数组中元素的个数,数组自带属性
for(var i = 0; i < labels.length; i++){
loss1 = loss1 + 1/2*Math.pow((answers1[i] - labels[i]),2);
loss2 = loss2 + 1/2*Math.pow((answers2[i] - labels[i]),2);
loss3 = loss3 + 1/2*Math.pow((answers3[i] - labels[i]),2);
}
console.log("第一个预测函数的总损失是:" + loss1);//17
console.log("第二个预测函数的总损失是:" + loss2);//14
console.log("第三个预测函数的总损失是:" + loss3);//10 √
利用斜率让线性函数值逐步下降
损失函数看作高度,将其中的参数变量看作水平方向的位置,只要知道损失函数的斜率,就可以通过调整参数,让损失函数下降。
斜率>0 :参数越小,损失函数越小
斜率<0 :参数越大,损失函数越小
斜率的定义
- 定义一个线性函数:
function linear(t){
var s = 2*t + 1;
return s;
}
console.log("在t=5处的函数值为:" + linear(5));
- 绘制:
plot(null, null, linear,{start:-5, end: 5});
- 得出斜率:
var diff = linear(6) - linear(5);
var sielv = diff/(6-5);
console.log("函数s=2*t+1斜率是:" + xielv);
斜率性质(函数值如何下降)
让函数值逐步下降:
var t = 5;
while(linear(t) > 0){
t = t - 1;
console.log("当前变量为:" + t + " 函数值为:" + linear(t));
}
图形演示下降过程:
var t = 5;
var points = [];
//每个数组都有push方法,用来将新元素追加到数组末尾
points.push([5,linear(5)]);
while(linear(t) > 0){
t = t - 1;
points.push([t,linear(t)]);
console.log("当前变量为:" + t + " 函数值为:" + linear(t));
}
plot(points, null, linear);
换个函数:
function newLinear(t){
var s = 8-2*t;
return s;
}
var newT = 1;
var newPoints = [];
//每个数组都有push方法,用来将新元素追加到数组末尾
NewPoints.push([1,newLinear(1)]);
var newXieLv = (newLinear(6)-newLinear(5))/(6-5);
console.log("函数s=8-2t斜率为:" + newXieLv);
while(newLinear(newT) > 0){
newT = newT + 1;
newPoints.push([newT,newLinear(newT)]);
console.log("当前变量为:" + newT + " 函数值为:" + newLinear(newT));
}
plot(newPoints, null, newLinear);
利用导数让非线性函数值逐步下降
导数的定义
function nonLinear(t){
var s = t*t;
return s;
}
console.log("在t=5处的函数值为" + nonLinear(5));
绘制:
//plot(null, null, nonLinear);
plot(null, null, nonLinear, {start:-5, end:5});
计算曲线函数上各点的导数?
var t = 5;
//var der = (nonLinear(5.01)-nonLinear(5))/(5.01-5);
//console.log("在t=5处的导数值近似等于:" + der);
console.log("在t=5处的导数值等于:" + 2*t);
导数性质(函数值如何下降)
当导数值大于0时,要减少变量t来让函数值下降。
当导数值小于0时,要增加变量t来让函数值下降。
var t = 5;
while(nonLinear(t) > 0){
var der = 2*t;
if(der > 0){
t = t - 1;
}else{
t = t + 1;
}
console.log("当前变量t:" + t + "当前函数值:" + nonLinear(t));
}
图形演示下降过程:
var t = 5;
var points = [];
points.push([t,nonLinear(t)]);
while(nonLinear(t) > 0){
var der = 2*t;
if(der > 0){
t = t - 1;
}else{
t = t + 1;
}
points.push([t,nonLinear(t)]);
console.log("当前变量t:" + t + "当前函数值:" + nonLinear(t));
}
//plots(points, null, nonLinear);
plots(points, null, nonLinear,{start:-5, end:5});
换个起始点?
function train(t){
var points = [];
points.push([t,nonLinear(t)]);
var times = 0;
while(nonLinear(t) > 0 && times < 100 ){
var der = 2*t;
if(der > 0){
t = t - 1;
}else{
t = t + 1;
}
points.push([t,nonLinear(t)]);
times = times + 1;
console.log("第" + times + "次时当前变量t:" + t + "当前函数值:" + nonLinear(t));
}
//plots(points, null, nonLinear);
plots(points, null, nonLinear,{start:-5, end:5});
}
train(-3.5);
换步幅
function train(t,step){
var points = [];
points.push([t,nonLinear(t)]);
var times = 0;
while(nonLinear(t) > 0 && times < 100 ){
var der = 2*t;
if(der > 0){
t = t - step;
}else{
t = t + step;
}
points.push([t,nonLinear(t)]);
times = times + 1;
console.log("第" + times + "次时当前变量t:" + t + "当前函数值:" + nonLinear(t));
}
//plots(points, null, nonLinear);
plots(points, null, nonLinear,{start:-5, end:5});
}
train(-3.5, 0.5);
train(-3.8, 0.5);//?下节学习步长
学习步长的概念和作用
让函数值离最低点远时下降速度快,离最低点近时下降速度慢(快到最低点时减速)。
即离最低点远时,让变量变化大一些;离最低点近时,让变量变化小一些。
而离最低点远时导数的绝对值较大,离最低点近的导数的绝对值较小。
导数大于0时,变量减去导数的绝对值;
导数小于0时,变量加上导数的绝对值。
即:
无论导数正负,只要让变量减去导数值,就可以让函数值下降。
但油门不能踩到底,为了避免震荡,需要在导数前乘以一个较小的系数。
综上:
tnext = t - αds/dt
其中,α为学习步长*。
yhat = w * x + b
L = (yhat - y)2
因此,L=(w * x + b - y)2
x:面积特征,y:真实售价,只要依据导数的性质调整w和b,就可以让损失函数逐步下降了。(下节偏导数和梯度下降法)
学习步长
function train(t,lr){//lr为学习步长
var points = [];
points.push([t,nonLinear(t)]);
var times = 0;
while(nonLinear(t) > 0.0001 && times < 100 ){
var der = 2*t;
//t = t - der;//油门踩到底
t = t - lr*der;
points.push([t,nonLinear(t)]);
times = times + 1;
console.log("第" + times + "次时当前变量t:" + t + "当前函数值:" + nonLinear(t));
}
//plots(points, null, nonLinear);
plots(points, null, nonLinear,{start:-5, end:5});
}
train(5, 0.4);//t = t - 0.4*der
train(5, 0.5);//√更好
train(5, 1.1);//×不是越大越好
偏导数和梯度下降
yhat = w * x + b
L = (yhat - y)2
因此,L=(w * x + b - y)2
x:面积特征,y:真实售价,只要依据导数的性质调整w和b,就可以让损失函数逐步下降了。(偏导数和梯度下降法)
梯度方向:合力方向
通过沿着梯度的反方向来更新变量,来让函数值逐步下降的:
r = s -2t
dr/dt = -2
dr/ds = 1
tnext = t - dr/dt
snext = s - dr/ds
后面要加入学习步长