机器学习实战-线性回归

简单线性回归模型

01_Simple_Linear_Regression

数据集

每一行数据表示一个学生的学习时间考试分数
|Hours |Scores |
|——-|——-|
|2.5 |21 |
|5.1 |47 |
|3.2 |27 |
|8.5 |75 |
|3.5 |30 |
|1.5 |20 |
|9.2 |88 |
|5.5 |60 |
|8.3 |81 |
|2.7 |25 |
|7.7 |85 |
|5.9 |62 |
|4.5 |41 |
|3.3 |42 |
|1.1 |17 |
|8.9 |95 |
|2.5 |30 |
|1.9 |24 |
|6.1 |67 |
|7.4 |69 |
|2.7 |30 |
|4.8 |54 |
|3.8 |35 |
|6.9 |76 |
|7.8 |86 |

第 1 步:数据预处理

这里导入我们需要的库,值得注意的是,这里多了一个 matplotlib.pyplot, matplotlibpython 上的一个 2D 绘图库, matplotlib 下的模块 pyplot 是一个有命令样式的函数集合, matplotlib.pyplot 是为我们对结果进行图像化作准备的。

1
2
3
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

导入相关数据

1
dataset = pd.read_csv('studentscores.csv')

打印数据集,运行代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    Hours  Scores
0 2.5 21
1 5.1 47
2 3.2 27
3 8.5 75
4 3.5 30
5 1.5 20
6 9.2 88
7 5.5 60
8 8.3 81
9 2.7 25
10 7.7 85
11 5.9 62
12 4.5 41
13 3.3 42
14 1.1 17
15 8.9 95
16 2.5 30
17 1.9 24
18 6.1 67
19 7.4 69
20 2.7 30
21 4.8 54
22 3.8 35
23 6.9 76
24 7.8 86

切分数据为输入特征 X 与标签 Y

这里我们需要使用 pandasiloc(区分于 loc 根据 index 来索引, iloc 利用行号来索引)方法来对数据进行处理,第一个参数为行号,: 表示全部行,第二个参数 :1 表示截到第 1 列(也就是取第 0 列)

1
2
X = dataset.iloc[:, : 1].values
Y = dataset.iloc[:, 1].values

打印 XY 运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
X:
[[2.5]
[5.1]
[3.2]
[8.5]
[3.5]
[1.5]
[9.2]
[5.5]
[8.3]
[2.7]
[7.7]
[5.9]
[4.5]
[3.3]
[1.1]
[8.9]
[2.5]
[1.9]
[6.1]
[7.4]
[2.7]
[4.8]
[3.8]
[6.9]
[7.8]]
Y:
[21 47 27 75 30 20 88 60 81 25 85 62 41 42 17 95 30 24 67 69 30 54 35 76 86]

划分训练集与测试集

导入 sklearn 库的 cross_validation 类来对数据进行训练集、测试集划分

1
2
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=1/4, random_state=0)

第 2 步:训练集使用简单线性回归模型来训练

1
2
3
from sklearn.linear_model import LinearRegression
regressor = LinearRegression()
regressor = regressor.fit(X_train, Y_train)

sklearn 线性回归还有一种模型 SGDRegressor ,它可以完成线性回归的随机梯度下降,代码如下:

1
2
3
from sklearn.linear_model import SGDRegressor
sgd_reg = SGDRegressor(n_iter=50, penalty=None, eta0=0.1)
sgd_reg.fit(X_train, Y_train)

上面的参数说明如下:

  • n_iter:迭代轮数
  • penalty:正则化项,可选 none l2 l1 elasticnet
  • eta0:学习率 $\eta$

比较线性回归的不同梯度下降算法,如下表:
02_table

第 3 步:预测结果

1
Y_pred = regressor.predict(X_test)

第 4 步:可视化

训练集结果可视化

1
2
3
4
5
# 散点图
plt.scatter(X_train, Y_train, color='red')
# 线图
plt.plot(X_train, regressor.predict(X_train), color='blue')
plt.show()

运行结果如下图所示:
03_train

测试集结果可视化

