在之前已介绍了线性回归的模型算法,那么有了模型之后,如何去评估这个模型的效果究竟是好还是差呢?而如果得到一个效果较好的模型又如何去将其封装,方便他人使用呢?这需要具备回归模型的评估与封装的知识。
回归模型的评估指标
如何去判断一个线性回归模型的好与坏,有个指标是看模型的拟合度,拟合度越高就代表模型的误差越小,也就代表着做预测时会越精准。因此对模型的效果评估很重要,并且模型的评估需要有同训练集分开的测试集,就好像高考是评估同学的学习效果,就必然不会拿平时做过的练习题去让同学们考,而是出新的题目给同学。
一般情况下,拿到数据集将整个数据集按照一定比例分为训练集和测试集,线性回归模型训练完毕后,可以利用测试集评估训练结果误差。sklearn.metrics提供了计算模型误差(预测结果和真实结果之间的)的几个常用算法API:
代码语言:javascript复制import sklearn.metrics as sm
#平均绝对值误差:1/mΣ|实际输出-预测输出|
sm.mean_absolute_error(y,pred_y)
#平均平方误差:SQRT(1/mΣ(实际输出-预测输出)A2)
sm.mean_squared_error(y,pred_y)
#中位绝对值误差:MEDIAN(|实际输出-预测输出)1
sm.median_absolute_error(y,pred_y)
#R2得分,(0,1]区间的分值。分数越高,误差越小。
sm.r2_score(y,pred_y)
- 平均绝对误差是相当于是看每个样本预测值和真实值的平均距离。误差对应到真实情况可理解为,假如我们根据一定的特征预测一个人的薪资水平大概15w/年,误差为0.4,也就是这个人的工资水平范围应该是14.6w-15.4w的区间内波动。
- 平均平方误差和平均绝对误差类似,只不过是取了一个平方再开根。
- 中位绝对值误差适合于最大值和最小值差距很大,中位数相较于均值更不易受影响
与上面的误差指标不同,实际上可看作一个模型的预测效果分数
代码实践
还是以薪资预测为例,这次使用一个名为数据集"Salary_Data.csv"的数据集,每行是一个样本,共有30个样本,共1个特征为工作年限,以及对应的薪资水平。将其读入python,画出散点图
代码语言:javascript复制# 加载数据集
data=pd.read_csv("Salary_Data.csv")
x,y=data['YearsExperience'],data['Salary']
train_x,train_y=pd.DataFrame(x),y
# 找到一组测试样本数据,输出评估指标结果
# 取测试集样本,从头至尾每4个切出1个数据
test_x,test_y=train_x.iloc[::4],train_y.iloc[::4]
test_x
输出结果:所取出的测试集
进行模型的建立和误差的评估
代码语言:javascript复制# 基于sklearn提供ApI,训练线性回归模型
model=lm.LinearRegression()
model.fit(train_x,train_y)
# 进行预测
pred_test_y=model.predict(test_x)
# 评估误差
import sklearn.metrics as sm
print(sm.mean_absolute_error(test_y,pred_test_y))
print(sm.mean_squared_error(test_y,pred_test_y))
print(sm.median_absolute_error(test_y,pred_test_y))
print(sm.r2_score(test_y,pred_test_y))
以第一个输出结果为例,4587.366,这说明预测的薪资的误差上下波动的幅度在4000 左右,如果这个误差可以被接受,那么这个模型便可以使用。第二个由于是平方的缘故数值会明显较大。而最后一个输出是
得分,该值非常接近1,说明其预测效果较为优秀。
有了评估模型的方法,意味着在之后可以去比较模型的效果,那么模型如果要真正使用还需要对其进行保存和加载。
模型的保存和加载
模型训练是一个耗时的过程,如果数据复杂算法复杂有可能训练起来要很久的时间,一个优秀的机器学习是非常宝贵的。可以模型保存到磁盘中,也可以在需要使用的时候从磁盘中重新加载模型到内存中即可。不需要重新训练。保存和加载的工作在真正的业务中非常重要。
要存的究竟是什么呢?其实就是模型的参数,比如线性回归中的w0,w1,w2...而在python当中提供了可持久化python对象的方案,其API如下。模型训练好后,先调用下列代码前两行将训练好的模型存起来,等需要时调用后面的代码加载出来,项目真正要上线的代码就是下面那一部分模型加载出来的代码。
代码语言:javascript复制# 将训练好的模型对象保存到磁盘文件中
with open(../../data/linear.pkl','wb')as f:
pickle.dump(model,f)
# 从磁盘文件中加载模型对象
with open(../../data/linear.pk1','rb')as f:
model=pickle.load(f)
# 根据输入预测输出
pred_y=model.predict(x)
代码实践
model是我们上面训练好的模型,运行如下这一段代码,如果保存成功就会输出“dump success.”
代码语言:javascript复制import pickle
with open('model.pickle','wb') as f:
pickle.dump(model,f)
print('dump success.')
这样在当前的工作目录中就可以找到一个 model.pickle的文件,其保存了持久化的python对象。
待需要使用时,直接在如下代码的predict()中加入要预测的样本数据
代码语言:javascript复制# 模型的加载
with open('model.pickle','rb') as f:
model=pickle.load(f)
model.predict([[15.6],[16.4]])
比如我设置了一组要预测的数据,当工作年限为15.6年和16.4年,对应的工资水平应该多少,输出结果如下:
然而,在实际的业务应用中,上面的内容还是比较麻烦,因为要工作的程序员不同,要对其有很多说明才能帮助他正确的调用你写的代码,并且模型如果更新了,还需要将自己更新的文件交给要使用的程序员。
那么就需要采用封装的方法,封装到一个类,别的程序员需要的时候只需要import类,创建一个对象就可以使用模型的方法。
模型的封装
封装一个薪资预测的类,其中的构造方法意味着一旦创建对象便读取文件,拿到模型并存到属性,predict()方法是供他人使用,调用者只需要输入一维数组,在函数中会整理成二维数组,这样便可以适用model.predict()
代码语言:javascript复制import numpy as np
import pandas as pd
import pickle
# 声明一个薪资预测类型,封装预测逻辑
class SalaryPredictionModel():
def _init_(self):
with open('model.pickle','rb')as f:
self.model=pickle.load(f)
def predict(self,exps):
"""
exps:工作年限数组(一维数组)
"""
exps=np.array(exps).reshape(-1,1)#可以把(4,)一维数细变维:(4,1)
return self.model.predict(exps)
在想要调用模型的时候只需要输入以下代码,传入一个数组即可
代码语言:javascript复制model=SalaryPredictionModel()
model.predict([3.4,5.5,6,8])