机器学习实战:线性回归模型

1,107 阅读6分钟

公众号:尤而小屋
作者:Peter
编辑:Peter

大家好,我是Peter~

今天带来的是机器学习的一篇实战文章:利用机器学习库scikit-learn实战线性回归模型。

机器学习实战—线性回归

在理想的状态下,任何非线性的东西都是可以通过线性的东西来拟合的(参考泰勒公式)。而且线性模型本质上是均值预测,而大部分事物的变化都只是围绕着均值来波动(参考大数定理),所以线性模型能够模拟绝大部分的现象。

网络图

文章目录

基本形式

基本表达

假设x是由d个属性来描述:x=x1,x2,......,xdx={x_1,x_2,......,x_d};其中xix_i表示第i个属性上的取值。线性模型是通过各个属性之间的组合来得到一个进行预测的函数,可表示为:

f(x)=w1x1+w2x2+...+wdxd+bf(x) = w_1x_1+ w_2x_2 + ... + w_dx_d + b

如果用向量表示为:

f(x)=wTx+bf(x) = w^Tx+b

其中w=(w1,w2,...,wd)w=(w_1,w_2,...,w_d)称之为权重,b称之为偏置


不同形式

不同尺度下的线性函数f(x):

  • f(x)取离散的值:线性多分类模型
  • f(x)取实数域上实值函数:线性回归模型
  • f(x)为对数:对数线性模式
  • f(x)进行sigmoid非线性变换:对数几率回归

本文中重点讲解的是线性回归问题,参考资料:《周志华-机器学习》和李航《统计学习方法》,还有datawhale的《南瓜书》公式部分。

线性回归

给定数据集D=(x1,y1),(x2,y2),...,(xm,ym),yiRD = {(x_1,y_1),(x_2,y_2),...,(x_m,y_m)},y_i \in R

线性回归linear regression试图学得一个线性模型,尽可能使得预测值f(x)f(x)和实际值yiy_i之间的差别最小

衡量方法

使用均方误差来衡量:找到合适的w和b,满足 min(w,b)i=1m(f(xi)yi)2\min _{(w,b)} \sum ^m _{i=1} (f(x_i) - y_i)^2

均方误差对应的就是常用的欧几里得距离(欧式距离)。基于均方误差最小化来进行模型求解的方法称之为:最小二乘法

在线性回归模型中,最小二乘法就是试图找到一条直线,使得所有样本到直线上的欧氏距离之和最小

参数求解

求解w和b使E(w,b)=i=1m(yiwxib)2 E(w,b)=\sum ^m _{i=1}(y_i-wx_i-b)^2达到最小,这个过程称之为最小二乘法的参数估计

E(w,b)对w和b单独求导的过程,具体推导过程参考:datawhalechina.github.io/pumpkin-boo…

令上面的两个求导出来的结果等于0,我们可以得到w和b的两个结果:

sklearn实战线性回归

我们通过网上的一个公开的数据集,来实现如何利用机器学习库sklearn进行线性回归学习线性回归问题。

  • 数据来源

  • 数据探索

  • 数据处理

  • 运行sklearn的线性模型

  • 模型评估

  • 模型优化

  • 可视化展示结果

数据来源

1、数据的介绍看这里: archive.ics.uci.edu/ml/datasets…

2、数据的下载地址请移步 archive.ics.uci.edu/ml/machine-…

数据中有4个字段属性用来描述发电厂的输出电力,最后一个是真实的输出电力值。

我们现在需要做的是利用线性回归模型找到4个因素对输出电力的影响,来预测后期的发电力。

数据探索

import pandas as pd
import numpy  as np
from sklearn import datasets, linear_model
from sklearn.linear_model import LinearRegression  # 导入线性回归模型

import matplotlib.pyplot as plt
%matplotlib inline 

1、读取数据

2、数据信息查看

3、数据统计信息查看

数据处理

1、选择需要的样本数据X,也就是前4个字段的信息

2、选择我们的样本输出标签数据y,也就是最后一个属性字段的数据

数据集划分

数据集的划分:一部分变成训练集,另一部分划分成测试集

from sklearn.model_selection import train_test_split  # 从模型选择模块中导入训练、测试集模块

