用 scikit-learn 和 pandas 学习线性回归
用 scikit-learn 和 pandas 学习线性回归¶
from https://www.cnblogs.com/pinard/p/6016029.html
就算是简单的算法,也需要跑通整个流程,通过一个简单的回归的例子,可以看到: 数据的准备 ,数据的维度? 用哪个模型,如何训练,如何评价,可视化? 有一系列的东西需要去落地,推导理解十一方面,同时也要会用。 就这个回归的例子,和之前的 GMM 的例子很像,整个一套流程的东西很像,但是这里我们是用 sklearn 这个框架来完成的。
这里我们用 UCI 大学公开的机器学习数据来跑线性回归。
数据的介绍在这: http://archive.ics.uci.edu/ml/datasets/Combined+Cycle+Power+Plant
数据的下载地址在这: http://archive.ics.uci.edu/ml/machine-learning-databases/00294/
里面是一个循环发电场的数据,共有 9568 个样本数据,每个数据有 5 列,分别是: AT(温度), V(压力), AP(湿度), RH(压强), PE(输出电力)。我们不用纠结于每项具体的意思。
我们的问题是得到一个线性的关系,对应 PE 是样本输出,而 AT/V/AP/RH 这 4 个是样本特征, 机器学习的目的就是得到一个线性回归模型,即:
PE=θ0+θ1∗AT+θ2∗V+θ3∗AP+θ4∗RHPE=θ0+θ1∗AT+θ2∗V+θ3∗AP+θ4∗RH
而需要学习的,就是θ0,θ1,θ2,θ3,θ4θ0,θ1,θ2,θ3,θ4 这 5 个参数。
下载后的数据可以发现是一个压缩文件,解压后可以看到里面有一个 xlsx 文件,我们先用 excel 把它打开,接着 “另存为 “”csv 格式,保存下来,后面我们就用这个 csv 来运行线性回归。
打开这个 csv 可以发现数据已经整理好,没有非法数据,因此不需要做预处理。但是这些数据并没有归一化,也就是转化为均值 0,方差 1 的格式。也不用我们搞,后面 scikit-learn 在线性回归时会先帮我们把归一化搞定。
好了,有了这个 csv 格式的数据,我们就可以大干一场了。
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import pandas as pd
from sklearn import datasets, linear_model
用 pandas 来读取数据¶
data = pd.read_csv('Folds5x2_pp.csv')
data.head()
y = data[['PE']]
print(type(y))
y.head()
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
print(X_train.shape,y_train.shape,X_test.shape,y_test.shape,type(X_train))
运行 scikit-learn 的线性模型¶
终于到了临门一脚了,我们可以用scikit-learn的线性模型来拟合我们的问题了。scikit-learn的线性回归算法使用的是最小二乘法来实现的。代码如下:
from sklearn.linear_model import LinearRegression
linreg = LinearRegression()
linreg.fit(X_train, y_train)
print(linreg.intercept_) #在线性模型的属性里。
print(linreg.coef_)
也就是说 PE 和其他 4 个变量的关系如下:
PE=447.06297099−1.97376045∗AT−0.23229086∗V+0.0693515∗AP−0.15806957∗RH
模型评价¶
我们需要评估我们的模型的好坏程度,对于线性回归来说,我们一般用均方差(Mean Squared Error, MSE)或者均方根差 (Root Mean Squared Error, RMSE) 在测试集上的表现来评价模型的好坏。
我们看看我们的模型的 MSE 和 RMSE,代码如下:
#模型拟合测试集
y_pred = linreg.predict(X_test)
from sklearn import metrics
# 用scikit-learn计算MSE
print("MSE:",metrics.mean_squared_error(y_test, y_pred))
# 用scikit-learn计算RMSE
print("RMSE:",np.sqrt(metrics.mean_squared_error(y_test, y_pred)))
得到了 MSE 或者 RMSE,如果我们用其他方法得到了不同的系数,需要选择模型时,就用 MSE 小的时候对应的参数。
比如这次我们用 AT, V,AP 这 3 个列作为样本特征。不要 RH, 输出仍然是 PE。代码如下:
X = data[['AT', 'V', 'AP']]
y = data[['PE']]
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
from sklearn.linear_model import LinearRegression
linreg = LinearRegression()
linreg.fit(X_train, y_train)
#模型拟合测试集
y_pred = linreg.predict(X_test)
from sklearn import metrics
# 用scikit-learn计算MSE
print("MSE:",metrics.mean_squared_error(y_test, y_pred))
# 用scikit-learn计算RMSE
print("RMSE:",np.sqrt(metrics.mean_squared_error(y_test, y_pred)))
可以看出,去掉RH后,模型拟合的没有加上RH的好,MSE变大了。
交叉验证¶
我们可以通过交叉验证来持续优化模型,代码如下,我们采用10折交叉验证,即cross_val_predict中的cv参数为10:
X = data[['AT', 'V', 'AP', 'RH']]
y = data[['PE']]
from sklearn.model_selection import cross_val_predict
predicted = cross_val_predict(linreg, X, y, cv=10)
# 用scikit-learn计算MSE
print("MSE:",metrics.mean_squared_error(y, predicted))
# 用scikit-learn计算RMSE
print("RMSE:",np.sqrt(metrics.mean_squared_error(y, predicted)))
可以看出,采用交叉验证模型的 MSE 比第 6 节的大,主要原因是我们这里是对所有折的样本做测试集对应的预测值的 MSE,而第 6 节仅仅对 25% 的测试集做了 MSE。两者的先决条件并不同。
疑惑解答:¶
2018-01-04 14:10 小北潜行
你好~ 真的非常感谢你的文章。理论和实际使用相结合,好理解很多~~
有个问题,就是不太明白 8. 交叉验证这一部分的作用
上文中 8 使用的数据集和前面计算均方差的数据集不一样,所以得到的数值不一样
但是如果使用相同的数据集,那和前面计算出来的数值没有差异
那这部分的作用体现在哪里呢?
[楼主] 2018-01-05 10:52 刘建平 Pinard
@ 小北潜行
你好,这是一个简单的例子,主要是说均方差可以用来衡量模型的好坏,可以怎么用,一般在交叉验证的时候不用看 MSE。
什么时候用 MSE 呢?在做模型测试的时候。
针对训练集和测试集,第一次选择合适参数 (比如优化方法,正则化参数等),训练集交叉验证出来的模型 A,来预测测试集,可以计算 MSE-A,第二次选择合适参数,训练集交叉验证出来的模型 B,来预测测试集,可以计算 MSE-B,通过 MSE-A 和 MSE-B 的大小,可以衡量模型 A 和 B 的好坏。
2018-03-18 18:50 TinyLaughing
博主,您好!
对于第 8 节的 10 折交叉验证有点不明白。
我的理解是 10 折交叉验证,得到了 10 个不同的模型,每一个模型有各自的系数、截距以及 MSE。(这样理解不知道对不对?)
那么,博主文中计算的 MSE 是 10 个模型的 MSE 的平均值,还是 10 个模型中最优模型的 MSE(即 10 个 MSE 的最小值)?
[楼主] 2018-03-25 18:51 刘建平 Pinard
@ TinyLaughing
你好,就是 10 个模型中最优模型的 MSE(即 10 个 MSE 的最小值)。
因为交叉验证的目的是找到最好的模型参数,而如何评判呢?对于这个例子就看这 10 折交叉验证中哪一次的 MSE 最好,那么对应的模型参数我们认为是最优的。
至于大家都很关心的,如何求出交叉验证的 参数和截距:¶
对于你说的需求,直接使用 skearn 单个 API 是无法得到的。 可行的做法是: 1)用 sklearn.model_selection.KFold 将数据分成 K 折。 2) 自己做一个循环(共 K 次),每次合并其中的 K-1 折的数据做训练集,另 1 折做测试集,按第 6 节的方法训练,打印模型参数和 MSE。 3)选择最小 MSE 对应的模型参数。
画图观察结果¶
这里画图真实值和预测值的变化关系,离中间的直线 y=x 直接越近的点代表预测损失越低。代码如下:
fig, ax = plt.subplots()
ax.scatter(y, predicted)
ax.plot([y.min(), y.max()], [y.min(), y.max()], 'k--', lw=4) #lw表示线宽
ax.set_xlabel('Measured')
ax.set_ylabel('Predicted')
plt.show()