回归是一种应用广泛的预测建模技术,这种技术的核心在于预测的结果是连续型变量。
决策树,随机森林,支持向量机的分类器等分类算法的预测标签是分类变量,多以{0,1}来表示,而无监督学习算法比如PCA,KMeans的目标根本不是求解出标签,注意加以区别。
只要一切基于特征预测连续型变量的需求,我们都使用回归技术。
既然线性回归是源于统计分析,我们就可以用不同的角度去理解它。从统计学的角度来看,我们对线性回归有许多要求,比如残差要满足正态分布,要排除共线性等等;然而从机器学习的角度来说,无论服从什么分布,无论是否存在共线性,只要模型效果好就行。
回归需求在现实中非常多,所以我们自然也有各种各样的回归类算法。最著名的就是我们的线性回归和逻辑回归, 从他们衍生出了岭回归,Lasso,弹性网,除此之外,还有众多分类算法改进后的回归,比如回归树,随机森林的回归,支持向量回归,贝叶斯回归等等。除此之外,我们还有各种鲁棒的回归:比如RANSAC,Theil-Sen估计,胡贝尔回归等等。考虑到回归问题在现实中的泛用性,回归家族可以说是非常繁荣昌盛,家大业大了。
我们要明白各个回归算法的优劣,明白如何衡量回归算法的效果,然后了解什么时间该选用什么回归。
这里只讲普通的线性回归 Linear Regresion怎么用。
做一次线性回归 步骤:
1.导入需要的模块和库
2.导入数据,探索数据
3.分训练集与测试集
4.建模
5. 探索建好的模型(即看这个模型的各种属性)
1.导入需要的模块和库
from sklearn.linear_model import LinearRegression as LR
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
from sklearn.datasets import fetch_california_housing as fch
# 加利福尼亚房屋价值数据集
import pandas as pd
2.导入数据,探索数据
housevalue=fch()
x=pd.DataFrame(housevalue.data)
x.shape
(20640, 8)
y=housevalue.target
y.shape
(20640,)
housevalue.feature_names
['MedInc',
'HouseAge',
'AveRooms',
'AveBedrms',
'Population',
'AveOccup',
'Latitude',
'Longitude']
x
# 把列名替换成真正的属性名字
x.columns=housevalue.feature_names
其中
"""
MedInc:该街区住户的收入中位数
HouseAge:该街区房屋使用年代的中位数
AveRooms:该街区平均的房间数目
AveBedrms:该街区平均的卧室数目
Population:街区人口
AveOccup:平均入住率
Latitude:街区的纬度
Longitude:街区的经度
"""
3.分训练集与测试集
Xtrain,Xtest,Ytrain,Ytest=train_test_split(x,y,test_size=0.3,random_state=420)
Xtrain
# 索引是乱的,因为是随机抽取组成的训练集
恢复索引:
for i in [Xtrain,Xtest]:
i.index=range(i.shape[0])
Xtrain
4.建模
# 实例化+fit训练模型
reg=LR().fit(Xtrain,Ytrain)
# 调用predict接口,返回输入的测试集上的每个样本点的回归结果
yhat=reg.predict(Xtest)
# yhat为预测的结果。因为有8列,所以有8个预测值
yhat
5. 探索建好的模型(即看这个模型的各种属性)
线性回归有两个属性:coef_和intercept_
# coef_属性:coefficient,系数w
# 数字越大,越重要
# yhat有8列,所以有8个系数
reg.coef_
# zip:能将两个结构相似的对象结合在一起
zip(Xtrain.columns,reg.coef_)
# 这样写是会报错的,这是一个惰性对象,要显示惰性对象有两种方式:1.tolist,2,[*]
# 正确写法:
[*zip(Xtrain.columns,reg.coef_)]
# intercept_属性:截距
reg.intercept_
-36.256893229204074
多元线性回归的模型评估指标(看效果好不好)
回归类与分类型算法的模型评估其实是相似的法则——找真实标签和预测值的差异。
只不过在分类型算法中,这个差异只有一种角度来评判,那就是是否预测到了正确的分类;而在我们的回归类算法中,我们有两种不同的角度来看待回归的效果:
第一,我们是否预测到了正确的数值;
第二,我们是否拟合到了足够的信息。
这两种角度,分别对应着不同的模型评估指标。
第一,我们是否预测到了正确的数值:
用均方误差MSE(mean squared error)来衡量我们的预测值和真实值的差异。
在sklearn当中,我们有两种方式调用这个评估指标:
一种是使用sklearn专用的模型评估模块metrics里的类mean_squared_error;
另一种是调用交叉验证的类cross_val_score 并使用里面的scoring参数来设置使用均方误差。
第一种:使用sklearn专用的模型评估模块metrics里的类mean_squared_error
from sklearn.metrics import mean_squared_error as MSE
MSE(yhat,Ytest)
0.5309012639324571
第二种:调用交叉验证的类cross_val_score 并使用里面的scoring参数来设置使用均方误差
cross_val_score(reg,x,y,cv=10,scoring="neg_mean_squared_error").mean()
-0.550952429695659
可见,第二种算出来的均方误差是负的。
线性回归的大坑一号:均方误差为负。
这是因为sklearn在计算模型评估指标的时候,会考虑指标本身的性质,均方误差本身是一种误差,所以被sklearn划分为模型的一种损失(loss)。
在sklearn当中, 所有的损失都使用负数表示,因此均方误差也被显示为负数了。
真正的均方误差MSE的数值,其实就是 neg_mean_squared_error去掉负号的数字。
第二,我们是否拟合到了足够的信息:
对于回归类算法而言,只探索数据预测是否准确是不足够的。
除了数据本身的数值大小之外,我们还希望我们的模型能够捕捉到数据的”规律“,比如数据的分布规律,单调性等等,而是否捕获了这些信息并无法使用MSE来衡量。
在我们学习降维算法PCA的时候,我们提到我们使用方差来衡量数据上的信息量。如果方差越大,代表数据上的信息量越多,而这个信息量不仅包括了数值的大小,还包括了我们希望模型捕捉的那些规律。
为了衡量模型对数据上的信息量的捕捉,我们定义了R^2和可解释性方差分数EVS(explained_variance_score)。
两者都衡量 1 - 我们的模型没有捕获到的信息量占真实标签中所带的信息量的比例,所以,两者都是越接近1越好。
R^2我们可以使用三种方式来调用:
第一种是直接从metrics中导入r2_score,输入预测值和真实值后打分;
第二种是直接从线性回归LinearRegression的接口score来进行调用;
第三种是在交叉验证中,输入"r2"来调用。
EVS有两种调用方法:
第一种是从metrics中导入;
第二种是在交叉验证中输入”explained_variance“来调用。
调用R^2:
# 第一种 直接从metrics中导入r2_score:
from sklearn.metrics import r2_score
r2_score(yhat,Ytest)
0.3380653761555984
# 第二种 是直接从线性回归LinearRegression的接口score来进行调用:
r2=reg.score(Xtest,Ytest)
r2
0.6043668160178817
# 第三种 在交叉验证中,输入"r2"来调用
cross_val_score(reg,x,y,cv=10,scoring="r2").mean()
0.5110068610524556
为什么不同方式调用的R^2不同?
线性回归的大坑二号:相同的评估指标不同的结果。
答:因为在第一种方式(直接从metrics中导入r2_score)中,函数规定真实值在前,预测值在后,参数写反了。第三种我不知道。。。
# 更正后的第一种 直接从metrics中导入r2_score:
from sklearn.metrics import r2_score
r2_score(Ytest,yhat)
0.6043668160178817
# 第一种 抑或者可以自己制定参数,就不必在意顺序了:
r2_score(y_true=Ytest,y_pred=yhat)
0.6043668160178817
调用EVS:
# 第一种 从metrics中导入:
from sklearn.metrics import explained_variance_score as EVS
EVS(Ytest,yhat)
0.60461026738544
# 第二种 在交叉验证中输入”explained_variance“来调用:
cross_val_score(reg,x,y,cv=10,scoring="explained_variance").mean()
0.5384986901370838
我们观察到,虽然我们在加利福尼亚房子价值数据集上的MSE相当小,但我们的R^2却不高,这证明我们的模型比较好地拟合了数据的数值,却没有能正确拟合数据的分布。
让我们与绘图来看看,究竟是不是这样一回事。
我们可以绘制一张图上的两条曲线,一条曲线是我们的真实标签Ytest,另一条曲线是我们的预测结果yhat,两条曲线的交叠越多,我们的模型拟合就越好:
import matplotlib.pyplot as plt
# 让Ytest从小到大排序
sorted(Ytest)
plt.plot(range(len(Ytest)),sorted(Ytest),c="black",label="Data")
# plot(x轴=索引,y轴=数值,颜色,标签)
plt.plot(range(len(yhat)),sorted(yhat),c="red",label="Predict")
plt.legend()
plt.show()
可见,虽然我们的大部分数据被拟合得比较好,但是图像的开头和结尾处却又着较大的拟合误差。如果我们在图像右侧分布着更多的数据,我们的模型就会越来越偏离我们真正的标签。这种结果类似于我们前面提到的,虽然在有限的数据集上将数值预测正确了,但却没有正确拟合数据的分布,如果有更多的数据进入我们的模型,那数据标签 被预测错误的可能性是非常大的。
注意:
注意到,其实EVS和R^2是异曲同工的,两者都是衡量 1 - 没有捕获到的信息占总信息的比例,EVS和难道不应该相等吗?
但从我们的结果来看,两者虽然相似,但却并不完全相等,这中间的差值究竟是什么呢? 和EVS有什么不同?
线性回归的三号大坑:负的R^2。
我们的R^2显示为负的时候,这证明我们的模型对我们的数据的拟合非常糟糕,模型完全不能使用。 所以,一个负的R^2是合理的。
现实应用中,如果你发现你的线性回归模型出现了负的,不代表你就要接受他,首先检查你的建模过程和数据处理过程是否正确,也许你已经伤害了数据本身,也许你的建模过程是存在bug的。如果你检查了所有的代码,也确定了你的预处理没有问题,但你的 也还是负的,那这就证明,线性回归模型不适合你的数据,试试看其他的算法吧。