X_train,X_test,y_train,y_test = train_test_split(X, y, random_state=1)

X_train   # 7176条数据训练数据

测试集的数据是2392条:

样本的输出值的行记录是和对应的X相同的;同时我们也发现:本次案例有75%的数据作为了训练集,25%作为了测试集

拟合实例化对象

line.fit(X_train,y_train)
LinearRegression()

查看我们模拟出来的系数:

print(line.intercept_)  # 相当于是d;类似于截距
print(line.coef_)   # 相当于是每个w的取值
[460.05727267]
[[-1.96865472 -0.2392946   0.0568509  -0.15861467]]

到这里,我们就已经模拟出来了线性回归的表达式:也就是PE和前面4个变量之间的关系式子:

PE=1.96865472AT0.2392946V+0.0568509AP0.15861467PH+460.05727267PE = -1.96865472*AT -0.2392946*V + 0.0568509*AP -0.15861467*PH + 460.05727267

模型评价

通过训练集的数据我们得到了线性回归的表达式,现在我们通过该表达式来模拟我们之前产生的测试集数据。

一个模型的评估,对于线性回归通常就是用上面我们介绍的均方差(Mean Squared Error, MSE)或者均方根差(Root Mean Squared Error, RMSE)在测试集上的表现来评价模型的好坏。下面通过代码来进行测试:

y_pred = line.predict(X_test)  # 对测试集数据进行预测

y_pred
array([[457.26722361],
       [466.70748375],
       [440.33763981],
       ...,
       [457.39596168],
       [429.37990249],
       [438.16837983]])
len(y_pred)
2392

预测到结果之后,我们将预测值和实际值进行比较:

from sklearn import metrics  # 对比模块
# 输出MSE

print("MSE:",metrics.mean_squared_error(y_test,y_pred)) 
MSE: 20.837191547220346
# 输出RMSE:MSE开根号的结果

print("RMSE: ",np.sqrt(metrics.mean_squared_error(y_test,y_pred)))
RMSE:  4.564777272465804

使用交叉验证优化模型

交叉验证法:将全部的数据样本D划分成k个大小相似的互斥子集。每个子集尽量保持数据分布的一致性。然后用用k-1个子集作为训练集,剩下的那个作为测试集。

这样就可以获取k组训练集/测试集,从而进行k次的训练和测试,最终返回k次训练的均值。

我们可以使用sklearn中自带的交叉验证方法来优化我们得到的模型,下面的例子中,采用的10折交叉验证:

line
LinearRegression()
from sklearn.model_selection import cross_val_predict  # 导入交叉验证模块

y_predicted = cross_val_predict(line,X,y,cv=10) 
y_predicted  # 通过交叉验证得到的预测值
array([[467.24487977],
       [444.06421837],
       [483.53893768],
       ...,
       [432.47556666],
       [443.07355843],
       [449.74395838]])
len(y_predicted)
9568

通过交叉验证得到的预测值predicted和真实值求MSE和RMSE:

# 输出MSE

print("MSE:",metrics.mean_squared_error(y,y_predicted)) 
MSE: 20.79367250985753
print("RMSE: ",np.sqrt(metrics.mean_squared_error(y,y_predicted)))
RMSE:  4.560007950635342

我们发现:通过使用交叉验证后的均方误差优于未使用情况下的误差

绘图

最后,我们画出真实的样本值和预测值之间的图形,当点距离中间y=x的值越近,说明预测损失越低。

下面是使用matplotlib绘图的代码和效果:

fig, ax = plt.subplots()

ax.scatter(y, y_predicted)

ax.plot([y.min(), y.max()], [y.min(), y.max()], 'k--', lw=3)

ax.set_xlabel('Measured')  # 真实值
ax.set_ylabel('Predicted') # 预测值

plt.show()

我把数据用Plotly_express重新绘制了一遍,看看效果:

data = pd.concat([pd.DataFrame(y),pd.DataFrame(y_predicted)],axis=1)
data.columns = ["Measured", "Predicted"]
data

import plotly_express as px

fig = px.scatter(data,
                 x="Measured",  # 真实值
                 y="Predicted",  # 预测值
                 trendline="ols",  # 趋势线
                 trendline_color_override="red" # 颜色
                )

fig.show()