线性回归算法梳理(从理论到示例)

1、机器学习的一些概念

  • 有监督、无监督:

    有监督机器学习又被称为“有老师的学习”,所谓的老师是指标签。监督学习就是最常见的分类(注意和聚类区分)问题,通过已有的训练样本(即已知数据及其对应的输出)去训练得到一个最优模型(这个模型属于某个函数的集合,最优表示某个评价准则下是最佳的),再利用这个模型将所有的输入映射为相应的输出,对输出进行简单的判断从而实现分类的目的。也就具有了对未知数据分类的能力。

    无监督机器学习被称为“没有老师的学习”,无监督相比于有监督,输入数据没有被标记,也没有确定的结果。样本数据类别未知,需要根据样本间的相似性对样本集进行分类(聚类,clustering)试图使类内差距最小化,类间差距最大化。通俗点将就是实际应用中,不少情况下无法预先知道样本的标签,也就是说没有训练样本对应的类别,因而只能从原先没有样本标签的样本集开始学习分类器设计。

  • 泛化能力:

    泛化能力(generalization ability)是指一个机器学习算法对于没有见过的样本的识别能力。我们也叫做举一反三的能力,或者叫做学以致用的能力。举个例子,小学生先通过学习十以内的加减乘除,知道什么是四则运算和怎么具体去算数,以后遇到百以内或者千以内的数字也知道怎么去做四则运算。我们只教会他十以内的运算,他自己就能推广到百以内或者千以内的运算,这种能力就是泛化能力。

  • 过拟合与欠拟合(方差和偏差以及各自的解决办法):

    过拟合:小学生学习四则运算,老师教过1+1=2,那么学生只记住了1+1=2,以后做题的时候碰到1+1知道答案是2,但是碰到10+10就不知道怎么计算答案,学生只是死记硬背1+1的答案是2,没理解四则运算的规律,不会推广到10+10,也就是泛化能力非常低,同时我们也把这种现象叫做过拟合(over-fitting)了。
    过拟合是一种分类器会发生的现象,而泛化能力可以理解为对分类器的一种性能的评价,过拟合表现为算法模型的高方差,模型训练时的结果很好,但是在预测时结果不好。
    产生过拟合的原因:模型的复杂度太高,比如:网络太深;过多的变量(特征);训练数据非常少。
    避免过拟合的方法有很多:(1)尽量减少特征的数量、(2)early stopping、(3)数据集扩增、(4)dropout、(5)正则化包括L1、L2、(6)清洗数据。

    欠拟合under-fitting)是和过拟合相对的现象,可以说是模型的复杂度较低,没法很好的学习到数据背后的规律。就好像开普勒在总结天体运行规律之前,他的老师第谷记录了很多的运行数据,但是都没法用数据去解释天体运行的规律并预测,这就是在天体运行数据上,人们一直处于欠拟合的状态,只知道记录过的过去是这样运行的,但是不知道道理是什么。
    欠拟合指的是模型不够复杂,没有很好地捕捉到数据特征,不能够很好地拟合数据,对应模型的高偏差。
    解决欠拟合可以从寻找更好的特征(具有代表性的)和使用更多的特征(增大输入向量的维度)。具体的方法:1、添加更多的特征项(比如上下文特征、位置特征等);2、添加多项式特征(例如将线性模型通过添加二次项或者三次项使模型泛化能力更强);3、减少正则化参数,正则化的目的是用来防止过拟合的,但是现在模型出现了欠拟合,则需要减少正则化参数。

  • 交叉验证:

    一个交叉验证将样本数据集分成两个互补的子集,一个子集用于训练(分类器或模型)称为训练集(training set);另一个子集用于验证(分类器或模型的)分析的有效性称为测试集(testing set)。利用测试集来测试训练得到的分类器或模型,以此作为分类器或模型的性能指标。得到高度预测精确度和低的预测误差,是研究的期望。为了减少交叉验证结果的可变性,对一个样本数据集进行多次不同的划分,得到不同的互补子集,进行多次交叉验证。取多次验证的平均值作为验证结果。
    用交叉验证的目的是为了得到可靠稳定的模型。

2、线性回归的原理