1
2
3
4
5
# 散点图
plt.scatter(X_test, Y_test, color='red'
# 线图
plt.plot(X_test, Y_pred, color='blue')
plt.show()

测试集结果如下图所示:
04_test

多元线性回归

05_Multiple Linear Regression

数据集

R&D Spend Administration Marketing Spend State Profit
165349.2 136897.8 471784.1 New York 192261.83
162597.7 151377.59 443898.53 California 191792.06
153441.51 101145.55 407934.54 Florida 191050.39
144372.41 118671.85 383199.62 New York 182901.99
142107.34 91391.77 366168.42 Florida 166187.94
131876.9 99814.71 362861.36 New York 156991.12
134615.46 147198.87 127716.82 California 156122.51
130298.13 145530.06 323876.68 Florida 155752.6
120542.52 148718.95 311613.29 New York 152211.77
123334.88 108679.17 304981.62 California 149759.96
101913.08 110594.11 229160.95 Florida 146121.95
100671.96 91790.61 249744.55 California 144259.4
93863.75 127320.38 249839.44 Florida 141585.52
91992.39 135495.07 252664.93 California 134307.35
119943.24 156547.42 256512.92 Florida 132602.65
114523.61 122616.84 261776.23 New York 129917.04
78013.11 121597.55 264346.06 California 126992.93
94657.16 145077.58 282574.31 New York 125370.37
91749.16 114175.79 294919.57 Florida 124266.9
86419.7 153514.11 0 New York 122776.86
76253.86 113867.3 298664.47 California 118474.03
78389.47 153773.43 299737.29 New York 111313.02
73994.56 122782.75 303319.26 Florida 110352.25
67532.53 105751.03 304768.73 Florida 108733.99
77044.01 99281.34 140574.81 New York 108552.04
64664.71 139553.16 137962.62 California 107404.34
75328.87 144135.98 134050.07 Florida 105733.54
72107.6 127864.55 353183.81 New York 105008.31
66051.52 182645.56 118148.2 Florida 103282.38
65605.48 153032.06 107138.38 New York 101004.64
61994.48 115641.28 91131.24 Florida 99937.59
61136.38 152701.92 88218.23 New York 97483.56
63408.86 129219.61 46085.25 California 97427.84
55493.95 103057.49 214634.81 Florida 96778.92
46426.07 157693.92 210797.67 California 96712.8
46014.02 85047.44 205517.64 New York 96479.51
28663.76 127056.21 201126.82 Florida 90708.19
44069.95 51283.14 197029.42 California 89949.14
20229.59 65947.93 185265.1 New York 81229.06
38558.51 82982.09 174999.3 California 81005.76
28754.33 118546.05 172795.67 California 78239.91
27892.92 84710.77 164470.71 Florida 77798.83
23640.93 96189.63 148001.11 California 71498.49
15505.73 127382.3 35534.17 New York 69758.98
22177.74 154806.14 28334.72 California 65200.33
1000.23 124153.04 1903.93 New York 64926.08
1315.46 115816.21 297114.46 Florida 49490.75
0 135426.92 0 California 42559.73
542.05 51743.15 0 New York 35673.41
0 116983.8 45173.06 California 14681.4

第 1 步: 数据预处理

导入库

1
2
import pandas as pd
import numpy as np

导入数据集

1
2
3
dataset = pd.read_csv('50_Startups.csv')
X = dataset.iloc[:, : -1].values
Y = dataset.iloc[:, 4].values

通过 print(X[:10]) print(Y[:10]) 打印 XY10 行数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
X前10行数据
[[165349.2 136897.8 471784.1 'New York']
[162597.7 151377.59 443898.53 'California']
[153441.51 101145.55 407934.54 'Florida']
[144372.41 118671.85 383199.62 'New York']
[142107.34 91391.77 366168.42 'Florida']
[131876.9 99814.71 362861.36 'New York']
[134615.46 147198.87 127716.82 'California']
[130298.13 145530.06 323876.68 'Florida']
[120542.52 148718.95 311613.29 'New York']
[123334.88 108679.17 304981.62 'California']]
Y前10行数据
[192261.83 191792.06 191050.39 182901.99 166187.94 156991.12 156122.51
155752.6 152211.77 149759.96]

将类别数据数字化

1
2
3
4
5
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
labelencoder = LabelEncoder()
X[:, 3] = labelencoder.fit_transform(X[:, 3])
onehotencoder = OneHotEncoder(categorical_features=[3])
X = onehotencoder.fit_transform(X).toarray()

分别打印 labelencoderonehotencoder 处理后 X 的前 10 行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
labelencoder:
[[165349.2 136897.8 471784.1 2]
[162597.7 151377.59 443898.53 0]
[153441.51 101145.55 407934.54 1]
[144372.41 118671.85 383199.62 2]
[142107.34 91391.77 366168.42 1]
[131876.9 99814.71 362861.36 2]
[134615.46 147198.87 127716.82 0]
[130298.13 145530.06 323876.68 1]
[120542.52 148718.95 311613.29 2]
[123334.88 108679.17 304981.62 0]]
onehot:
[[0.0000000e+00 0.0000000e+00 1.0000000e+00 1.6534920e+05 1.3689780e+05
4.7178410e+05]
[1.0000000e+00 0.0000000e+00 0.0000000e+00 1.6259770e+05 1.5137759e+05
4.4389853e+05]
[0.0000000e+00 1.0000000e+00 0.0000000e+00 1.5344151e+05 1.0114555e+05
4.0793454e+05]
[0.0000000e+00 0.0000000e+00 1.0000000e+00 1.4437241e+05 1.1867185e+05
3.8319962e+05]
[0.0000000e+00 1.0000000e+00 0.0000000e+00 1.4210734e+05 9.1391770e+04
3.6616842e+05]
[0.0000000e+00 0.0000000e+00 1.0000000e+00 1.3187690e+05 9.9814710e+04
3.6286136e+05]
[1.0000000e+00 0.0000000e+00 0.0000000e+00 1.3461546e+05 1.4719887e+05
1.2771682e+05]
[0.0000000e+00 1.0000000e+00 0.0000000e+00 1.3029813e+05 1.4553006e+05
3.2387668e+05]
[0.0000000e+00 0.0000000e+00 1.0000000e+00 1.2054252e+05 1.4871895e+05
3.1161329e+05]
[1.0000000e+00 0.0000000e+00 0.0000000e+00 1.2333488e+05 1.0867917e+05
3.0498162e+05]]

躲避虚拟变量陷阱

在回归预测中我们需要所有的数据都是 numeric 的,但是会有一些非 numeric 的数据,比如国家,省,部门,性别。这时候我们需要设置虚拟变量(Dummy variable)。做法是将此变量中的每一个值,衍生成为新的变量,是设为 1,否设为 0。举个例子,“性别”这个变量,我们可以虚拟出“男”和”女”两虚拟变量,男性的话“男”值为 1,”女”值为 0;女性的话“男”值为 0,”女”值为 1

但是要注意,这时候虚拟变量陷阱就出现了。就拿性别来说,其实一个虚拟变量就够了,比如 1 的时候是“男”, 0 的时候是”非男”,即为女。如果设置两个虚拟变量“男”和“女”,语义上来说没有问题,可以理解,但是在回归预测中会多出一个变量,多出的这个变量将会对回归预测结果产生影响。一般来说,如果虚拟变量要比实际变量的种类少一个。

在多重线性回归中,变量不是越多越好,而是选择适合的变量。这样才会对结果准确预测。如果 category 类的特征都放进去,拟合的时候,所有权重的计算,都可以有两种方法实现,一种是提高某个 categoryw,一种是降低其他 categoryw,这两种效果是等效的,也就是发生了共线性,虚拟变量系数相加和为 1,出现 完全共线陷阱

1
X = X[:, 1:]

拆分数据集为训练集和测试集

1
2
from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.2, random_state=0)

