编辑
首先我们看一下,这个代码可以看到,上面
import numpy as np 这个numpy是用来做数学计算的包
import matplotlib.pyplot as plt 这个是用来绘图的.
编辑
然后接着我们看这里:
我们准备数据,先得到一个X 这个x,是用np.random.rand(100,1)
产生随机数对吧,我们看看这个rand是怎么产生随机数的
编辑
点进去这个rand方法,可以看到,里面有介绍,说populate,填充,
a uniform distribution 是一个均匀的分布
可以看到是左闭右开的.
编辑
下面还有例子是,np.random.rand(3,2) 这里,表示的是
生成一个,3行,2列的随机数,可以看到上面也有例子,可以看到,数据的大小是0到1,
左闭右开的一个数.
编辑
然后我们再看我们这里写的,
X = 2 * np.random.rand(100,1) 这里 其实就是生成一个,100行 1列的数据,因为我们知道
数据范围是0到1,所以这2 * 的数据范围就是0 到2 对吧.
编辑
然后我们再来看,这里
y= 4+3 *X + np.random.randn(100,1) 这个是什么什么意思呢?
编辑
我们看看这个randn这个函数的解释,可以看到是说是,一个standard normal distribution
是一个标准的,normal distribution 标准的正太分布对吧.
编辑
下面也有例子可以看到,是写的np.random.randn() 这个直接调用的话,返回的是:
2.19238753...这样一个数,这个数是什么呢?
实际上他就是, x从负无穷到正无穷 ,然后 u = 0 ,方差是1的这样的一个,正态分布中的一个值,
这里就是随机取了一个2.19238753...返回来.
编辑
然后我们再看这里,有个例子是:
N 这里如果指定. (3,6.25) 意思就是,
u = 3 ,方差等于6.25 这样一个正太分布中的取值,但要注意,这样就不是标准正态分布了,
返回的其实就是,这个正态分布的,x从负无穷到正无穷中的一个取值.
编辑
然后我们来看一下,这里的例子,这个
2.5 * np.random.randn(2,4) +3
这里就是一个2行4列的, 一个标准正太分布,也就是u=0 方差为1的这个正太分布的值.可以看到.
获取值,就是一个2行4列的矩阵.
编辑
然后我们再来看,下面这个代码:
y = 4 + 3 * X +np.random.randn(100,1)
这个是什么?
其实就是y = yhat + e ebuselo对吧,其实就是真实值 = 预测值 + 误差对吧,
那么这里的,np.random.randn(100,1),这个是个标准正态分布中的一组值,我们用它来模拟误差,我们之前也推导的时候,说过,我们就是假设,误差是随机的,并且,符合正太分布的,所以,这里我们用
随机的正态分布的值,来代表这个ebuselo随机误差,然后我们再看:
y = 4 + 3 * X +np.random.randn(100,1)
这里预测值是什么? 也就是4+ 3* X 对吧,那么这里的4和3是什么呢?
也就是我们说的模型对吧.
我们之前说:y = ax +b 那么,可以写成 y = ax1 + b x0 ,这里x0 =1 x1就是我们的数据,所以.
4 + 3 * X = yhat 也就是,x0 * 4 + 3 * X1 ,这里的X1就是上面我们声明的那个X对吧.
因而这里w0 = 4 w1= 3,也就是我们说的模型.
所以这里我们,其实就是要,利用上面的y = 4 + 3 * X +np.random.randn(100,1) 公式,
我们要通过,不停的输入我们的x,y的值,然后得到一组组的,模型,也就是w0,w1,让我们通过
这种方式得到的模型,尽可能w0 = 4 w1=3 就可以了,但是我们为什么说尽可能?
因为还有ebuselo误差对吧,要想, y = 4 + 3 * X +np.random.randn(100,1) 成立,
那么除非,np.random.randn(100,1)取的的随机数全部都是0,这个概率太小了.
编辑
所以我们计算的时候是不可能做到,做到让w0 =4 w1=3的,除非我们说上面的情况,我们随机出来的
所有误差都是0,但是那种可能性太低了.
但是我们可以求最优解,让w0尽可能等于4,让w1尽可能等于3.
编辑
然后我们可以看到,上面其实我们就是得到了,两组数据而已,一组是x
一组是y ,其中y是真实值,是我们用上面的公式,也就是y = yhat + ebuselo误差得到的
,我们有了x,y的一组数据,那么我们把数据带入到,
seta = (XT*X)^-1 *XT*y 这样的损失函数,我们说,通过线性代数的方法,我们就可以一步把解析解,
解出来.
编辑
然后我们再来继续看,这里x_b = np.c_[np.ones((100,1)),X]
这个是什么意思呢?
注意首先这里的np.c c是combine是连接的意思,那么,这里,他其实就是要把x0,和x1,连接起来,
是什么意思呢?
这里的x0,我们说恒为1,也就是100行,1列,全部是1,所以,这里 np.ones(100,1) ,就是获取100行
1列的1,然后X呢? 是上面我们得到的,一个符合100行,1列的一个随机数,所以,现在我买通过
np.c得到的就是一个矩阵,一个100行,两列,其中第一列全部是1的这样一个矩阵.
编辑
然后我们可以看到上面我们已经把x_b,这个变量打印出来了,所以我们执行一下看看,就可以看到
得到了一个矩阵,100行,两列,第一列全部是1的矩阵.
编辑
然后我们再来看,下面的一行代码:
theta_best = np.linalg.inv...
这里的np.linalg是什么呢,我们点进去看看.
编辑
可以看到这个np下面的,linalg,其实是 linear algebra对吧,也就是线性代数工具对吧.
编辑
然后我们回过来再看看,下一步.
这里
theta_best = np.linalg.inv(x_b.T.dot(x_b)).dot(x_b.T).dot(y)
这里,我们首先看,这里np.linalg.inv,这里我们说linalg是线性代数工具,然后,这个inv是什么意思呢?
其实就是inverse,取逆的意思,我们再看看,我们损失函数的,线性代数的表达那个公式:
theta = (XT.X)^-1 .XT.y 这个公式对吧.所以对应到这里就是:
注意这里的 (XT.X)^-1,也就是:
x_b.T.dot(x_b) 其实就相当于XT.X,这里的 x_b.T,其实就是,x_b的转置,然后.dot,指的是乘的意思,
是线性代数里的乘,可以看到后续就很清楚了,其实就是
theta = (XT.X)^-1 .XT.y 把这个函数,用,np工具中的,线性代数表示了一下,然后,我们再去
执行,可以看到这个损失函数的,最优解就被计算出来了.
编辑
所以可以看到这里得到的结果,其实,3.839...就是我们说的w0也就是4,那么3.2267...就是我们上面说的w1,也就是3,也就是说,但我们的,这两个模型是,w0 = 3.839... w1 = 3.2267...的时候,我们的
数据带入进去以后,预测到的结果可以使得误差最小.
编辑
那么这里我们可以看到计算的很快对吧,但是实际上,是因为我们的维度只有2个维度,x0,x1,而且
我们的数据比较小,但是实际上的应用中,往往可能考虑上亿个参数,也就是,x0到x1亿,
并且矩阵也很大,这时候如果再用一步求解的方式,用这个线性代数的方式就很费劲了.
算不出来了. ,还有就是我们的数据比较少,只有,100组数据对吧
如果数据规模特别大,那么也很难直接通过解方程的方式得到解析解.
编辑
而我们说在人工智能的时代,做预测实际上是数据为王的,也就说,只有数据量大结果才准参数越大,
结果才准,所以说,这个也是有冲突的地方. 一方面数据量大直接解方程出不来结果,一方面又必须数据量大,才有意义,所以有了下面的方法.
编辑
在说方法之前,我们先来看一下,上面我们已经通过解方程的方式,得到了,两个权重,或者说叫做
模型W0,W1,那么有了这个W0,W1,我们就可以去验证一下我们做出的预测对不对,
y = w0 * x0 + w1 *x1 这里我们有了,w0,w1,所以我们这里再准备x0,x1就可以了,我们说
x0是1,所以这里我们先准备x1可以看到上面,x_new = np.array([0],[2]),我们这里生成了,0,2这样一个
两行一列的数据对吧,
然后我们再:
x_new_b = np.c_[(np.ones((2,1))),x_new] 其实就是把 1,1 和0,2 连接起来对吧
生成两组数据,也就是:
1 0
1 2
这样一个矩阵.
编辑
这里我们有了准备的x数据了,然后我们又知道,x.seta =y 为什么会有这个公式了?
因为我们知道损失函数是:seta = (XT.X)^-1 . XT.Y 也就是
seta = 1/XT.X .XT.Y 所以简化后就是 seta = Y/X
也就是说X.seta =Y
而seta这里其实就是指的我们求出来的,那组模型对吧.
编辑
可以看到这里的X.seta =y hat 其实就是得出的预测值,
因为这里的X,我们说是一个m行n列的矩阵,然后乘以seta,这里的seta,其实就是n列的模型对吧,
这里是w0,w1,所以m行 n列的x数据,再乘以n列的模型数据,就得到了预测值,其实也就是
y = w0x0 + w1x1 这样对吧.因为这里的seta,我们知道,其实就是我们通过解方程得到的,最优解,也就是模型对吧.
然后我们去执行去看看结果:
编辑
可以看到这里执行以后得到的预测值,这里是4.00153876对吧,yhat1,
我们看看,因为我们这里x0是1,所以y=4+3*x +np.random.randn(100,1)
y = 4 x0 + 3* x1 +np.random.randn(100,1)
这里我们知道x0 =1 x1,我们第一组数据取的是0,第二组是2对吧
所以带入就是y =4+ 0 +np.random.randn(100,1)
所以可以看到,得到并不是4,真实值是4对吧,因为我们说,这里是有误差的,是因为我们得到的w0 和w1模型有误差对吧
编辑
可以看到得到w0是4.0015...w1是2.978...并不是4,3对吧,所以说有误差的.
编辑
然后下一步,我们用图形来表示一下,这个结果,可以看到
这里plt是个绘图的库,plt.plot是(x_new,y_predict,'r-')这个意思是说,
在图形上用r就是red红色,并且用-直线来画图,来表示第二次我们造的测试数据,
我们通过第一组测试数据得到的w0,w1,然后把第二组数据带入,就得到了用我们的
模型得到的预测值.
然后plt.plot(x,y,'b.'),b就是blue就是用蓝色的.线 点线来表示,第一次我们造的测试数据
也就是第一组数据,我们通过这一组数据得到了w0 和w1,这个模型对吧
然后plt.axis([0,2,0,15]),就是说x轴是0到2,y轴是0到15
然后我们执行去看看.
编辑
可以看到上面蓝色的点就是,我们第一次的测试数据对吧,而第二次我们是根据得到的
w0,w1这个模型,得到的一个预测值,也就是红色的那根线对吧.所以呢,可以看到
这个红色的预测值,实际上,也就是模型,可以保证,图上的所有点,到红线的距离,加起来平方加和,然后
得到的值最小对吧,也就是误差最小.
编辑
然后我们继续看,如果我们再去执行一遍的话会看到得到的结果跟原来不一样了
这个是为什么呢
编辑
很简单因为我们的数据是随机出来的对吧,可以看到上面x,y值,是随机的,所以每次都不一样,所以
每次出来的图形也是有所不一样.
但是预测值可以看到都是差不多的对吧.
编辑
然后我们再来看下一个比较重要的概念,因为我们说,
利用一次性解出答案的方式,不是不行,但是往往因为我们的数据参数太多,导致,解公式太复杂
而不能得到结果.所以就需要用到梯度下降法.
首先可以看到我们的公式中:
seta = (XT.X)^-1 . XT.Y 这个是损失函数,那么如果我们这里只看:
XT.X 这里我们分析一下,实际上,这个是两个矩阵相乘,也就两个对称矩阵,因为XT是X的转置.
那么这个时候复杂度就是ON的3次方什么意思? 也就是如果X的特征数量翻倍,那么计算时间大致上要是2的三次方,也就是说是8倍,是原来数据的8倍.
也就是说:
编辑
比如你的参数是2个的话那么,需要2s的计算时间,如果是4个的话,需要的时间就是16秒
是比原来2的时候多了,2的三次方也就是8倍的慢 2*8 = 16, 如果是8个的话,需要的时间就是32秒,比原来2的时候多了,2的三次方8倍的慢, 2个八倍的慢 ,也就是 2* 16 = 32s
当然如果这里说,8000个参数呢?那需要花费的时间就不可想象了.
编辑
所以这里我们可以用梯度下降法来解决这个问题,怎么弄了?
可以看到首先,我们知道y = x^2 是一个凸函数,对吧开口向上的,它有极小值,这个要知道,
然后我们再来看我们的损失函数:可以看到J(seta) = E(i=1到m)(yhat-yi)^2 这个损失函数
跟上面我们计算seta一样,这里的seta也就是我们说的,去根据公式计算w0,w1...模型对吧
也就是说,我们的seta,模型定了以后,就会得到一个j(seta) 这个函数的值,然后seta也就是
这个另一组模型定了的话,我们又可以得到一个新的j(seta)值,这样的话,我们就可以根据
模型中w0,w1..也就是seta,得到很多的j(seta)值,最终,我们可以画出来上面的那样的图
可以看到,下面的最小值,的时候,损失函数的值最小,这个时候对应的w0,w1...对应的seta
模型也就是我们要找的模型了.
这样的方法是一步步来找到最优解的,不用一次性利用线性方程求解的方式来求解析解,
这样就可以对一些,要花很长时间来求得解析解的方程,来通过这种方式,逐步得到最优解了.
编辑
这是因为首先我们知道,损失函数J(seta) = E i=1到m (y hat -yi)^2 我们知道这个函数是一个凸函数,
所以,当我们有一个seta的值的时候,就会通过这个函数得到一个J(seta),这就相当于y = x+b,一样的,
有了一个x就得到一个y,只不过这里是,有了一个seta 就有了一个J(seta),有了这个关系就可以画出,
这个函数曲线,可以看到,函数曲线就是上面这个样子的,至于为什么说这个函数是个凸函数呢?
因为我们都知道y=x^2 是 凸函数,右上角那样画出来对吧,这个J(seta) = E i=1到m (y hat -yi)^2,
所以也是凸函数了.
编辑
然后我们来看这里,我们说损失函数是一个,凸函数,可以看到凸函数,只有波谷,如果有两个波谷可以看到,跟下面那个图
一样就不是凸函数了,凸函数只有一个最小值. 非凸函数可能有多个,比如,下面那个图,右边那个是全局最小值,然后
左边那个是局部最小值.
编辑
编辑
这里,首先我们要知道,这个图形对应的函数是
损失函数也就是J(seta) = E i=1到m (yi - x.seta)^2 对吧其实就是.
E i=1到m (yi-yhat)^2 这里的yhat 其实就是x.seta 对吧,因为我们知道,y = ax+b
其实可以写成y = a.x1 + b .x0 这里我们把x0设置为一个固定的值,所以这里的x0设置为0,
所以就可以认为是y = a.x1对吧,所以这里就可以写成 x.seta = yhat 对吧
然后我们再看,梯度下降法,就是刚开始我先给seta 初始化一个任意值,这个值是 (-无穷 到 +无穷),比如
可以看到我初始化了一个,上图左侧的random initial value 这个值,然后,带入我们的损失函数,就可以得到
J(seta) 也就是,对应的cost函数的值,也就是得到了y的值,也可以认为,然后我们,在这个点,画出一个
切线,这个切线这里,有一个斜率对吧,这个斜率,就是对这个切线求导得到的,可以看到在最小值的左侧的时候,
这个斜率,也就是这个切线的倒数,我们写成缩写g, 求g,也就是gradient,就是求导的意思,这个导数,在最小值
左侧是时候是小于0的对吧.
然后,我们有一个公式:seta t+1 = seta t - g.阿尔法 这里我们知道,我们找的这个seta值,比如是seta t,那么
我们这里减去此时的,把seta t带入损失函数得到的,j(seta)对应的斜率, 可以看到,其实就是减去一个小于零的数
对吧,减去小于零的数,那么,seta t+1 就会变大对吧,所以,这样我们就得到了,seta t+1 ,也就是...我们取的seta值
就慢慢往右靠了,可以看到,往右靠,其实就是接近最小值了对吧.
然后seta t+1带入到损失函数,可以看到又得到一个j(seta) t+1 对吧,就相当于,y值向下了,就跟下山一样,
这个叫做梯度下降法.
编辑
然后我们第一步用初始化的seta值,得到了对应j(seta)
编辑
然后我们再去,根据seta t+1 = seta t-g 阿尔法
根据这个,来去计算出seta t+1的值,然后再带入,损失函数,然后继续计算j(seta) t+1 ,这个时候,
seta的值就会一点点,往右移动,越来越接近 最小值时候的seta值.
编辑
编辑
然后我们得到seta t+2 以后,然后再带入到,seta t+2 = seta t+1 - g阿尔法
就这样一步步,梯度下降,慢慢像最小值靠拢.
编辑
然后这里要注意这里,seta t+3 = seta t+2 -g阿尔法
这里的这个阿尔法...这个被称为学习率
什么意思呢? 这个决定了,seta t+1 的跨度,如果 这个学习率,值特别大的话,可能,得到seta t+1 一步就跨到,最小值右边去了
编辑
可以看到如果学习率,很大,得到的seta t+1 的值,就会很大,那么很可能会一步就跨到了
最小值seta的 右边去了,然后 ,这个时候右边的这个斜率可以看到,就会是大于0的了,那么
把这个斜率大于0的斜率,带入到 seta t+1 = seta t -gh 中,带入到里面以后, 这个时候,因为g斜率是大于0的,所以
得到的这个seta t+1 ,就变小了这个时候,所以这个时候,seta t+1的值,就会变小了,也就是
会往左移了,可以看到,不管怎么做,其实...这个方法,都会,让seta 自动的,往,最小值靠拢对吧...
编辑
但是这里就要知道了,
如果seta t+1 = seta t - g阿尔法 如果,这个阿尔法学习率,太大的话,就会引起, seta 一会走到了,最小seta值的,左边,一会
走到了最小seta值的右边,就会引起震荡.
如果阿尔法这个,学习率的值,太小的话,那么就会导致,走得慢对吧,走得慢,那么迭代次数就多
迭代次数多,那么运行的就慢,学习的就慢.
编辑
这里还要知道一点,就是,这个 seta t+1 = seta t - g阿尔法 这个阿尔法的值,被称为 学习率我们知道了,其实每个公司,
这个学习率的设定,都可以说是公司机密了,怎么设置,能让这个学习,次数少,迭代次数少,更快获得结果,消耗的资源
也更少, 这个学习率很重要
这个学习率也叫做 haperparameter 超参数也叫做,然后还有一个的,由于,切线的斜率,往往不可能最后,会等于0,
那么这个时候,我们就会指定一个值,这个值叫做threadhold 阈值, 这个g=0,是不可能的在实际中,因此
比如我们指定,当g < 0.15的时候,我们就认为,可以了,学习到位了...可以用来预测了...就是 g< threadhold
的时候就可以了..当然这个0.15 是我们指定的.
编辑
所以可以看到,其实梯度下降法,就是,4步
1.初始化一个seta值
2.求当前是seta值对应的y值 也就是j(seta) 的值,然后求出,这个点,对应地方的斜率 g
3.然后利用seta t+1 =seta t -g阿尔法u 来计算seta t+1 然后再带入2中计算,循环往复
4.直到收敛 斜率的值 小于等于阈值的时候 就完成了.
这里这个seta t+1 =seta t -g阿尔法u 这里的阿尔法u这里,成为haperparameter 超参数,这个
超参数决定了,这个解析解求算的速度对吧,如果太大我们说会震荡,太小,可能迭代次数就越多,所以这个超参数的选择
很重要,这也是各个公司的秘密所在了.
然后这里的斜率,也就是梯度,如果随着不停的计算,快要等于0了,这个时候就说明,这个就已经符合我们的
要求了,但是这个梯度一般很难达到0,那么这个时候就需要有个阈值,这个阈值也是一个超参数,叫做threadhold
,比如我们规定这个阈值小于0.15就够用了,能预测的足够准了比如说.
编辑
然后这里其实梯度下降法就是一个试的过程,通过不断的尝试,来得到一个相对精确的可用的模型,其实
现实生活中我们也往往都是通过不停的尝试,最后得到一个模型.或者规律
编辑
然后我们说梯度下降法实际上就是利用了导函数对吧,利用了斜率
利用了损失函数的 的斜率
编辑
可以看到损失函数上面,这个函数我们经过一次变化
编辑
对他进行求导就可以得到:
j(theta) = (yihat -yi) ^2 对吧 我们就求这个导函数,斜率最下的时候就可以了,也就是,
j(theta) 几乎等于0的时候,对应的theta值其实就是,对应的w,权重参数对吧.
编辑
这里我们再说一个框架,这个scikit-learn框架
编辑
可以看到这里scikit-learn 这里包含了,求解析解的函数了,
求导函数的,解析解 已经包含到这个包里了
编辑
可以看到也是开源的
编辑
这里我们可以不用自己,调用np的线性代数等方法,自己去利用,损失函数去计算了
我们利用scikit-learn会更简单,因为它里面提供了,直接计算解析解的方法
编辑
我们可以看一下,这里我们要用到np 导入这个包,还有导入sklearn.linear_model import LinearRegression
LinearRegression 这个就是,线性回归,是sklearn给封装好的,我们直接用就可以了,可以看到这一下代码就简单多了
这里还是准备 x, y 数据,然后,带入函数是损失函数的导函数,一步计算最小值
可以看到这里,先获取了LinearRegression线性回归这个类的,实例,然后直接调用.fit(x,y) 就可以了
这个.fit 就是,直接一步求出解析解的方法,这个.fit 类似于spark中的,train,训练的意思对吧,然后,这个训练以后,就可以
直接打印出结果了,上面这个,就是..
通过lin_reg.intercept_,lin_reg.oef_
这个,其实就是lin_reg通过这个实例,打印出结果对吧,这个结果 可以看到lin_reg.intercept_,这个是截距,
编辑
截距其实,就是实际值,到预测值的距离,也就是说,预测值+截距 =实际值
也就相当于w0 ,然后 ,lin_reg.oef_ 就相当于 w1,w2,w3...这样,这要看我们的,函数是几元的,
对吧,几元就会输出几个.
编辑
可以看到这里我们直接调用lin_reg.fit(x,y) 可以看到就一步给算出解析解了
可以看到是4.07.. 2.96...很接近 4,3了对吧
这里为什么不是等于4,3 因为我们的y x 后面,添加了随机数了对吧.
编辑
然后我们再看看,如果我们通过求解析解的方式,得到了W0,W1了,然后,我们再进行,有新的数据预测是时候,
我们就可以直接lin_reg.predict(x_new) ,就可以用来做预测了对吧
就相当于带入新的数据,来预测y值了.
编辑
实际上这个sklearn框架在你安装Anaconda的时候就自动提供了对吧.这个anaconda是蟒蛇的意思.
编辑
总结一下学的内容.