通过第2章的学习,想必读者已经对一元线性回归有了深刻的理解。一元线性回归推广到多个特征即为多元线性回归模型,它在许多实际问题中亦有广泛运用,本节将以一个案例为基础,讲解使用多元性回归模型的一般步骤和Python实现。
已知Boston城市的4个地段以及每个地段的各项数据如表3.3所示
。
表3.3 Boston房价(部分数据)
要求依照给定数据训练一个模型,然后根据每个地段的各项数据,使用该模型预测该地段的平均房价。
根据我们的生活经验,可以猜测房价与这些特征(各项数据)之间存在线性关系:
其中,
x
=(1,
x
犯罪率
,
x
ZN比例
,…,
x
贫困人口比例
)
T
,
。1与
ω
0
表示截距项,
y
为价格的预测值,式(3.1)即为多元线性回归模型。
最理想的参数 ω 应使风险函数最小:
其中, m 为训练集的个体数,根据2.1.2节的介绍,用矩阵的形式可以表示为:
在式(3.3)中对 ω 求偏导并令其为0的方式解出 ω :
解出模型的参数之后,根据式(2.6)、式(2.7)和式(2.9)就可以计算出模型在训练集、测试集中的评价指标了,由此决定是否采纳该模型。
通过3.3.1节中的案例介绍,想必读者对多元线性回归有了深刻的理解。本节归纳出多元线性回归的一般步骤如下:
问题提出:根据多特征的输入
预测数值连续型随机变量
y
。
假设模型:假设输入与输出之间存在线性关系,提出模型
。
模型训练:提出一个风险函数
c
(
ω
),可以是最小二乘、极大似然或最小描述,然后将参数求解问题转化为优化问题,从而求解出参数
ω
。
评价模型:使用
R
方、MSE或者调整
R
方等评价指标,分别计算模型在训练集和测试集中的拟合优度。
仍旧以3.3.1节的案例为例,由于Python的Sklearn模块自带Boston数据集,所以可以通过sklearn.datasets模块的load_boston函数直接导入数据集。为了进行模型评价,需要将数据集按比例拆分成训练集和测试集。拆分数据集可以通过sklearn.model_selection模块的train_test_split函数实现,设置参数test_size的值来调整拆分比例。这里令test_size=0.3,即将数据按7∶3的比例进行拆分。
然后实例化一个sklearn.linear_model模块的LinearRegression类,再通过实例对象的.fit()接口对模型进行训练,代码如下(代码文件为linear_regression.py
)。
运行上述代码,得出多元线性回归模型的表达式如下:
y =46.42−0.097 x 1 +0.061 x 2 +0.060 x 3 +…−0.060 x 13
Tips: 初学编程的读者在阅读时可能会感到疑惑,什么是类、实例、对象和接口呢?在面向对象的编程中,通常将许多变量(称为属性)和函数(称为接口)封装在一个类中。类是一个抽象的概念,一般情况下需要实例化一个对象方可使用。打个比方,类与对象就如鱼是一个种类,而水里的鱼是实实在在的一个个体一样。前者为类,后者为对象。而调用对象中封装好的函数,即接口,就可以修改对象中的属性。通常,许多属性都是封装的和不可见的,使用者也无须知道它们的存在。通过将代码封装成一个类,再通过实例化对象使用这个类。这样可以避免重复编程,使编程更简洁,此即为面向对象的编程方法。
得到模型后,需要在训练集和测试集中查看模型的拟合优度,以审核模型的效果。这里分别计算模型在训练集、测试集中的 R 方和MSE,计算方法如2.1.3节所述。在Python中,可以通过sklearn.metrics模块的r2_score、mean_squared_error函数计算模型的 R 方和MSE,代码如下(接上段代码)。
为了直观地评估模型的效果,可以画出
与个体构成的曲线,也可以以预测值为
x
轴,以实际值为
y
轴画出所有个体,如图3.15所示,画图的实现代码如下。
运行上述代码,可以算出模型在训练集中的 R 方和MSE分别为0.710和23.513;模型在测试集中的 R 方和MSE分别为0.784和19.830。输出图像如图3.15所示。
图3.15 可视化拟合优度(测试集)
从图3.15左图中可以看出实际数据与拟合数据的走向基本一致。从右图中可以看出,实际值与预测值都集中在对角线上,可见数据的偏差不大。在回归任务中,画出形如图3.15所示的图是一种常见的可视化方法,通过这类图像可以大致判断拟合的效果,有时候还可以发现一些数字指标看不到的信息。
Tips: Matplotlib是Python中一个常用的画图模块,读者可以根据3.1.2节介绍的方法,使用pip install命令来安装该模块。如果使用Anaconda一站式安装Python和IDE,那么在安装过程中已经将Matplotlib模块安装好了,只需要直接用import方法导入对应的库就可以使用了。另外,就如上面代码展示的一样,可以通过subplot函数画出多幅图像。
2.4.2节曾提过拟合的问题。所谓过拟合,是指模型在训练集中表现优异,而在测试集中其拟合效果就差强人意了。为了减少过拟合的程度,其中一种有效的方法是对模型进行正则化,正则化是指在风险函数中加入正则项。以线性回归为例,可将式(3.2)的风险函数改写为:
其中,
为
l
2范数,
,
n
为特征个数。同样对
ω
求导并令其为0,可得:
其中,
α
为正则化系数、
为补偿项,风险函数包含该项的线性回归,也称为Ridge回归。
由于风险函数中包含补偿项,使得参数
ω
无法无限地往最优值靠拢,所以可以防止模型过度拟合训练集。另外,正则化可以解释为“牺牲”一定的精确度来降低预测值
的方差。方差反映一组数据的波动水平,方差降低意味着
的波动不大,这样就加强了模型对陌生数据的处理能力。但相对的,MSE可能会增大。物极必反,如果正则化系数
α
设置得非常大,那么(
ω
T
x
i
−
y
i
)
2
项的作用就会降低,导致方差接近0,从而使误差非常大,模型欠拟合。
更深一层的解释是,对于式(3.4)而言,如果输入的各个特征
x
i
存在线性关系,那么
X
T
X
很有可能是病态矩阵,即行列式
。于是它的逆或者说伪逆将会对数值的波动十分敏感。表现为
X
变化很小,而得出的
ω
千差万别。但加入正则项后,总可以找到一个
α
,使得
,
X
T
X
−
α
I
为一个可逆、非奇异的矩阵,从而使
ω
m
对
X
的变化就相对不敏感了。
正则化的数学解释相对复杂,在此读者先了解其简单的工作原理即可,详细的数学解释将会在后续章节中展开。在此读者应着重学习Ridge回归的Python实现方法,仍旧以3.3.1节为例,设置正则化系数 a =0.5,用Boston数据集训练Ridge回归模型,并计算模型在训练集和测试集中的 R 方与MSE。
在Python中,可以用sklearn.linear_model模块的Ridge类实现Ridge回归,并通过设置类的初始化参数alpha来调整正则化系数 α 的值,代码如下。
运行以上代码,可得模型在训练集中的 R 方和MSE分别为0.709和23.658,模型在测试集中的 R 方和MSE为0.788和19.426。
对比普通的线性回归可以看出,模型在训练集中的 R 方有所降低,而测试集中的 R 方有所提高,这其实是Ridge正则化导致模型泛化能力增强的结果。
Tips: 对象的某些属性可以在初始化类时就进行赋值。在Python面向对象实现中,一般通过__init__函数实现对象属性初始化赋值。就如上述代码中的rdg对象,其属性alpha就是通过初始化赋值的。当然,这些是Ridge类的底层代码,读者大可不管。如果读者感兴趣想观察它们的实现,可以直接在各IDE中打开其源码。本书主要介绍机器学习的相关内容,因此很多概念为了方便读者理解,使用了容易理解的词,如使用“参数”“函数”来描述一些“属性”“接口”之类的名词。
还有一个问题,如何选取正则化系数 α 的值呢?遗憾的是, α 的选取至今未存在标准的方法。只能通过遍历 α 的所有取值,再结合实际拟合优度来选择(如第5章中将会介绍的交叉验证法和网格寻优法)。