1. 线性回归
前面介绍了很多分类算法,分类的目标变量是标称型数据,回归是对连续型的数据做出预测。
标称型数据(Nominal Data)是统计学和数据分析中的一种数据类型,它用于分类或标记不同的类别或组别,数据点之间并没有数值意义上的距离或顺序。例如,颜色(红、蓝、绿)、性别(男、女)或产品类别(A、B、C)。
标称数据的特点:
-
无序性:标称数据的各个类别之间没有固有的顺序关系。例如,“性别”可以分为“男”和“女”,但“男”和“女”之间不存在大小、高低等顺序关系。
-
非数值性:标称数据不能进行数学运算,因为它们没有数值含义。你不能对“颜色”或“品牌”这样的标称数据进行加减乘除。
-
多样性:标称数据可以有很多不同的类别,具体取决于研究的主题或数据收集的目的。
-
比如西瓜的颜色,纹理,敲击声响这些数据就属于标称型数据,适用于西瓜分类
连续型数据(Continuous Data)表示在某个范围内可以取任意数值的测量,这些数据点之间有明确的数值关系和距离。例如,温度、高度、重量等
连续型数据的特点包括:
-
可测量性:连续型数据通常来源于物理测量,如长度、重量、温度、时间等,这些量是可以精确测量的。
-
无限可分性:连续型数据的取值范围理论上是无限可分的,可以无限精确地细分。例如,你可以测量一个物体的长度为2.5米,也可以更精确地测量为2.53米,甚至2.5376米,等等。
-
数值运算:连续型数据可以进行数学运算,如加、减、乘、除以及求平均值、中位数、标准差等统计量。
在数据分析中,连续型数据的处理和分析方式非常丰富,常见的有:
-
描述性统计:计算均值、中位数、众数、标准差、四分位数等,以了解数据的中心趋势和分布情况。
-
概率分布:通过拟合概率分布模型,如正态分布、指数分布、伽玛分布等,来理解数据的随机特性。
-
图形表示:使用直方图、密度图、箱线图、散点图等来可视化数据的分布和潜在的模式。
-
回归分析:建立连续型变量之间的数学关系,预测一个或多个自变量如何影响因变量。
-
比如西瓜的甜度,大小,价格这些数据就属于连续型数据,可以用于做回归。
1.1 什么是回归
回归的目的是预测数值型的目标值y。最直接的办法是依据输入x写出一个目标值y的计算公式。假如你想预测小姐姐男友汽车的功率,可能会这么计算:
HorsePower = 0.0015 * annualSalary - 0.99 * hoursListeningToPublicRadio,写成中文就是:小姐姐男友汽车的功率 = 0.0015 * 小姐姐男友年薪 - 0.99 * 收听公共广播的时间
这就是所谓的回归方程(regression equation),其中的0.0015和-0.99称为回归系数(regression weights),**求这些回归系数的过程就是回归**。一旦有了这些回归系数,再给定输入,做预测就非常容易了。具体的做法是用回归系数乘以输入值,再将结果全部加在一起,就得到了预测值。
1.2 线性回归
说到回归,一般都是指线性回归(linear regression)。线性回归意味着可以将输入项分别乘以一些常量,再将结果加起来得到输出。线性回归是机器学习中一种有监督学习的算法,回归问题主要关注的是因变量(需要预测的值)和一个或多个数值型的自变量(预测变量)之间的关系。
需要预测的值:即目标变量target,y影响目标变量的因素:X_1,X_2...X_n,可以是连续值也可以是离散值,因变量和自变量之间的关系:即模型,model,就是我们要求解的,比如1个包子是2元 3个包子是6元 预测5个包子多少钱。
列出方程: y=wx+b,带入:2=w*1+b,6=w*3+b,轻易求得 w=2 b=0,模型(x与y的关系): y=2*x+0,预测 x=5 时 target_y=2*5+0=10元
上面的方程式我们人类很多年以前就知道了,但是不叫人工智能算法,因为数学公式是理想状态,是100%对的,而人工智能是一种基于实际数据求解最优最接近实际的方程式,这个方程式带入实际数据计算后的结果是有误差的。
人工智能中的线性回归:数据集中,往往找不到一个完美的方程式来100%满足所有的y目标,我们就需要找出一个最接近真理的方程式。
比如:有这样一种植物,在不同的温度下生长的高度是不同的,对不同温度环境下,几颗植物的环境温度(横坐标),植物生长高度(纵坐标)的关系进行了采集,并且将它们绘制在一个二维坐标中,其分布如下所示:
坐标分别为[4.2, 3.8],[4.2, 2.7],[2.7, 2.4],[0.8, 1.0],[3.7, 2.8],[1.7, 0.9],[3.2, 2.9]。
我们发现这些点好像分布在一条直线的附近,那么我们能不能找到这样一条直线,去“拟合”这些点,这样的话我们就可以通过获取环境的温度大概判断植物在某个温度下的生长高度了。
于是我们的最终目的就是通过这些散点来拟合一条直线,使该直线能尽可能准确的描述环境温度与植物高度的关系。
1.3 损失函数
数据: [[4.2, 3.8],[4.2, 2.7],[2.7, 2.4],[0.8, 1.0],[3.7, 2.8],[1.7, 0.9],[3.2, 2.9]],我们假设 这个最优的方程是:
这样的直线随着w和b的取值不同 可以画出无数条,在这无数条中,哪一条是比较好的呢?
我们有很多方式认为某条直线是最优的,其中一种方式:均方差就是每个点到线的竖直方向的距离平方 求和 在平均 最小时 这条直接就是最优直线
假设: y=wx+b,把x_1,x_2,x_3...带入进去 然后得出:y_1^,=wx_1+b;y_2^,=wx_2+b;y_3^,=wx_3+b ...
然后计算{y_1-y_1^,} 表示第一个点的真实值和计算值的差值 ,然后把第二个点,第三个点...最后一个点的差值全部算出来,有的点在上面有点在下面,如果直接相加有负数和正数会抵消,体现不出来总误差,平方后就不会有这个问题了。
总误差(也就是传说中的损失):,平均误差(总误差会受到样本点的个数的影响,样本点越多,该值就越大,所以我们可以对其平均化,求得平均值,这样就能解决样本点个数不同带来的影响)。
这样就得到了传说中的损失函数:,怎么样让这个损失函数的值最小呢?我们先假设b=0 (等后面多元方程求解这个b就解决了)
然后就简单了 算w在什么情况下损失函数的值最小(初中的抛物线求顶点的横坐标,高中求导数为0时)
求得w=0.795时损失函数取得最小值,那我们最终那个真理函数(最优解)就得到了,,在这个求解的过程中,我们是假设了b=0的 学了多元方程求解后 这个b也是可以求解出来的,因为一元方程是一种特殊的多元方程。
总结:
1. 实际数据中 x和y组成的点 不一定是全部落在一条直线上;
2. 我们假设有这么一条直线 y=wx+b 是最符合描述这些点的;
3. 最符合的条件就是这个方程带入所有x计算出的所有y与真实的y值做 均方差计算;
4. 找到均方差最小的那个w;
5. 这样就求出了最优解的函数(前提条件是假设b=0)。
1.4 多参数回归
上面案例中,实际情况下,影响这种植物高度的不仅仅有温度,还有海拔,湿度,光照等等因素:实际情况下,往往影响结果y的因素不止1个,这时x就从一个变成了n个,x_1,x_2,x_3...x_n 上面的思路是对的,但是求解的公式就不再适用了。
案例: 假设一个人健康程度怎么样,由很多因素组成
被爱 | 学习指数 | 抗压指数 | 运动指数 | 饮食情况 | 金钱 | 心态 | 压力 | 健康程度 |
---|---|---|---|---|---|---|---|---|
0 | 14 | 8 | 0 | 5 | -2 | 9 | -3 | 339 |
-4 | 10 | 6 | 4 | -14 | -2 | -14 | 8 | -114 |
-1 | -6 | 5 | -12 | 3 | -3 | 2 | -2 | 30 |
5 | -2 | 3 | 10 | 5 | 11 | 4 | -8 | 126 |
-15 | -15 | -8 | -15 | 7 | -4 | -12 | 2 | -395 |
11 | -10 | -2 | 4 | 3 | -9 | -6 | 7 | -87 |
-14 | 0 | 4 | -3 | 5 | 10 | 13 | 7 | 422 |
-3 | -7 | -2 | -8 | 0 | -6 | -5 | -9 | -309 |
11 | 14 | 8 | 10 | 5 | 10 | 8 | 1 | ? |
求如果karen的各项指标是:被爱:11 学习指数:14 抗压指数:8 运动指数:10 饮食水平:5 金钱:10 心态:8 压力:1,那么karen的健康程度是多少?
直接能想到的就是八元一次方程求解:
解出权重然后带入即可求出karen的健康程度,权重即重要程度,某一项的权重越大说明它影响最终健康的程度越大,但是这有一个前提:这个八元一次方程组得有解才行。因此我们还是按照损失最小的思路来求权重
多元线性回归:;b是截距,我们也可以使用
来表示只要是个常量就行:
;
那么损失函数就是:
如何求得对应的使得loss最小呢? 数学家高斯给出了答案。
1.5 最小二乘法MSE
x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x0 | y |
---|---|---|---|---|---|---|---|---|---|
0 | 14 | 8 | 0 | 5 | -2 | 9 | -3 | 1 | 339 |
-4 | 10 | 6 | 4 | -14 | -2 | -14 | 8 | 1 | -114 |
-1 | -6 | 5 | -12 | 3 | -3 | 2 | -2 | 1 | 30 |
5 | -2 | 3 | 10 | 5 | 11 | 4 | -8 | 1 | 126 |
-15 | -15 | -8 | -15 | 7 | -4 | -12 | 2 | 1 | -395 |
11 | -10 | -2 | 4 | 3 | -9 | -6 | 7 | 1 | -87 |
-14 | 0 | 4 | -3 | 5 | 10 | 13 | 7 | 1 | 422 |
-3 | -7 | -2 | -8 | 0 | -6 | -5 | -9 | 1 | -309 |
1.5.1 矩阵相关公式
,
,
1.5.2 最小二乘法
这就是传说中的最小二乘法公式是欧几里得范数的平方,也就是每个元素的平方相加。
虽然这个案例中n=8,但是常常令n=2,因为是一个常数 求最小值时n随便取哪个正数都不会影响W结果,但是求导过程可以约掉前面的系数,会加速后面的计算。
高斯把公式给了,但是何时loss最小呢?
1. 二次方程导数为0时最小:
2. 先展开矩阵乘法:
3. 进行求导(注意X,y都是已知的,W是未知的):
4. 令导数:
5. 矩阵没有除法,使用逆矩阵转化:
第二种方式链式求导(推荐,因为后期深度学习全是这种)
内部函数是:;外部函数是 :
;其中:
。
外部函数的导数:;
内部函数的导数:。
应用链式法则,我们得到最终的梯度:
有了W,回到最初的问题,求如果karen的各项指标是:
被爱:11 学习指数:14 抗压指数:8 运动指数:10 饮食水平:5 金钱:10 权利:8 压力:1,那么karen的健康程度是多少?
分别用W各项乘以新的X 就可以得到y健康程度。
1.5.3 API 介绍
sklearn.linear_model.LinearRegression()
功能: 普通最小二乘法线性回归, 权重和偏置是直接算出来的,对于数量大的不适用,因为计算量太大,计算量太大的适合使用递度下降法参数:
fit_intercept bool, default=True是否计算此模型的截距(偏置)。如果设置为False,则在计算中将不使用截距(即,数据应中心化)。
属性:
coef_ 回归后的权重系数
intercept_ 偏置print("权重系数为:\n", estimator.coef_) #权重系数与特征数一定是同样的个数。
print("偏置为:\n", estimator.intercept_)
示例:
from sklearn.linear_model import LinearRegression
import numpy as np
data=np.array([[0,14,8,0,5,-2,9,-3,399],[-4,10,6,4,-14,-2,-14,8,-144],[-1,-6,5,-12,3,-3,2,-2,30],[5,-2,3,10,5,11,4,-8,126],[-15,-15,-8,-15,7,-4,-12,2,-395],[11,-10,-2,4,3,-9,-6,7,-87],[-14,0,4,-3,5,10,13,7,422],[-3,-7,-2,-8,0,-6,-5,-9,-309]])
x=data[:,0:8]
y=data[:,8:]
estimator=LinearRegression(fit_intercept=False)
estimator.fit(x,y)
print("权重系数为:\n", estimator.coef_) #权重系数与特征数一定是同样的个数。
print("偏置为:\n", estimator.intercept_)
x_new=[[11,14,8,10,5,10,8,1]]
y_predict=estimator.predict(x)
print("预测结果:\n",y_predict)
print(-3*0.4243965-7*7.32281732-2*15.05217218-8*3.5996297+0*12.05805264-6*1.76972959-5*17.0276393-9*11.31212591)
1.6 梯度下降
1.6.1 梯度下降概念
正规方程求解的缺:之前利用正规方程求解的W是最优解的原因是MSE这个损失函数是凸函数。但是,机器学习的损失函数并非都是凸函数,设置导数为0会得到很多个极值,不能确定唯一解,MSE还有一个问题,当数据量和特征较多时,矩阵计算量太大。
1. 假设损失函数是这样的,利用正规方程求解导数为0会得到很多个极值,不能确定唯一解
2. 使用正规方程求解要求X的特征维度
不能太多,逆矩阵运算时间复杂度为
, 也就是说如果特征x的数量翻倍,计算时间就是原来的
倍,8倍太恐怖了,假设2个特征1秒,4个特征8秒,8个特征64秒,16个特征512秒,而往往现实生活中的特征非常多,尤其是大模型,运行时间太长了,所以 正规方程求出最优解并不是机器学习和深度学习常用的手段,梯度下降算法更常用。
梯度下降:
假设你在一个陌生星球的山地上,你想找到一个谷底,那么肯定是想沿着向下的坡行走,如果想尽快的走到谷底,那么肯定是要沿着最陡峭的坡下山。每走一步,都找到这里位置最陡峭的下坡走下一步,这就是梯度下降。
在这个比喻中,梯度就像是山上的坡度,告诉我们在当前位置上地势变化最快的方向。为了尽快走向谷底,我们需要沿着最陡峭的坡向下行走,而梯度下降算法正是这样的方法。
每走一步,我们都找到当前位置最陡峭的下坡方向,然后朝着该方向迈进一小步。这样,我们就在梯度的指引下逐步向着谷底走去,直到到达谷底(局部或全局最优点)。
在机器学习中,梯度表示损失函数对于模型参数的偏导数。具体来说,对于每个可训练参数,梯度告诉我们在当前参数值下,沿着每个参数方向变化时,损失函数的变化率。通过计算损失函数对参数的梯度,梯度下降算法能够根据梯度的信息来调整参数,朝着减少损失的方向更新模型,从而逐步优化模型,使得模型性能更好。
在这个一元二次方程中,损失函数对于参数 w 的梯度就是关于 w 点的切线斜率。梯度下降算法会根据该斜率的信息来调整参数 w,使得损失函数逐步减小,从而找到使得损失最小化的参数值,优化模型的性能。
梯度下降法(Gradient Descent)是一个算法,但不是像多元线性回归那样是一个具体做回归任务的算法,而是一个非常通用的优化算法来帮助一些机器学习算法求解出最优解,所谓的通用就是很多机器学习算法都是用梯度下降,甚至深度学习也是用它来求解最优解。 所有优化算法的目的都是期望以最快的速度把模型参数W求解出来,梯度下降法就是一种经典常用的优化算法。
1.6.2 梯度下降步骤
梯度下降流程就是“猜"正确答案的过程:
1. Random随机数生成初始W,随机生成一组成正态分布的数值w_0,w_1,w_2....w_n,这个随机是成正太态布的(高斯说的);
2. 求梯度g,梯度代表曲线某点上的切线的斜率,沿着切线往下就相当于沿着坡度最陡峭的方向下降;
3. if g < 0,w变大,if g >0,w变小(目标左边是斜率为负右边为正 );
4. 判断是否收敛,如果收敛跳出迭代,如果没有达到收敛,回第2步再次执行2~4步收敛的判断标准是:随着迭代进行查看损失函数Loss的值,变化非常微小甚至不再改变,即认为达到收敛;
5. 上面第4步也可以固定迭代次数。
1.6.3 梯度下降公式
随机给一个w初始值,然后就不停的修改它,直到达到抛物线最下面附近,比如:w=0.2
w=w-0.01*w为0.2时的梯度(导数) 假设算出来是 0.24;
w=w-0.01*w为0.24时的梯度(导数) 假设算出来是 0.33;
w=w-0.01*w为0.33时的梯度(导数) 假设算出来是 0.51;
w=w-0.01*w为0.51时的梯度(导数) 假设算出来是 0.56;
w=w-0.01*w为0.56时的梯度(导数) 假设算出来是 0.58;
w=w-0.01*w为0.58时的梯度(导数) 假设算出来是 0.62。
就这样一直更新下去,会在真实值附近,我们可以控制更新的次数。
关于随机的w在左边和右边问题:因为导数有正负,如果在左边导数是负数减去负数就是加往右移动,如果在右边导数是正数减去正数就是减往左移动。
1.6.4 学习率
根据我们上面讲的梯度下降公式,我们知道α是学习率,设置大的学习率α;每次调整的幅度就大,设置小的学习率α;每次调整的幅度就小,然而如果步子迈的太大也会有问题! 学习率大,可能一下子迈过了,到另一边去了(从曲线左半边跳到右半边),继续梯度下降又迈回来,使得来来回回震荡。步子太小呢,就像蜗牛一步步往前挪,也会使得整体迭代次数增加。
学习率的设置是门一门学问,一般我们会把它设置成一个小数,0.1、0.01、0.001、0.0001,都是常见的设定数值(然后根据情况调整)。一般情况下学习率在整体迭代过程中是不变,但是也可以设置成随着迭代次数增多学习率逐渐变小,因为越靠近山谷我们就可以步子迈小点,可以更精准的走入最低点,同时防止走过。还有一些深度学习的优化算法会自己控制调整学习率这个值。
1.6.5 实现梯度下降
我们自己用代码亲自实现一遍梯度下降,之后使用API时就明白它底层的核心实现过程了。
1. 假设损失函数是只有一个特征的抛物线:
我们要求解这个抛物线最小值时的横坐标的值:
#1.列损失函数 画出函数图像
loss=lambda w_1:(w_1-3.5)**2-4.5*w_1+10
w_1=np.linspace(0,11.5,100)
plt.plot(w_1,loss(w_1))
#2.求这个损失函数的最小值:梯度下降
def cb():g=lambda w_1:2*(w_1-3.5)-4.5#导函数t0,t1=1,100 alpha=t0/t1#学习率,设置大和过大会导致震荡或者无法收敛w_1=np.random.randint(0,10,size=1)[0]#随机初始值#控制更新次数for i in range(1000):alpha=t0/(i+t1)#控制学习率 逐步变小w_1=w_1-alpha*g(w_1)#梯度下降公式print("更新后的w_1:",w_1)
cb()
2. 假设损失函数是有两个特征的椎体(我画不来 假装下面是个椎体):
上一个案例:一个w_1更新梯度时是抛物线对于求导然后更新
,这个案例是:两个
,那么我们再分别更新
时 就是对于另一个求偏导,比如随机初始:
。
第一次更新时:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
#1.列损失函数 画出函数图像
loss=lambda w_1,w_2:(w_1-3.5)**2+(w_2-2)**2+2*w_2-4.5*w_1+3*w_1*w_2+20
#2.求这个损失函数的最小值:梯度下降
def cb2():t0,t1=1,100 alpha=t0/t1#学习率,设置大和过大会导致震荡或者无法收敛w_1=10#np.random.randint(0,100,size=1)[0]#随机初始值w_2=40#np.random.randint(0,100,size=1)[0]#随机初始值dw_1=lambda w_1,w_2:2*(w_1-3.5)+3*w_2-4.5#w_1的导函数dw_2=lambda w_1,w_2:3*w_1+2*w_2-2#w_2的导函数#控制更新次数for i in range(100):alpha=t0/(i+t1)#控制学习率 逐步变小w_1_=w_1#保存起来 防止梯度下降过程中w_1和w_2的值发生改变w_2_=w_2#w_1=w_1-alpha*dw_1(w_1_,w_2_)#梯度下降公式w_2=w_2-alpha*dw_2(w_1_,w_2_)print("更新后的w_1,w_2:",w_1,w_2)
cb2()
1.6.6 sklearn梯度下降
官方的梯度下降API常用有三种:
1. 批量梯度下降BGD(Batch Gradient Descent) ;
2. 小批量梯度下降MBGD(Mini-BatchGradient Descent);
3. 随机梯度下降SGD(Stochastic Gradient Descent)。
三种梯度下降有什么不同呢?
Batch Gradient Descent (BGD):在这种情况下,每一次迭代都会使用全部的训练样本计算梯度来更新权重。这意味着每一步梯度更新都是基于整个数据集的平均梯度。这种方法的优点是每次更新的方向是最准确的,但缺点是计算量大且速度慢,尤其是在大数据集上。
Mini-Batch Gradient Descent (MBGD):这种方法介于批量梯度下降和随机梯度下降之间。它不是用全部样本也不是只用一个样本,而是每次迭代从数据集中随机抽取一小部分样本(例如,从500个样本中选取32个),然后基于这一小批样本的平均梯度来更新权重。这种方法在准确性和计算效率之间取得了一个平衡。
Stochastic Gradient Descent (SGD):在随机梯度下降中,每次迭代仅使用随机单个样本(或有时称为“例子”)来计算梯度并更新权重。这种方法能够更快地收敛,但由于每次更新都基于单个样本,所以会导致权重更新路径不稳定。
1.6.7 批量梯度下降BGD
批量梯度下降是一种用于机器学习和深度学习中的优化算法,它用于最小化损失函数(目标函数),批量梯度下降使用整个训练数据集来计算梯度并更新模型参数。
原理:批量梯度下降的基本思想是在每个迭代步骤中使用所有训练样本来计算损失函数的梯度,并据此更新模型参数。这使得更新方向更加准确,因为它是基于整个数据集的梯度,而不是像随机梯度下降那样仅基于单个样本。
更新规则:假设我们有一个包含 ( m ) 个训练样本的数据集,其中
是输入特征,
是对应的标签。我们的目标是最小化损失函数
相对于模型参数
的值。
损失函数可以定义为:;其中
是模型对第
个样本的预测输出。
批量梯度下降的更新规则为:;对于
(其中
是特征的数量),并且
是学习率。
特点
-
准确性:由于使用了所有训练样本,所以得到的梯度是最准确的,这有助于找到全局最小值。
-
计算成本:每次更新都需要遍历整个数据集,因此计算量较大,特别是在数据集很大的情况下。
-
收敛速度:虽然每一步的更新都是准确的,但由于计算成本较高,实际收敛到最小值的速度可能不如其他方法快。
-
内存需求:需要在内存中存储整个数据集,对于大型数据集来说可能成为一个问题。
使用场景
-
小数据集:当数据集较小时,批量梯度下降是一个不错的选择,因为它能保证较好的收敛性和准确性。
-
不需要实时更新:如果模型不需要实时更新,例如在离线训练场景下,批量梯度下降是一个合理的选择。
实现注意事项
-
选择合适的学习率:选择合适的学习率对于快速且稳定的收敛至关重要。如果学习率太小,收敛速度会很慢;如果太大,则可能会导致不收敛。
-
数据预处理:对数据进行标准化或归一化,可以提高批量梯度下降的效率。
-
监控损失函数:定期检查损失函数的变化趋势,确保算法正常工作并朝着正确的方向前进。
1.6.8 随机梯度下降SGD
随机梯度下降(Stochastic Gradient Descent, SGD)是一种常用的优化算法,在机器学习和深度学习领域中广泛应用。与批量梯度下降(BGD)和小批量梯度下降(MBGD)相比,SGD 每一步更新参数时仅使用单个训练样本,这使得它更加灵活且计算效率更高,特别是在处理大规模数据集时。
基本步骤
-
初始化参数:选择一个初始点作为参数向量
的初始值。
-
选择样本:随机选取一个训练样本
。
-
计算梯度:使用所选样本
来近似计算损失函数
的梯度
。
-
更新参数:根据梯度的方向来更新参数
。更新公式为:
;其中
是学习率,决定了每次迭代时参数更新的步长。
-
重复步骤 2 到 4:对所有的训练样本重复此过程,直到完成一个完整的 epoch(即所有样本都被访问过一次)。
-
重复多个 epoch:重复上述过程,直到满足某个停止条件,比如达到最大迭代次数或者梯度足够小。
-
输出结果:输出最小化损失函数后的最优参数
。
数学公式:假设我们有一个包含 (m) 个样本的数据集,其中
是第
个样本的特征向量,
是对应的标签。
对于线性回归问题,损失函数可以定义为均方误差 (Mean Squared Error, MSE):
是模型对第 i个样本的预测值。
梯度对于每个参数
的偏导数可以表示为:
。
更新规则:参数的更新规则为:
。
注意事项:
学习率:需要适当设置,太大会导致算法不收敛,太小则收敛速度慢;
随机性: 每次迭代都从训练集中随机选择一个样本,这有助于避免陷入局部最小值;
停止条件: 可以是达到预定的最大迭代次数,或者梯度的范数小于某个阈值。
随机梯度下降的一个关键优势在于它能够快速地进行迭代并适应较大的数据集。然而,由于每次只使用一个样本进行更新,梯度估计可能较为嘈杂,这可能导致更新过程中出现较大的波动。在实际应用中,可以通过减少学习率(例如采用学习率衰减策略)来解决这个问题。
API介绍:
sklearn.linear_model.SGDRegressor()
功能:梯度下降法线性回归
参数:loss: 损失函数,默认为 ’squared_error’fit_intercept: 是否计算偏置, default=Trueeta0: float, default=0.01学习率初始值learning_rate: str, default=’invscaling’ The learning rate schedule:‘constant’: eta = eta0 学习率为eta0设置的值,保持不变‘optimal’: eta = 1.0 / (alpha * (t + t0)) ‘invscaling’: eta = eta0 / pow(t, power_t)‘adaptive’: eta = eta0, 学习率由eta0开始,逐步变小max_iter: int, default=1000 经过训练数据的最大次数(又名epoch)shuffle=True 每批次是否洗牌penalty: {‘l2’, ‘l1’, ‘elasticnet’, None}, default=’l2’要使用的惩罚(又称正则化项)。默认为' l2 ',这是线性SVM模型的标准正则化器。' l1 '和' elasticnet '可能会给模型(特征选择)带来' l2 '无法实现的稀疏性。当设置为None时,不添加惩罚。
属性:
coef_ 回归后的权重系数
intercept_ 偏置
示例:加载加利福尼亚住房数据集,进行回归预测, 注意网络。
# 线性回归 加载加利福尼亚住房数据集,进行回归预测
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, SGDRegressor, Ridge
from sklearn.metrics import mean_squared_errorfrom sklearn.datasets import fetch_california_housing
# 1)加载数据
housing = fetch_california_housing(data_home="./src")
print(housing)
# 2)划分训练集与测试集
x_train, x_test, y_train, y_test = train_test_split(housing.data, housing.target, random_state=22)
# 3)标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)# 4)线性回归预估器
estimator = SGDRegressor(learning_rate="constant", eta0=0.01, max_iter=1000, penalty="l1",loss="squared_error")estimator.fit(x_train, y_train)# 5)得出模型
print("权重系数为:\n", estimator.coef_) #权重系数与特征数一定是同样的个数。
print("偏置为:\n", estimator.intercept_)# 6)模型评估
y_predict = estimator.predict(x_test)
print("预测的数据集:\n", y_predict)
print("得分:\n",estimator.score(x_test, y_test))
error = mean_squared_error(y_test, y_predict)
print("均方误差为:\n", error)
1.6.9 小批量梯度下降MBGD
小批量梯度下降是一种介于批量梯度下降(BGD)与随机梯度下降(SGD)之间的优化算法,它结合了两者的优点,在机器学习和深度学习中被广泛使用。
原理:小批量梯度下降的基本思想是在每个迭代步骤中使用一小部分(即“小批量”)训练样本来计算损失函数的梯度,并据此更新模型参数。这样做的好处在于能够减少计算资源的需求,同时保持一定程度的梯度准确性。
更新规则:假设我们有一个包含 ( m ) 个训练样本的数据集,其中
是输入特征,
是对应的标签。我们将数据集划分为多个小批量,每个小批量包含 ( b ) 个样本,其中 ( b ) 称为批量大小(batch size),通常 ( b ) 远小于 ( m )。
损失函数可以定义为:;其中
是模型对第
个样本的预测输出。
小批量梯度下降的更新规则为:对于
(其中 n 是特征的数量),并且
是学习率, B 表示当前小批量中的样本索引集合。
特点
-
计算效率:相比于批量梯度下降,小批量梯度下降每次更新只需要处理一部分数据,减少了计算成本。
-
梯度估计:相比于随机梯度下降,小批量梯度下降提供了更准确的梯度估计,这有助于更稳定地接近最小值。
-
内存需求:相比批量梯度下降,小批量梯度下降降低了内存需求,但仍然比随机梯度下降要高。
-
收敛速度与稳定性:小批量梯度下降能够在保持较快的收敛速度的同时,维持相对较高的稳定性。
使用场景
-
中等规模数据集:当数据集大小适中时,小批量梯度下降是一个很好的折衷方案,既能够高效处理数据,又能够保持良好的收敛性。
-
在线学习:在数据流式到达的场景下,小批量梯度下降可以有效地处理新到来的数据批次。
-
分布式环境:在分布式计算环境中,小批量梯度下降可以更容易地在多台机器上并行执行。
实现注意事项
-
选择合适的批量大小:批量大小的选择对性能有很大影响。较大的批量可以减少迭代次数,但计算成本增加;较小的批量则相反。
-
选择合适的学习率:选择合适的学习率对于快速且稳定的收敛至关重要。如果学习率太小,收敛速度会很慢;如果太大,则可能会导致不收敛。
-
数据预处理:对数据进行标准化或归一化,可以提高小批量梯度下降的效率。
-
监控损失函数:定期检查损失函数的变化趋势,确保算法正常工作并朝着正确的方向前进。
示例:
# 线性回归 加载加利福尼亚住房数据集,进行回归预测
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, SGDRegressor, Ridge
from sklearn.metrics import mean_squared_errorfrom sklearn.datasets import fetch_california_housing
# 1)加载数据
housing = fetch_california_housing(data_home="./src")
print(housing)
# 2)划分训练集与测试集
x_train, x_test, y_train, y_test = train_test_split(housing.data, housing.target, random_state=22)
# 3)标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# 4)线性回归预估器
estimator = SGDRegressor(learning_rate="constant", eta0=0.01, max_iter=1000,shuffle=True, penalty="l1")
# 小批量梯度下降
batch_size = 50 # 批量大小
n_batches = len(x_train) // batch_size # 批次数量
for epoch in range(estimator.max_iter):indices = np.random.permutation(len(x_train)) # 随机打乱样本顺序for i in range(n_batches):start_idx = i * batch_sizeend_idx = (i + 1) * batch_sizebatch_indices = indices[start_idx:end_idx]X_batch = x_train[batch_indices]y_batch = y_train[batch_indices]estimator.partial_fit(X_batch, y_batch) # 更新模型权重# 5)得出模型
print("权重系数为:\n", estimator.coef_) #权重系数与特征数一定是同样的个数。
print("偏置为:\n", estimator.intercept_)# 6)模型评估
y_predict = estimator.predict(x_test)
print("得分:\n",estimator.score(x_test, y_test))
print("预测的数据集:\n", y_predict)
error = mean_squared_error(y_test, y_predict)
print("均方误差为:\n", error)
梯度下降优化:
1. 标准化:前期数据的预处理,前面有的;
2. 正则化:防止过拟合(下面一小节讲)。
1.7 欠拟合过拟合
1.7.1 欠拟合
欠拟合是指模型在训练数据上表现不佳,同时在新的未见过的数据上也表现不佳。这通常发生在模型过于简单,无法捕捉数据中的复杂模式时。欠拟合模型的表现特征如下:
1. 训练误差较高;
2. 测试误差同样较高;
3. 模型可能过于简化,不能充分学习训练数据中的模式。
1.7.2 过拟合
过拟合是指模型在训练数据上表现得非常好,但在新的未见过的数据上表现较差。这通常发生在模型过于复杂,以至于它不仅学习了数据中的真实模式,还学习了噪声和异常值。过拟合模型的表现特征如下:
1. 训练误差非常低;
2. 测试误差较高;
3. 模型可能过于复杂,以至于它对训练数据进行了过度拟合。
1.7.3 正则化
正则化就是防止过拟合,增加模型的鲁棒性,鲁棒是Robust 的音译,也就是强壮的意思。就像计算机软件在面临攻击、网络过载等情况下能够不死机不崩溃,这就是软件的鲁棒性,鲁棒性调优就是让模型拥有更好的鲁棒 性,也就是让模型的泛化能力和推广能力更加的强大。
比如,下面两个方程描述同一条直线,哪个更好?
;
。
第一个更好,因为下面的公式是上面的十倍,当w越小公式的容错的能力就越好。我们都知道人工智能中回归是有误差的,为了把误差降低而拟合出来的一个接近真实的公式,比如把一个测试数据[10,20]带入计算得到的值跟真实值会存在一定的误差,但是第二个方程会把误差放大,公式中,当x有一点错误,这个错误会通过w放大。但是w不能太小,当w太小时(比如都趋近0),模型就没有意义了,无法应用。
想要有一定的容错率又要保证正确率就要由正则项来发挥作用了! 所以正则化(鲁棒性调优)的本质就是牺牲模型在训练集上的正确率来提高推广、泛化能力,W在数值上越小越好,这样能抵抗数值的扰动。同时为了保证模型的正确率W又不能极小。因此将原来的损失函数加上一个惩罚项使得计算出来的模型W相对小一些,就是正则化。这里面损失函数就是原来固有的损失函数,比如回归的话通常是MSE,然后在加上一部分惩罚项来使得计算出来的模型W相对小一些来带来泛化能力。
常用的惩罚项有L1正则项或者L2正则项:
,对应曼哈顿距离;
,对应欧氏距离。
其实L1 和L2 正则的公式在数学里面的意义就是范数,代表空间中向量到原点的距离,当我们把多元线性回归损失函数加上L2正则的时候,就诞生了Ridge岭回归。当我们把多元线性回归损失函数加上L1正则的时候,就孕育出来了Lasso回归。其实L1和L2正则项惩罚项可以加到任何算法的损失函数上面去提高计算出来模型的泛化能力的。
2. 岭回归Ridge
2.1 损失函数公式
岭回归是失损函数通过添加所有权重的平方和的乘积(L2)来惩罚模型的复杂度。
均方差除以2是因为方便求导,指所有的权重系数, λ指惩罚型系数,又叫正则项力度,特点:
1. 岭回归不会将权重压缩到零,这意味着所有特征都会保留在模型中,但它们的权重会被缩小;
2. 适用于特征间存在多重共线性的情况;
3. 岭回归产生的模型通常更为平滑,因为它对所有特征都有影响。
2.2 API 介绍
具有L2正则化的线性回归-岭回归。
sklearn.linear_model.Ridge()
1 参数:
(1)alpha, default=1.0,正则项力度
(2)fit_intercept, 是否计算偏置, default=True
(3)solver, {‘auto’, ‘svd’, ‘cholesky’, ‘lsqr’, ‘sparse_cg’, ‘sag’, ‘saga’, ‘lbfgs’}, default=’auto’
当值为auto,并且数据量、特征都比较大时,内部会随机梯度下降法。
(4)normalize:,default=True, 数据进行标准化,如果特征工程中已经做过标准化,这里就该设置为False
(5)max_iterint, default=None,梯度解算器的最大迭代次数,默认为150002 属性
coef_ 回归后的权重系数
intercept_ 偏置说明:SGDRegressor也可以做岭回归的事情,比如SGDRegressor(penalty='l2',loss="squared_loss"),但是其中梯度下降法有些不同。所以推荐使用Ridge实现岭回归
示例:岭回归 加载加利福尼亚住房数据集,进行回归预测。
# 岭回归 加载加利福尼亚住房数据集,进行回归预测
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, SGDRegressor, Ridge
from sklearn.metrics import mean_squared_errorfrom sklearn.datasets import fetch_california_housing
# 1)加载数据
housing = fetch_california_housing(data_home="./src")
print(housing)
# 2)划分训练集与测试集
x_train, x_test, y_train, y_test = train_test_split(housing.data, housing.target, random_state=22)
# 3)标准化
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)# 4)岭回归预估器
estimator = Ridge(alpha=0.5, max_iter=10000)
estimator.fit(x_train, y_train)# 5)得出模型
print("权重系数为:\n", estimator.coef_) #权重系数与特征数一定是同样的个数。
print("偏置为:\n", estimator.intercept_)# 6)模型评估
y_predict = estimator.predict(x_test)
print("预测的数据集:\n", y_predict)
error = mean_squared_error(y_test, y_predict)
print("均方误差为:\n", error)
3. 拉索回归Lasso
3.1 损失函数公式
Lasso回归是一种线性回归模型,它通过添加所有权重的绝对值之和(L1)来惩罚模型的复杂度。Lasso回归的目标是最小化以下损失函数:
其中:n 是样本数量;p 是特征的数量;是第 i 个样本的目标值;
是第
个样本的特征向量;w是模型的参数向量;
是正则化参数,控制正则化项的强度。
特点:
1. 拉索回归可以将一些权重压缩到零,从而实现特征选择。这意味着模型最终可能只包含一部分特征;
2. 适用于特征数量远大于样本数量的情况,或者当特征间存在相关性时,可以从中选择最相关的特征;
3. 拉索回归产生的模型可能更简单,因为它会去除一些不重要的特征。
3.2 API 介绍
sklearn.linear_model.Lasso()
参数:
-
alpha (float, default=1.0):控制正则化强度;必须是非负浮点数。较大的 alpha 增加了正则化强度。
-
fit_intercept (bool, default=True):是否计算此模型的截距。如果设置为 False,则不会使用截距(即数据应该已经被居中)。
-
precompute (bool or array-like, default=False):如果为 True,则使用预计算的 Gram 矩阵来加速计算。如果为数组,则使用提供的 Gram 矩阵。
-
copy_X (bool, default=True):如果为 True,则复制数据 X,否则可能对其进行修改。
-
max_iter (int, default=1000):最大迭代次数。
-
tol (float, default=1e-4):精度阈值。如果更新后的系数向量减去之前的系数向量的无穷范数除以 1 加上更新后的系数向量的无穷范数小于 tol,则认为收敛。
-
warm_start (bool, default=False):当设置为 True 时,再次调用 fit 方法会重新使用之前调用 fit 方法的结果作为初始估计值,而不是清零它们。
-
positive (bool, default=False):当设置为 True 时,强制系数为非负。
-
random_state (int, RandomState instance, default=None):随机数生成器的状态。用于随机初始化坐标下降算法中的随机选择。
-
selection ({'cyclic', 'random'}, default='cyclic'):如果设置为 'random',则随机选择坐标进行更新。如果设置为 'cyclic',则按照循环顺序选择坐标。
属性:
-
coef_:系数向量或者矩阵,代表了每个特征的权重。
-
intercept_:截距项(如果 fit_intercept=True)。
-
n_iter_:实际使用的迭代次数。
-
n_features_in_ (int):训练样本中特征的数量。
示例:
from sklearn.datasets import fetch_california_housing
from sklearn.linear_model import Lasso
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import numpy as np# 加载波士顿房价数据集
data = fetch_california_housing(data_home="./src")
X, y = data.data, data.target# 划分训练集和测试集
X_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)# 创建Lasso回归模型
lasso = Lasso(alpha=0.1) # alpha是正则化参数# 训练模型
lasso.fit(X_train, y_train)# 得出模型
print("权重系数为:\n", lasso.coef_) #权重系数与特征数一定是同样的个数。
print("偏置为:\n", lasso.intercept_)#模型评估
y_predict = lasso.predict(x_test)
print("预测的数据集:\n", y_predict)
error = mean_squared_error(y_test, y_predict)
print("均方误差为:\n", error)
4. 逻辑回归
4.1 概念
逻辑回归(Logistic Regression)是机器学习中的一种分类模型,逻辑回归是一种分类算法,虽然名字中带有回归,但是它与回归之间有一定的联系。由于算法的简单和高效,在实际中应用非常广泛。
逻辑回归一般用于二分类问题,比如:是好瓜还是坏瓜,健康还是不健康,可以托付终身还是不可以。
4.2 原理
逻辑回归的输入是线性回归的输出,线性回归:;
sigmoid激活函数:;sigmoid函数的值是在[0,1]区间中的一个概率值,默认为0.5为阈值可以自己设定,大于0.5认为是正例,小于则认为是负例,把上面的h(w) 线性的输出再输入到sigmoid函数当中
。
损失函数:
损失函数图:当y=1时:
通过损失函数图像,我们知道:当y=1时,我们希望值越大越好;当y=0时,我们希望
值越小越好。
综合0和1的损失函数:
通过计算:
然后使用梯度下降算法,去减少损失函数的值,这样去更新逻辑回归前面对应算法的权重参数,提升原本属于1类别的概率,降低原本是0类别的概率。
4.3 API 介绍
sklearn.linear_model.LogisticRegression()
参数:fit_intercept bool, default=True 指定是否计算截距max_iter int, default=100 最大迭代次数。迭代达到此数目后,即使未收敛也会停止。
模型对象:.coef_ 权重.intercept_ 偏置predict()预测分类predict_proba()预测分类(对应的概率)score()准确率
示例:
#导包
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
#加载数据
X,y = load_iris(return_X_y=True)
print(y)#二分类 删除第三类
X=X[y!=2]
y=y[y!=2]
print(y)#数据集划分
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.25,random_state=33)
print(X_train.shape,y_train.shape)#逻辑回归模型
model=LogisticRegression()#训练
model.fit(X_train,y_train)#权重
print(model.coef_)#偏置
print(model.intercept_)#预测分类
y_predict=model.predict(X_test)
print(y_predict)
print(y_test)#预测分类对应的概率
proba=model.predict_proba(X_test)
print(proba)#评估
print(model.score(X_test,y_test))
5. 无监督学习之K-means算法
5.1 无监督学习
无监督学习(Unsupervised Learning)计算机根据样本的特征或相关性,实现从样本数据中训练出相应的预测模型。
无监督学习模型算法中,模型只需要使用特征矩阵X即可,不需要真实的标签y,聚类算法是无监督学习中的代表之一。
-
聚类算法:
-
数据集中,拥有数据特征,但是没有具体的标签
-
将数据划分成有意义或有用的簇
-
聚类算法追求“簇内差异小,簇外差异大”。而这个 “差异”便是通过样本点到其簇质心的距离来衡量
-
-
聚类算法和分类算法的区别:
5.2 K-means 算法
K-means 是一种流行的聚类算法,主要用于无监督学习中对未标记的数据进行分类,该算法的目标是将数据集中的样本划分为K个簇,使得簇内的样本彼此之间的差异最小化,这种差异通常通过簇内所有点到该簇中心点的距离平方和来衡量。
属性 | 含义 |
---|---|
簇 | Kmeans 算法将一组N 个样本的特征矩阵X 划分为K 个无交集的簇,直观上看来簇是一个又一个聚集一起的数据,在一个簇中的数据就认为是同一类,簇就是聚类的结果表现,其中簇的个数是一个超参数 |
质心 | 每个簇中所有数据的均值u ,通常被称为这个簇的"质心" ,在二维平面中,簇的质心横坐标是横坐标的均值,质心的纵坐标是纵坐标的均值 |
K-means 算法的基本步骤:
1. 随机抽取`k`个样本作为最初的质心,这可以通过随机选取数据集中的K个样本或者使用一些启发式方法来实现;
2. 计算每个样本点与`k`个质心的距离(通常是欧氏距离),将样本点分配到最近的一个质心,生成`k`个簇;
3. 对于每个簇,计算所有被分该簇的样本点的平均值作为新的质心;
4. 当质心的位置不再发生变化或者迭代结束,聚类完成。
动态图示:
5.3 API 介绍
K-means 算法输入的是 k 值和样本数据结合,输出的是 k 个簇的集合。
-
sklearn.cluster.KMeans
类是scikit-learn
库提供的一个用于执行K-means聚类算法的工具。它提供了一个易于使用的接口来执行聚类操作,并且内置了多种优化选项,KMeans()
用来实例化模型对象参数如下:
-
n_clusters
: int,默认为8。要创建的簇的数量; -
init
:, callable 或传入的数组,默认为'k-means++'。指定如何初始化质心。'k-means++'使用一种启发式方法来选择初始质心,以加快收敛速度;'random'则随机选择初始质心;
-
n_init
: int,默认为10。运行算法的次数,每次使用不同的质心初始化。最终结果将是具有最低惰性的模型; -
max_iter
: int,默认为300。单次运行的最大迭代次数。
-
-
cluster_centers_
属性:cluster_centers_ 属性存储了每个聚类的中心点坐标; -
labels_
属性:labels_ 存储了每个数据点的聚类标签。 -
make_blobs
方法是 Sklearn 库中 sklearn.datasets 模块提供的一个函数,用于生成一组二维或高维的数据簇。这些数据簇通常用于聚类算法的测试。具体来说:-
参数:
-
n_samples 参数指定了生成样本的数量;
-
centers 参数定义了数据集中簇的中心数量;
-
random_state 参数用于设置随机数生成器的种子,以便在不同运行之间获得相同的结果。
-
-
返回值:返回一个元组
-
X:一个形状为 (n_samples, n_features) 的数组,表示生成的样本数据。每个样本都是一行,特征列为样本的各个维度坐标;
-
y:一个形状为 (n_samples,) 的数组,表示每个样本所属的簇标签(中心索引)。如果不需要这个标签,可以像示例中那样用 _ 忽略它。
-
-
示例:
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np
data=np.random.randint(0,1000,(1000,2))
# print(data)
# plt.scatter(data[:,0],data[:,1])
# plt.show()
# model.fit(data)
n_class=7
model=KMeans(n_class)
model.fit(data)
# print(model.cluster_centers_)
# print(model.labels_)
# print(model.labels_==0)
# print(data[model.labels_==0])
for i in range(n_class):point=data[model.labels_==i]plt.scatter(point[:,0],point[:,1])
# plt.scatter(model.cluster_centers_[:,0],model.cluster_centers_[:,1])
plt.show()