线性回归
线性回归预测模型
向量化线性回归公式:
在实践中,选择线性回归的成本函数时,将均方误差(MSE)最小化比最小化RMSE更为简单,二者效果相同(因为使函数最小化的值,同样也使其平方根最小)。
线性回归模型的MSE成本函数
标准线性方程的闭式解:
梯度下降算法
梯度下降是一种非常通用的优化算法,能够为大范围的问题找到最优解。梯度下降的中心思想就是迭代地调整参数从而使成本函数最小化。具体来说,首先使用一个随机的θ值(这被称为随机初始化),然后逐步改进,每次踏出一步,每一步都尝试降低一点成本函数(如MSE),直到算法收敛出一个最小值。
梯度下降算法示意图
梯度下降中一个重要参数是每一步的步长,这取决于超参数学习率。如果学习率太低,算法需要经过大量迭代才能收敛,这将耗费很长时间。
学习率太低
如果学习率太高,那你可能会越过山谷直接到达山的另一边,甚至有可能比之前的起点还要高。这会导致算法发散,值越来越大,最后无法找到好的解决方案。
学习率太高
最后,并不是所有的成本函数看起来都像一个漂亮的碗。有的可能看着像洞、像山脉、像高原或者是各种不规则的地形,导致很难收敛到最小值。
幸好,线性回归模型的MSE成本函数恰好是个凸函数,这意味着连接曲线上任意两个点的线段永远不会跟曲线相交。也就是说不存在局部最小,只有一个全局最小值。它同时也是一个连续函数,所以斜率不会产生陡峭的变化。
成本函数虽然是碗状的,但如果不同特征的尺寸差别巨大,那它可能是一个非常细长的碗。如图所示的梯度下降,左边的训练集上特征1和特征2具有相同的数值规模,而右边的训练集上,特征1的值则比特征2要小得多。
特征缩放和无特征缩放的梯度下降
左图的梯度下降算法直接走向最小值,可以快速到达。而在右图中,先是沿着与全局最小值方向近乎垂直的方向前进,接下来是一段几乎平坦的长长的山谷。最终还是会抵达最小值,但是这需要花费大量的时间。
批量梯度下降
要实现梯度下降,你需要计算每个模型关于参数θj的成本函数的梯度。换言之,你需要计算的是如果改变θj,成本函数会改变多少。这被称为偏导数。
成本函数的偏导数
成本函数的梯度向量
如果要训练的线性模型拥有几十万个特征,使用梯度下降比标准方程要快得多。
一旦有了梯度向量,哪个点向上,就朝反方向下坡。也就是从θ中减去梯度向量。这时学习率η就发挥作用了:用梯度向量乘以η确定下坡步长的大小。
梯度下降步长
随机梯度下降
批量梯度下降的主要问题是它要用整个训练集来计算每一步的梯度,所以训练集很大时,算法会特别慢。与之相反的极端是随机梯度下降,每一步在训练集中随机选择一个实例,并且仅基于该单个实例来计算梯度。显然,这让算法变得快多了,因为每个迭代都只需要操作少量的数据。
由于算法的随机性质,它比批量梯度下降要不规则得多。成本函数将不再是缓缓降低直到抵达最小值,而是不断上上下下,但是从整体来看,还是在慢慢下降。随着时间推移,最终会非常接近最小值,但是即使它到达了最小值,依旧还会持续反弹,永远不会停止。所以算法停下来的参数值肯定是足够好的,但不是最优的。
随机梯度下降
随机梯度下降其实可以帮助算法跳出局部最小值,所以相比批量梯度下降,它对找到全局最小值更有优势。
小批量梯度下降
每一步的梯度计算,既不是基于整个训练集(如批量梯度下降)也不是基于单个实例(如随机梯度下降),而是基于一小部分随机的实例集也就是小批量。相比随机梯度下降,小批量梯度下降的主要优势在于可以从矩阵运算的硬件优化中获得显著的性能提升,特别是需要用到图形处理器时。
多项式回归
将每个特征的幂次方添加为一个新特征,然后在这个拓展过的特征集上训练线性模型。这种方法被称为多项式回归。
正则线性模型
减少过度拟合的一个好办法就是对模型正则化(即约束它):它拥有的自由度越低,就越不容易过度拟合数据。比如,将多项式模型正则化的简单方法就是降低多项式的阶数。
岭回归
岭回归(也叫作吉洪诺夫正则化)是线性回归的正则化版:在成本函数中添加一个等于
的正则项。这使得学习中的算法不仅需要拟合数据,同时还要让模型权重保持最小。注意,正则项只能在训练的时候添加到成本函数中,一旦训练完成,你需要使用未经正则化的性能指标来评估模型性能。
训练阶段使用的成本函数与测试时使用的成本函数不同是非常常见的现象。除了正则化以外,还有一个导致这种不同的原因是,训练时的成本函数通常都可以使用优化过的衍生函数,而测试用的性能指标需要尽可能接近最终目标。
岭回归成本函数
超参数α控制的是对模型进行正则化的程度。如果α=0,则岭回归就是线性模型。如果α非常大,那么所有的权重都将非常接近于零,结果是一条穿过数据平均值的水平线。
在执行岭回归之前,必须对数据进行缩放(例如使用StandardScaler),因为它对输入特征的大小非常敏感。大多数正则化模型都是如此。
岭回归方程的闭式解
套索回归
线性回归的另一种正则化,叫作最小绝对收缩和选择算子回归(简称Lasso回归,或套索回归)。与岭回归一样,它也是向成本函数增加一个正则项,但是它增加的是权重向量的l1范数,而不是l2范数的平方的一半。
套索回归成本函数
Lasso回归的一个重要特点是它倾向于完全消除掉最不重要特征的权重(将他们设置为零)
岭回归和套索回归的区别:岭回归会倾向于将重要特征值的权重逐渐减小。套索回归会逐渐消除掉不重要的特征值。
弹性网络
弹性网络是岭回归与Lasso回归之间的中间地带。其正则项就是岭回归和Lasso回归的正则项的混合,混合比例通过r来控制。当r=0时,弹性网络即等同于岭回归,而当r=1时,即相当于Lasso回归。
弹性网络成本函数
早期停止法
对于梯度下降这一类迭代学习的算法,还有一个与众不同的正则化方法,就是在验证误差达到最小值时停止训练,该方法叫作早期停止法。下图展现了一个用批量梯度下降训练的复杂模型(高阶多项式回归模型)。经过一轮一轮的训练,算法不断地学习,训练集上的预测误差(RMSE)自然不断下降,同样其在验证集上的预测误差也随之下降。但是,一段时间之后,验证误差停止下降反而开始回升。这说明模型开始过度拟合训练数据。通过早期停止法,一旦验证误差达到最小值就立刻停止训练。
早期停止法正则化
线性模型的回归算法
逻辑回归
逻辑回归(Logistic回归,也称为罗吉思回归)被广泛用于估算一个实例属于某个特定类别的概率。如果预估概率超过50%,则模型预测该实例属于该类别(称为正类,标记为“1”),反之,则预测不是(也就是负类,标记为“0”)。这样它就成了一个二元分类器。
逻辑回归概率估算方式
跟线性回归模型一样,逻辑回归模型也是计算输入特征的加权和(加上偏置项),但是不同于线性回归模型直接输出结果,它输出的是结果的数理逻辑
逻辑回归概率估算
逻辑模型(也称为罗吉特),是一个sigmoid函数(即S形),机座σ(·),它输出一个0到1之间的数字。
逻辑函数
逻辑回归的预测函数
训练和成本函数
这个成本函数是有道理的,因为当t接近于0时,-log(t)会变得非常大,所以如果模型估算一个正类实例的概率接近于0,成本将会变得很高。同理估算出一个负类实例的概率接近1,成本也会变得非常高。那么反过来,当t接近于1的时候,-log(t)接近于0,所以对一个负类实例估算出的概率接近于0。
逻辑回归成本函数
Softmax回归
代码:
import numpy as np
# 随机生成点 y = 4 + 3x + 噪声
x=2*np.random.rand(100,1)
y=4+3*x+np.random.randn(100,1)
import matplotlib.pyplot as plt
plt.scatter(x,y)
plt.show()
- 线性方程的截距和系数
from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(x,y)
# 线性方程的截距和系数
lin_reg.intercept_,lin_reg.coef_
- 根据散点图画出回归方程
line_x=np.linspace(0,2,100)
line_y=lin_reg.coef_*line_x+lin_reg.intercept_
line_y=line_y.reshape(100,)
import matplotlib.pyplot as plt
plt.scatter(x,y)
plt.plot(line_x,line_y,'r--')
plt.show()
- 多项式回归
m=100
X=6*np.random.rand(m,1)-3
y=0.5*X**2+2+np.random.randn(m,1)
plt.scatter(X,y)
from sklearn.preprocessing import PolynomialFeatures
ploy_features = PolynomialFeatures(degree=2,include_bias=False)
# 将X转换为多项式类型
X_ploy = ploy_features.fit_transform(X)
line_reg = LinearRegression()
line_reg.fit(X_ploy,y)
line_reg.intercept_, line_reg.coef_
#out:(array([1.93972958]), array([[-0.00557663, 0.46076188]]))
- 绘制学习曲线:绘制训练集和测试集的误差
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
def plot_learning_curve(model,X,y):
X_train,X_val,y_train,y_val = train_test_split(X,y,test_size=0.2)
train_errors,val_errors = [],[]
for m in range(1,len(X_train)):
model.fit(X_train[:m],y_train[:m])
# 在训练集上预测
y_train_predict = model.predict(X_train[:m])
#在测试集上预测
y_val_predict = model.predict(X_val)
#计算并添加误差
train_errors.append(mean_squared_error(y_train_predict,y_train[:m]))
val_errors.append(mean_squared_error(y_val_predict,y_val))
plt.plot(np.sqrt(train_errors),'r-+',linewidth=2,label='train')
plt.plot(np.sqrt(val_errors),'b-',linewidth=3,label='val')
plt.legend()
lin_reg = LinearRegression()
plot_learning_curve(lin_reg,X,y)