用Python的Scikit-Learn库实现线性回归

xiaoxixi 2019-04-23

回归和分类是两种监督机器学习算法,前者预测连续值输出,而后者预测离散输出。例如,用美元预测房屋的价格是回归问题,而预测肿瘤是恶性的还是良性的则是分类问题。

在本文中,我们将简要研究线性回归是什么,以及如何使用Scikit-Learn(最流行的Python机器学习库之一)在两个变量和多个变量的情况下实现线性回归。

用Python的Scikit-Learn库实现线性回归

线性回归理论

代数学中,术语“线性”是指两个或多个变量之间的线性关系。如果在二维空间中绘制两个变量之间的关系,可以得到一条直线。

线性回归可以根据给定的自变量(x)预测因变量值(y),而这种回归技术可以确定x(输入)和y(输出)之间的线性关系,因此称之为线性回归。如果在x轴上绘制自变量(x),又在y轴上绘制因变量(y),线性回归给出了一条最符合数据点的直线,如下图所示。

得出线性方程大概是:

用Python的Scikit-Learn库实现线性回归

上述等式应为:Y= mx + b

其中b是截距,m是直线的斜率。线性回归算法大体上提供了截距和斜率的最优值。因为x和y是数据特征,因此这两个变量保持不变。可以控制的值是截距(b)和斜率(m)。根据截距和斜率的值,图上可以有多条直线。线性回归算法的可以找到符合数据点的多条线,并确认导致最小误差的其中一条线。

两个以上的变量的情况也适合使用线性回归,这可称为多元线性回归。比方说,假设这样一个场景,你必须根据房屋面积、卧室数量、住房人口的平均收入、屋龄等来预测房屋的价格。在这种情况下,因变量(目标变量)取决于几个不同的独立变量。而这种涉及多个变量的回归模型可表示为:

y = b0 + m1b1 +m2b2 + m3b3 + ... mnbn

这是超平面的等式。请牢记,二维线性回归模型是一条直线; 而三维线性回归模型则是一个平面,并且三维以上是超平面。

本节内容将介绍Python中用于机器学习的Scikit-Learn库如何实现回归函数。我们将从涉及两个变量的简单线性回归开始,然后逐步转向涉及多个变量的线性回归。

用Python的Scikit-Learn库实现线性回归

简单线性回归

用Python的Scikit-Learn库实现线性回归

线性回归

在查看第二次世界大战数据集中空中轰炸行动的记录时,我发现恶劣天气几乎要推迟当时的诺曼底登陆,下载了当时的天气报告,以便与轰炸行动数据集的任务进行比较。

该数据集包含世界各地气象站每天记录的天气状况信息,内容包括降水、降雪、气温和风速,同时也记录了当天是否出现雷暴或其他恶劣天气情况。

将这些输入特征值看成是最低温度,从而以预测最高温。

开始编码

导入所需的库:

import pandas as pd 
import numpy as np 
import matplotlib.pyplot as plt 
import seaborn as seabornInstance
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn import metrics
%matplotlib inline

以下命令使用pandas导入CSV数据集:

dataset =pd.read_csv('/Users/nageshsinghchauhan/Documents/projects/ML/ML_BLOG_LInearRegression/Weather.csv')

通过检查数据集内的行数和列数,大概对数据有了一点认识。

dataset.shape

如果输出值写着 (119040, 31),这意味着这个数据集含有119040行和31列。

可以使用describe()以查看数据集的统计详细信息:

dataset.describe()

用Python的Scikit-Learn库实现线性回归

数据集的统计视图

最后,在二维图上绘制我们的数据点并观察我们的数据集,看看是否可以使用以下脚本手动查找数据之间的关系:

dataset.plot(x='MinTemp', y='MaxTemp', style='o') 
plt.title('MinTemp vs MaxTemp') 
plt.xlabel('MinTemp') 
plt.ylabel('MaxTemp') 
plt.show()

我们采用了MinTemp和MaxTemp进行分析。下面是MinTemp和MaxTemp之间的二维图。

用Python的Scikit-Learn库实现线性回归

查找一下平均最高温度——二维图绘制完成后,可以观察到平均最高温度在25(摄氏度)和35(摄氏度)之间。

plt.figure(figsize=(15,10))
plt.tight_layout()
seabornInstance.distplot(dataset['MaxTemp'])

用Python的Scikit-Learn库实现线性回归

平均最高温在20到35之间

下一步,把这些数据分为“属性”和“标签”两类。

属性是自变量,而标签是因变量,其值有待预测。在我们的数据集中,我们只有两列数据。我们想根据记录的MinTemp来预测MaxTemp,因此属性集将包含存储在X变量中的“MinTemp”列,而标签则存储在y变量中的“MaxTemp”列。

