导读:这篇笔记主要介绍线性回归算法,对在第一篇笔记中介绍过的线性回归算法进行实现。kNN算法主要解决的是分类问题,并且它的结果不具备良好的解释性。线性回归算法主要解决回归问题,它的结果具有良好的可解释性,和kNN算法的介绍过程一样,线性回归算法也蕴含了机器学习中很多重要的思想,并且它是许多强大的非线性模型的基础。
作者 | 计缘
线性回归算法的评测标准
在讲kNN算法时,我们分类问题的评测标准是基于将样本数据拆分为训练数据和测试数据的前提下的,那么在线性回归算法中也是一样的。我们使用训练数据计算出a
和b
的值,然后将测试数据代入拟合直线方程算出结果,进行比较。我们通过公式来看一下。
将训练数据代入公式算出a
和b
,然后代入拟合直线方程算出
此时我们的衡量标准既为:
也就是上面的公式值越小说明我们拟合的越好。
均方误差(MSE)
上面这个公式有一个问题,那就是最终值受
的影响,比如某个算法10个样本数据求出的值为80,另一个算法10000个样本数据求出的值为100,也不能表明第一个算法就比第二个算法好,因为样本数据量相差巨大,所以将上面公式改变一下,将值除以
这个衡量标准称为均方误差(MSE, Mean Squared Error)
均方根误差(RMSE)
在对量纲不敏感的情况下,使用均方误差没什么问题,但是在一些对量纲比较敏感的场景下,均方误差就会有问题,因为均方误差的量纲为XX平方,比如房屋面积售价的例子,均方误差的量纲就成了
元
平均绝对误差(MAE)
另外一个能统一量纲的衡量公式为平均绝对误差,既将真实值与预测值的差取绝对值而不是平方:
实现MSE, RMSE, MAE
实现这三个指标我们使用Scikit Learn中提供的波士顿房价的数据集,我们先使用简单线性回归进行预测:
import numpy as np
from sklearn import datasets
import matplotlib.pyplot as plt
boston = datasets.load_boston()
boston.feature_names
# 结果
array(['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD',
'TAX', 'PTRATIO', 'B', 'LSTAT'],
dtype='<U7')
# 波士顿房价数据提供了13个特征数据,因为是简单线性回归,所以我们只使用房间数量这个特征来预测房价
x = boston.data[:, 5]
# 将数据绘制回来
plt.scatter(x, y)
plt.show()
|
从图中我们可以看到在顶部有一些似乎到最大值的数据,这是因为在真实的数据中有一些类似50万以上这类数据,都会被归为数据集最大值一类,这些数据对我们的预测不但没有帮助,反而会有影响,所以我们将这些数据去掉:
x = x[y < 50]
y = y[y < 50]
# 导入我们封装好的简单线性回归对象和训练/测试数据拆分的对象
from myML.SimpleLinearRegression import SimpleLinearRegression
from myML.modelSelection import train_test_split
x_train, y_train, x_test, y_test = train_test_split(x, y, seed=666)
slr = SimpleLinearRegression()
slr.fit(x_train, y_train)
y_train_predict = slr.predict(x_train)
# 绘制出拟合直线
plt.scatter(x_train, y_train)
plt.plot(x_train, y_train_predict, color="r")
plt.show()
|
下面我们来计算MSE:
y_test_predict = slr.predict(x_test)
mse_test = np.sum((y_test - y_test_predict)**2) / len(y_test)
mse_test
# 结果
24.156602134387402
|
再来计算RMSE:
rmse_test = np.sqrt(mse_test)
rmse_test
# 结果
4.9149366358466313
|
再来看看MAE:
mae_test = np.sum(np.absolute(y_test - y_test_predict)) / len(y_test)
mae_test
# 结果
3.5430974409463842
|
从结果可以看出RMSE比MAE的值要大,那是因为RMSE是差值先平方然后求和然后再开方,所以如果有某个真实值和预测值之间差距比较大的时候,平方操作就会放大数据的量级。所以一般我们使用RMSE更有实际意义,因为RMSE的值小,说明了最大误差比较小。
封装MSE, RMSE, MAE
我们将这三个衡量指标封装起来,在metrics.py
文件中增加三个方法:
import numpy as np
def accuracy_score(y_true, y_predict):
assert y_true.shape[0] == y_predict.shape[0], \
"y_true 和 y_predict 数据的行数必须一致"
return np.sum(y_true == y_predict) / len(y_predict)
def mean_squared_error(y_true, y_predict):
assert len(y_true) == len(y_predict), "y_true与y_predict的数量必须一致"
return np.sum((y_true - y_predict)**2) / len(y_true)
def root_mean_squared_error(y_true, y_predict):
return np.sqrt(mean_squared_error(y_true, y_predict))
def mean_absolute_error(y_true, y_predict):
assert len(y_true) == len(y_predict), "y_true与y_predict的数量必须一致"
return np.sum(np.absolute(y_true - y_predict)) / len(y_true)
|
这样就可以在Jupyter Notebook中方便的使用了:
from myML.metrics import mean_squared_error
from myML.metrics import root_mean_squared_error
from myML.metrics import mean_absolute_error
mean_squared_error(y_test, y_test_predict)
# 结果
24.156602134387402
root_mean_squared_error(y_test, y_test_predict)
# 结果
4.9149366358466313
mean_absolute_error(y_test, y_test_predict)
# 结果
3.5430974409463842
|
R Squared
在之前的分类问题中,衡量标准的值都是在0/1之间,1表示最好,0表示最差,这个值和量纲无关。但是在线性回归问题中衡量标准的值是带有量纲的,比如某个算法在预测房价的场景中RMSE是5万,但在预测学生分数的场景中RMSE是10分,那么这个算法是在预测房价场景中好呢还是在预测学生分数场景中好呢?这个是无法判断的,这就是RMSE和MAE的局限性。那么为解决这个问题,就出现了一个新的衡量指标R Squared,也就是
。这个指标也是目前机器学习算法使用比较广泛的一个指标。我们先来看看
这个公式的分子其实就是简单线性回归的模型预测产生的错误,既Loss函数。分母中的 就无限接近于1,说明我们的模型拟合的非常好。如果比值接近1,说明我们的模型和均值模型没差多少,表明我们的模型比较烂,此时
就会接近0。那么综上,
我们对
的公式再处理一下,将1后面的分数分子分母各除以
此时,分子其实就是上文中讲到的MSE,而分母就是我们在第二篇笔记中讲过的方差,所以
实现R Squared
实现
r_square = 1 - mean_squared_error(y_test, y_test_predict)/np.var(y_test)
r_square
# 结果
0.6129316803937328
|
我们同样将
import numpy as np
def accuracy_score(y_true, y_predict):
assert y_true.shape[0] == y_predict.shape[0], \
"y_true 和 y_predict 数据的行数必须一致"
return np.sum(y_true == y_predict) / len(y_predict)
def mean_squared_error(y_true, y_predict):
assert len(y_true) == len(y_predict), "y_true与y_predict的数量必须一致"
return np.sum((y_true - y_predict)**2) / len(y_true)
def root_mean_squared_error(y_true, y_predict):
return np.sqrt(mean_squared_error(y_true, y_predict))
def mean_absolute_error(y_true, y_predict):
assert len(y_true) == len(y_predict), "y_true与y_predict的数量必须一致"
return np.sum(np.absolute(y_true - y_predict)) / len(y_true)
def r2_score(y_true, y_predict):
return 1 - mean_squared_error(y_true, y_predict) / np.var(y_true)
|
这样就可以在Jupyter Notebook中方便的使用了:
from myML.metrics import r2_score
r2_score = r2_score(y_test, y_test_predict)
r2_score
# 结果
0.6129316803937328
|
Scikit Learn中的
from sklearn.metrics import r2_score
r2_score(y_test, y_test_predict)
# 结果
0.6129316803937328
|
END