用 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 格式的数据,我们就可以大干一场了。

In [1]:
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import pandas as pd
from sklearn import datasets, linear_model
 

用 pandas 来读取数据

In [2]:
data = pd.read_csv('Folds5x2_pp.csv')
data.head()
Out[2]:
 
 ATVAPRHPE
0 8.34 40.77 1010.84 90.01 480.48
1 23.64 58.49 1011.40 74.20 445.75
2 29.74 56.90 1007.15 41.91 438.76
3 19.07 49.69 1007.22 76.79 453.09
4 11.80 40.66 1017.13 97.20 464.43
 

准备运行算法的数据

In [3]:
data.shape
Out[3]:
(9568, 5)
In [4]:
X = data[['AT', 'V', 'AP', 'RH']]
X.head()
Out[4]:
 
 ATVAPRH
0 8.34 40.77 1010.84 90.01
1 23.64 58.49 1011.40 74.20
2 29.74 56.90 1007.15 41.91
3 19.07 49.69 1007.22 76.79
4 11.80 40.66 1017.13 97.20
In [16]:
y = data[['PE']]
print(type(y))
y.head()
 
<class 'pandas.core.frame.DataFrame'>
Out[16]:
 
 PE
0 480.48
1 445.75
2 438.76
3 453.09
4 464.43
 

划分训练集和测试集

我们把 X 和 y 的样本组合划分成两部分,一部分是训练集,一部分是测试集,代码如下:

可以看到75%的样本数据被作为训练集,25%的样本被作为测试集。

In [30]:
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))
 
(7176, 4) (7176, 1) (2392, 4) (2392, 1) <class 'pandas.core.frame.DataFrame'>
 

运行 scikit-learn 的线性模型

终于到了临门一脚了,我们可以用scikit-learn的线性模型来拟合我们的问题了。scikit-learn的线性回归算法使用的是最小二乘法来实现的。代码如下:

In [31]:
from sklearn.linear_model import LinearRegression
linreg = LinearRegression()
linreg.fit(X_train, y_train)
print(linreg.intercept_)     #在线性模型的属性里。
print(linreg.coef_)
 
[447.06297099]
[[-1.97376045 -0.23229086  0.0693515  -0.15806957]]
 

也就是说 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,代码如下:

In [11]:
#模型拟合测试集
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: 20.080401202073904
RMSE: 4.481116066570236
 

得到了 MSE 或者 RMSE,如果我们用其他方法得到了不同的系数,需要选择模型时,就用 MSE 小的时候对应的参数。

    比如这次我们用 AT, V,AP 这 3 个列作为样本特征。不要 RH, 输出仍然是 PE。代码如下:

In [12]:
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)))
 
MSE: 23.208907470136236
RMSE: 4.817562399194871
 

可以看出,去掉RH后,模型拟合的没有加上RH的好,MSE变大了。

 

交叉验证

我们可以通过交叉验证来持续优化模型,代码如下,我们采用10折交叉验证,即cross_val_predict中的cv参数为10:

In [18]:
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: 20.7955974619431
RMSE: 4.560219014690314
 

可以看出,采用交叉验证模型的 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 直接越近的点代表预测损失越低。代码如下:

In [27]:
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()
 
posted @ 2018-08-31 12:00  dahu1  Views(1207)  Comments(0Edit  收藏  举报