X = dataset['MinTemp'].values.reshape(-1,1)
y = dataset['MaxTemp'].values.reshape(-1,1)

接下来,80%的数据将作为训练样本集,而另外的20%则用于测试以下编码。

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,random_state=0)

在将数据分成训练集和测试集后,便开始训练算法。为此,需要导入LinearRegression类,并将之实例化,并采用fit()方法已验证这些训练数据。

regressor = LinearRegression() 
regressor.fit(X_train, y_train) #training the algorithm

我们前面曾讨论过,线性回归模型可以大致找到截距和斜率的最佳值,从而确定最符合相关数据的线的位置。如要查看线性回归算法为我们的数据集计算的截距和斜率的值,请执行以下代码。

#To retrieve the intercept:
print(regressor.intercept_)
#For retrieving the slope:
print(regressor.coef_)

结果分别约为10.66185201与0.92033997。

这意味着——若最低温度发生变化,那么最高温度有0.92%的可能性也发生变化。

既然已经训练了这算法,现在是时候进行一些预测了。为需要测试数据,并检验算法预测百分比得分的准确程度。要对测试数据进行预测,请执行以下脚本:

y_pred = regressor.predict(X_test)

现在将X_test的实际输出值与预测值进行比较,请执行以下脚本:

df = pd.DataFrame({'Actual': y_test.flatten(), 'Predicted':y_pred.flatten()})
df

用Python的Scikit-Learn库实现线性回归

实际值与预测值的比较

还可以使用以下脚本,用条形图的方式展示这些比较:

注意:由于记录数量庞大,为了更好的展示效果,我们只使用了其中25条记录。

df1 = df.head(25)
df1.plot(kind='bar',figsize=(16,10))
plt.grid(which='major', linestyle='-', linewidth='0.5', color='green')
plt.grid(which='minor', linestyle=':', linewidth='0.5', color='black')
plt.show()

用Python的Scikit-Learn库实现线性回归

实际值与预测值比较的条形图

尽管这个模型不尽准确,但预测的百分比依然接近实际数值。

根据这些测试数据可以画出一条直线:

plt.scatter(X_test, y_test, color='gray')
plt.plot(X_test, y_pred, color='red', linewidth=2)
plt.show()

用Python的Scikit-Learn库实现线性回归

预测值和测试数据

图上直线显示我们的算法无误。

最后一步是评估算法的性能。此步骤对于比较不同算法在特定数据集上的实现情况尤为重要。对于回归算法,通常使用三种评估指标:

1.平均绝对误差(MAE)指的是误差绝对值的平均值。计算方法如下:

用Python的Scikit-Learn库实现线性回归

2.均方误差(MSE)是平方误差的平均值,计算公式如下:

用Python的Scikit-Learn库实现线性回归

3.均方根误差 (RMSE)为平方误差均值的平方根:

用Python的Scikit-Learn库实现线性回归

幸运的是,我们无需手动计算,Scikit-Learn库的预建功能可以计算这些值。

使用测试数据找到这些指标的值。