线性回归为何叫线性?实际上,像在处理Google的股票统计数据时,我们使用线性回归是在这堆数据所在的N维空间中找到一条线来描述这些数据的规律,因此才叫线性回归。这个过程称为拟合,这条线成为拟合线。
这条拟合线上的某个数据点或多或少都会偏离实际统计的值。实际统计数据和拟合线对应数据的差叫残差。很明显,残差可以反映模型的预测误差。
但是残差有正有负的,不方便计算。而且实际运用中我们不需要关注残差的正负,因为正负并不能描述误差的大小程度。为了降低计算复杂性,我们使用这个差值的平方进行计算。你可能会想到,差值的平方不是把差值给改了吗,没关系吗?答案是:数据确实变了,但没影响。因为我们真正使用的是残差的绝对值,用它描述误差大小的程度,而对这个绝对值进行平方后有同样的效果,毕竟 y = ∣ x ∣ {y = |x|} y=x y = x 2 {y = x^2} y=x2有同样的单调性。

结合上述平方的想法,为了让预测更加准确,我们应该选择一条线,能够使得线上每个点与实际数据的残差平方的总和最小。这样的线才能叫最佳拟合线。直观理解,线性回归其实就是这么一条直线。

3、线性回归的目标函数、损失函数(代价函数)

线性回归试图学得 f ( x i ) = w ∗ x i + b {f(x_i) = w*x_i + b} f(xi)=wxi+b目标函数)使得 f ( x i ) ≃ y i {f(x_i)\simeq y_i} f(xi)yi,如何确定 w {w} w b {b} b呢?关键在于如何衡量 f ( x ) {f(x)} f(x) y {y} y之间的差别。
均方误差是回归任务中常用的性能度量,因此我们试图让均方误差(损失函数,或代价函数)最小化,即
( w ∗ , b ∗ ) = a r g m i n ( w , b ) ∑ i = 1 m ( f ( x i ) − y i ) 2 = a r g m i n ( w , b ) ∑ i = 1 m ( y i − w x i − b ) 2 {(w^*,b^*)=argmin_{(w,b)} \sum_{i=1}^{m}(f(x_i)-y_i)^2=argmin_{(w,b)} \sum_{i=1}^{m}(y_i-wx_i-b)^2} (w,b)=argmin(w,b)i=1m(f(xi)yi)2=argmin(w,b)i=1m(yiwxib)2
均方误差有非常好的几何意义,它对应了常用的欧几里得距离(欧氏距离),基于均方误差最小化来进行模型求解的方法称为“最小二乘法”。
在线性回归中,最小二乘法就是试图找到一条直线,使得所有样本到直线上的欧氏距离之和最小。
求解 w {w} w b {b} b使 ∑ ( w , b ) = ∑ i = 1 m ( y i − w x i − b ) 2 {\sum_{(w,b)}=\sum_{i=1}^{m}(y_i-wx_i-b)^2} (w,b)=i=1m(yiwxib)2最小化的过程,称为线性回归模型的最小二乘“参数估计”。这里暂不推广到其它模型(多元线性回归和逻辑回归)。

注意: 我们为了求导计算方便,往往将损失函数写成下面的形式:
J ( w ) = J ( w 0 , w 1 ) = 1 2 m ∑ i = 1 m ( h ( x i ) − y i ) 2 {J(w)=J(w_0,w_1)=\frac {1}{2m} \sum_{i=1}^{m}(h(x^i)-y^i)^2} J(w)=J(w0,w1)=2m1i=1m(h(xi)yi)2
其中, h ( x i ) − y i {h(x^i)-y^i} h(xi)yi是预测值和实际值的差,所以损失(成本代价)就是预测值和实际值的差的平方的平均值,之所以乘以 1 2 {\frac {1}{2}} 21是为了计算方便,这个函数也被称为均方差方程。有了损失函数,就可以精确地测量模型对训练样本拟合的好坏程度。

4、优化方法(梯度下降法、牛顿法等)

有了目标函数(预测函数),也可以精确地测量预测函数对训练样本的拟合情况,我们要怎样求解模型的参数的值呢?这时,梯度下降算法就派上用场了。

梯度下降法