第 2 步: 在训练集上训练多元线性回归模型

1
2
3
from sklearn.linear_model import LinearRegression
regressor = LinearRegression()
regressor.fit(X_train, Y_train)

第 3 步: 在测试集上预测结果

1
y_pred = regressor.predict(X_test)

打印预测结果:

1
2
3
4
y_pred:
[103015.20159795 132582.27760816 132447.73845175 71976.09851258
178537.48221056 116161.24230165 67851.69209676 98791.73374687
113969.43533013 167921.06569552]

多项式回归模型

多项式回归就是线性回归的特殊情况,我们依然使用线性回归的优化器,但是在训练数据之前,我们使用 Scikit-LearningPolynomialFeatures 类进行训练数据集的转换,让训练集中每个特征的平方(2 次多项式)作为新特征:

1
2
3
from sklearn.preprocessing import PolynomialFeatures
poly_features = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly_features.fit_transform(X) # X为训练数据

请注意,当存在多个特征时,多项式回归能够找出特征之间的关系(这是普通线性回归模型无法做到的)。 这是因为 LinearRegression 会自动添加当前阶数下特征的所有组合。例如,如果有两个特征 $a,b$,使用 3 阶(degree=3)的 LinearRegression 时,不仅有 $a^2,a^3,b^2$ 以及 $b^3$,同时也会有它们的其他组合项 $ab,a^2b,ab^2$ 。

PolynomialFeatures(degree=d) 把一个包含 $n$ 个特征的数组转换为一个包含 $\frac{(n+d)!}{d!n!}$ 特征的数组,$n!$ 表示 n 的阶乘,等于 $1 2 3 \cdots * n$ 。小心大量特征的组合爆炸!

线性模型的正则化

岭(Ridge)回归

第一种写法

1
2
3
from sklearn.linear_model import Ridge
ridge_reg = Ridge(alpha=1, solver="cholesky")
ridge_reg.fit(X, y)

第二种写法

1
2
3
from sklearn.linear_model import SGDRegressor
sgd_reg = SGDRegressor(penalty="l2")
sgd_reg.fit(X, y.ravel())

Lasso 回归

第一种写法

1
2
3
from sklearn.linear_model import Lasso
lasso_reg = Lasso(alpha=0.1)
lasso_reg.fit(X, y)

第二种写法

1
2
3
from sklearn.linear_model import SGDRegressor
sgd_reg = SGDRegressor(penalty="l1")
sgd_reg.fit(X, y)

弹性网络 ElasticNet

1
2
3
from sklearn.linear_model import ElasticNet
elastic_net = ElasticNet(alpha=0.1, l1_ratio=0.5)
elastic_net.fit(X, y)

参考链接

机器学习100天

坚持原创技术分享,您的支持将鼓励我继续创作!