print('MeanAbsolute Error:', metrics.mean_absolute_error(y_test, y_pred)) 
print('MeanSquared Error:', metrics.mean_squared_error(y_test, y_pred)) 
print('RootMean Squared Error:', np.sqrt(metrics.mean_squared_error(y_test, y_pred))

你会得到这样的输出结果(结果可能略有不同):

('MeanAbsolute Error:', 3.19932917837853)
('MeanSquared Error:', 17.631568097568447)
('RootMean Squared Error:', 4.198996082109204)

由上可见,均方根误差的值是4.19,这个数值超过了所有温度百分比平均值的10%,即22.41。这意味着我们的算法不是很准确,但预测能力良好。

用Python的Scikit-Learn库实现线性回归

多元线性回归

用Python的Scikit-Learn库实现线性回归

来源

上面部分主要针对两个变量进行线性回归,但你遇到的所有实际问题中变量可不止两个。涉及多个变量的线性回归则称为“多元线性回归”。执行多元线性回归的步骤与简单线性回归的步骤相似。不同之处在于评估过程。利用多元线性回归可以找出哪个因素对预测输出的影响最大,以及不同变量之间的相互关系。

在本节中,我们下载了红葡萄酒质量数据集,该数据集与葡萄牙的“Vinho Verde”(绿酒)葡萄酒的红色变体有关。由于隐私和后勤问题,我们只掌握物理化学(输入)变量和感官(输出)变量的数据(例如,关于葡萄类型,葡萄酒品牌,葡萄酒销售价格等的数据暂缺)。

将考虑各种输入特征,如固定酸度,挥发性酸度,柠檬酸,残糖,氯化物,游离二氧化硫,总二氧化硫,密度,pH,硫酸盐,酒精。我们将利用这些特征来预测葡萄酒的质量。

开始编码

输入所需的库:

importpandas as pd 
importnumpy as np 
importmatplotlib.pyplot as plt 
importseaborn as seabornInstance
fromsklearn.model_selection import train_test_split
fromsklearn.linear_model import LinearRegression
fromsklearn import metrics
%matplotlibinline

以下指令将通过上面的链接从下载的文件中导入数据集:

dataset =pd.read_csv('/Users/nageshsinghchauhan/Documents/projects/ML/ML_BLOG_LInearRegression/winequality.csv')

通过检查数据集内的行数和列数,我们大概对以上数据有了一点认识。

dataset.shape

若输出值为(1599,12),则表明数据集中行数为1599,列数为12.

我们可以使用describe()以查看数据集的统计详细信息:

dataset.describe()

用Python的Scikit-Learn库实现线性回归

我们还需对数据进行筛选,首先查找哪些列含有NaN值:

dataset.isnull().any()

执行上面的代码后,所有列都会显示最后的结果False,如果有一列出现了True,则使用下面的代码从该列中删除所有空值。

dataset= dataset.fillna(method='ffill')

下一步是将数据划分为“属性”和“标签”。X变量包含所有属性/特征,y变量包含标签。

X = dataset[['fixed acidity', 'volatileacidity', 'citric acid', 'residual sugar', 'chlorides', 'free sulfur dioxide','total sulfur dioxide', 'density', 'pH', 'sulphates','alcohol']].values
y = dataset['quality'].values

计算“质量”一行的平均值。

plt.figure(figsize=(15,10))
plt.tight_layout()
seabornInstance.distplot(dataset['quality'])

用Python的Scikit-Learn库实现线性回归

葡萄酒质量的平均值

从上图可得,大部分葡萄酒的质量平均值为5或6。

接下来,80%的数据将作为训练样本集,而另外的20%则用于测试以下编码。

X_train,X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

现在开始测试模型。

regressor= LinearRegression() 
regressor.fit(X_train,y_train)

如前所述,在多变量线性回归中,回归模型必须找到所有属性的最佳系数。如要查看该回归模型选择了哪些系数,请执行以下脚本:

coeff_df= pd.DataFrame(regressor.coef_, X.columns, columns=['Coefficient']) 
coeff_df

最后的输出值大致如下:

用Python的Scikit-Learn库实现线性回归

这意味着,随着“密度”的单位增加,葡萄酒的质量减少了31.51个单位。同理,“氯化物”的单位的减少也会使得葡萄酒质量增加1.87个单位。同时我们还可以可以看到其余的特征对葡萄酒的质量影响很小。

现在对测试数据进行预测。

y_pred= regressor.predict(X_test)

检验实际值和预测值之间的差异。

df =pd.DataFrame({'Actual': y_test, 'Predicted': y_pred})
df1= df.head(25)

用Python的Scikit-Learn库实现线性回归

实际值与预测值的对比

对实际值和预测值之间对比进行描点:

df1.plot(kind='bar',figsize=(10,8))
plt.grid(which='major',linestyle='-', linewidth='0.5', color='green')
plt.grid(which='minor',linestyle=':', linewidth='0.5', color='black')
plt.show()

用Python的Scikit-Learn库实现线性回归

以上条形图可用于展示预测值和实际值之间的差异

可以看到,这个模型的预测结果比较准确。

最后一步是评估算法的性能。我们将通过计算MAE,MSE和RMSE的值来完成此操作。请执行以下脚本:

print('MeanAbsolute Error:', metrics.mean_absolute_error(y_test, y_pred))
print('MeanSquared Error:', metrics.mean_squared_error(y_test, y_pred))
print('RootMean Squared Error:', np.sqrt(metrics.mean_squared_error(y_test, y_pred)))

输出值为:

('MeanAbsolute Error:', 0.46963309286611077)
('MeanSquared Error:', 0.38447119782012446)
('RootMean Squared Error:', 0.6200574149384268)

可以看到,均方根误差值为0.62,略大于所有状态下的气体消耗平均值的10%,即5.63。这意味着算法还不够精准,但其预测能力依然让人认同。

导致这种不准确的有多种因素,如:

  • 数据量不足:需要大量数据才能获得最准确的预测。
  • 假设失误:假设这些数据具有线性关系,但实际可能并非如此。可以将数据可视化来确定结果。
  • 属性关联度低:参与计算的属性与我们的预测值关联度不大。

用Python的Scikit-Learn库实现线性回归

相关推荐