我们希望能找到 w {w} w使得 J ( w ) {J(w)} J(w)达到最小,于是我们可以使一个搜索算法,初始化 w {w} w为一个任意值,在迭代过程中不断地更新 w {w} w使得 J ( w ) {J(w)} J(w)更小,直到收敛为止(可以认为 J ( w ) {J(w)} J(w)不再改变)。下面我们来考虑梯度下降算法,它先给 w {w} w一个初始化值,然后通过下面公式来更新 w {w} w
w j : = w j − η   ∂ J ( w ) ∂ w j {w_j:= w_j-\eta \ \frac{\partial J(w)}{\partial w_j}} wj:=wjη wjJ(w),其中 j = 0 , 1 , 2 , . . . , n {j=0,1,2,...,n} j=0,1,2,...,n
上式中, η {\eta} η是学习率,为了理解上面的算法,我们需要推导一下偏微分部分,推导过程中我们只考虑一个样例 ( x , y ) {(x,y)} (x,y),然后只需要把所有的样例加起来就可以了。
∂ J ( w ) ∂ w j = 1 2 ∂ ( h w ( x ) − y ) 2 ∂ w j = ( h w ( x ) − y ) ∂ ( ∑ i = 0 n w i x i − y ) ∂ w j = ( h w ( x ) − y ) x j {\frac{\partial J(w)}{\partial w_j}=\frac{1}{2} \frac{\partial (h_w(x)-y)^2}{\partial w_j} = (h_w(x)-y)\frac{\partial (\sum_{i=0}^{n}w_ix_i-y)}{\partial w_j}=(h_w(x)-y)x_j} wjJ(w)=21wj(hw(x)y)2=(hw(x)y)wj(i=0nwixiy)=(hw(x)y)xj
对于单独的第i个样本,更新规则为:
w j : = w j − η ( h w ( x i ) − y i ) x j i {w_j:= w_j-\eta (h_w(x^{i})-y^i)x_{j}^{i}} wj:=wjη(hw(xi)yi)xji,其中 j = 0 , 1 , 2 , . . . . , n {j=0,1,2,....,n} j=0,1,2,....,n
当有m个样本时,更新规则为:
w j : = w j − η ∑ i = 1 m ( h w ( x i ) − y i ) x j i {w_j:= w_j-\eta \sum_{i=1}^{m}(h_w(x^{i})-y^i)x_{j}^{i}} wj:=wjηi=1m(hw(xi)yi)xji,其中 j = 0 , 1 , 2 , . . . , n {j=0,1,2,...,n} j=0,1,2,...,n
上式每次迭代将所有样本考虑进来更新 w {w} w,这种方法叫做批量梯度下降。梯度下降容易陷入一个局部的最优解,事实上 J ( w ) {J(w)} J(w)是一个凸函数,所以没有所谓的局部最优解,它只有一个全局最优解,凸函数的这种性质非常好用。
之后又出现了随机梯度下降(或增量梯度下降)SGD,该算法每一个样例都更新了 w {w} w一次,当m很大的时候,批量梯度下会很耗时,通常,随机梯度下降比批量梯度下降要快很多,然而它可能永远达不到最小值,并在最小值附近震荡,而实际上这种近似最小值已经够了。在样本量比较大的情况下,随机梯度下降比梯度下降更实用。

牛顿法

牛顿法的思想就是通过迭代来找到函数的零点。牛顿法是二阶收敛,梯度下降是一阶收敛,牛顿法通常比梯度下降算法收敛速度要快,只需要更少的迭代次数就能获得最小值。然而一次牛顿迭代要比一次梯度下降更昂贵,因为它需要计算 H e s s a n {Hessan} Hessan矩阵并且求它的逆,这将花费不少时间。但是当参数个数 n {n} n不是太大时,总体来说速度还是要快很多。

5、线性回归的评估指标

在预测任务中,给定样例集 D = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x m , y m ) } {D=\{(x_1,y_1),(x_2,y_2),...,(x_m,y_m)\}} D={(x1,y1),(x2,y2),...,(xm,ym)},其中 y i {y_i} yi是示例 x i {x_i} xi的真实标记。要评估学习器 f {f} f的性能,就要把学习器预测结果 f {f} f与真实标记 y {y} y进行比较。
回归任务最常用的性能度量(评估指标)是“均方误差”(mean squared error,MSE):
E ( f ; D ) = 1 m ∑ i = 1 m ( f ( x i ) − y i ) 2 {E(f;D)=\frac{1}{m} \sum_{i=1}^{m}(f(x_i)-y_i)^2} E(f;D)=m1i=1m(f(xi)yi)2

拓展一些分类任务中常用的性能度量,以后再来作详细补充。
错误率与精度;查全率、查准率与 F 1 {F_1} F1值; R O C {ROC} ROC A U C {AUC} AUC;代价敏感错误率与代价曲线等。

6、sklearn参数详解(示例)

在scikit-learn里,LinearRegression类实现了线性回归算法。我们这一节使用scikit-learn自带地波士顿房价数据集来训练模型,然后用模型来测算房价。
在sklearn的波士顿房价数据集里,总共收集了13个特征,具体如下:

  • CRIM:城镇人均犯罪率
  • ZN:城镇超过25,000平方英尺的住宅区域的占地比例
  • INDUS:城镇非零售用地占地比例
  • CHAS:是否靠近河边,1为靠近,0为远离
  • NOX:一氧化氮浓度
  • RM:每套房产的平均房间个数
  • AGE:在1940年之前就盖好,且业主自住的房子的比例
  • DIS:与波士顿市中心的距离
  • RAD:周边高速公路的便利性指数
  • TAX:每10,000美元的财产税率
  • PTRATIO:小学老师的比例
  • B:城镇黑人的比例
  • LSTAT:地位较低的人口比例
    这些指标中可以看出中美文化的一些差异。当然,这个数据是在1993年之前收集的,可能和现在会有差异。实际上一个模型的好坏和输入特征的选择是关系密切的。开一下脑洞,如果在中国预测房价,应该收集哪些特征数据?收集成本有多高?特征数据的可获得性怎么样?
    废话不多说,开始撸代码。
  • 我们导入数据
from sklearn.datasets import load_boston

boston = load_boston() #加载数据集
X, y = boston.data, boston.target # 获得数据集X和标签(真实值)y
print(X.shape) # 看一下数据集的形状,其输出为(506,13),表明这个数据集有506个样本,每个样本有13个特征。
print(y.shape)

"""
整个训练样本放在一个506 * 13的矩阵里。可以通过X[0]来看一个样本数据:

"""
print(X[0])

"""输出:
[6.320e-03 1.800e+01 2.310e+00 0.000e+00 5.380e-01 6.575e+00 6.520e+01
 4.090e+00 1.000e+00 2.960e+02 1.530e+01 3.969e+02 4.980e+00]
"""

boston.feature_names # 查看这些特征的标签
"""
array(['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD',
       'TAX', 'PTRATIO', 'B', 'LSTAT'], dtype='<U7')
"""
  • 模型训练
# 在对模型进行训练之前,我们需要先把数据集分成两份,以便评估算法的准确性。

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=3)

"""
由于数据集较小,我们只选取了20%(参数test_size)的样本作为测试集。
接着,训练模型并测试模型的准确性评分。
"""
import time
from sklearn.linear_model import LinearRegression

model = LinearRegression()
start = time.clock()
model.fit(X_train, y_train)

train_score = model.score(X_train, y_train)
cv_score = model.score(X_test, y_test)
print("elaspe: {0:.6f}; train_score: {1:0.6f}; cv_score: {2:.6f}".format(time.clock()-start, train_score, cv_score))

"""输出:
elaspe: 0.063014; train_score: 0.723941; cv_score: 0.794958

我们顺便统计了模型的训练时间,除此之外,统计模型针对训练样本的准确性得分(即对训练样本拟合的好坏程度)train_score,
还统计了模型针对测试样本的得分cv_score

从得分情况来看,模型的拟合效果一般,还有没有办法来优化模型的拟合效果呢?
"""
  • 模型优化
"""
首先观察一下数据,特征数据的范围相差比较大,最小的在10的13次方级别,而最大的在10的2次方级别,看来我们需要先把数据进行归一化处理。
归一化处理最简单的方式是,创建线性回归模型的时候增加normalize=True参数。
model = LinearRegression(normalize=True)

当然,数据归一化处理只会加快算法收敛速度,优化算法训练的效率,无法提升算法的准确性。
怎么样优化模型准确性呢?我们回到训练分数上来,可以观察到数据针对训练样本的评分较低(train_score: 0.723941),
即模型对训练数据的拟合成本(损失,或者误差)比较高,这是典型的欠拟合现象。大家可以往上翻一下如何处理欠拟合的办法:
一是挖掘更多的输入特征,二是增加多项式特征。这里我们使用低成本的方案,即增加多项式特征来看看能否优化模型的性能。
增加多项式特征,其实就是增加模型的复杂度。

下面我们写一个创建多项式模型的函数
"""
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline

def polynomial_model(degree=1):
    polynomial_features = PolynomialFeatures(degree = degree,
                                             include_bias = False)
    linear_regression = LinearRegression(normalize = True)
    pipeline = Pipeline([("polynomial_features", polynomial_features), ("linear_regression", linear_regression)])
    return pipeline
"""
接着,我们使用二阶多项式来拟合数据。
"""
model = polynomial_model(degree=2)  # 二阶多项式

start = time.clock()
model.fit(X_train, y_train)

train_score = model.score(X_train, y_train)
cv_score = model.score(X_test, y_test)
print("elaspe: {0:.6f}; train_score: {1:0.6f}; cv_score: {2:.6f}".format(time.clock()-start, train_score, cv_score))

"""输出
elaspe: 0.049655; train_score: 0.930547; cv_score: 0.860465

可以看到,训练样本分数和测试分数都提高了,看来模型确实得到了优化。我们还可以把多项式改成三阶看一下结果。
其实改为三阶后,针对训练样本的分数达到了1,而针对测试样本的分数却为负数,说明这个模型过拟合了。
"""

==============================================================

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值