最优化方法Python计算:无约束优化应用——回归模型的测试

实践中,除了用训练数据训练回归模型,使用线性回归模型做预测前,通常需要对训练结果进行测试。所谓测试指的是用另一组带有标签的数据数据集 ( x i ⊤ , y i ) , i = 1 , 2 , ⋯   , m (\boldsymbol{x}^\top_i,y_i),i=1,2,\cdots,m (xi,yi),i=1,2,,m,用训练所得的最优模式 w 0 \boldsymbol{w}_0 w0,得预测值 y i ′ y'_i yi i = 1 , 2 , ⋯   , m i=1,2,\cdots,m i=1,2,,m。记 y = ( y 1 y 2 ⋮ y m ) \boldsymbol{y}=\begin{pmatrix}y_1\\y_2\\\vdots\\y_m\end{pmatrix} y= y1y2ym y t = ( y 1 ′ y 2 ′ ⋮ y m ′ ) \boldsymbol{y}_t=\begin{pmatrix}y'_1\\y'_2\\\vdots\\y'_m\end{pmatrix} yt= y1y2ym 计算均方根误差
rmse = ∥ y t − y ∥ 2 m = ∥ y t − y ∥ m \text{rmse}=\sqrt{\frac{\lVert\boldsymbol{y}_{t}-\boldsymbol{y}\rVert^2}{m}}=\frac{\lVert\boldsymbol{y}_{t}-\boldsymbol{y}\rVert}{\sqrt{m}} rmse=myty2 =m yty
表示平均每个测试样本的预测值与对应实际的标签值之间的误差。显然,rmse值越小,意味着训练效果越好。下列代码是可通用于作为预测的回归模型的辅助类Regression类:

import numpy as np
class Regression():							#回归模型
    def rmse(self, y, y1):					#均方根误差
        m = y.size
        return np.linalg.norm(y - y1)/np.sqrt(m)
    def test(self, x, y):					#测试函数
        x, y = self.pretreat(x, y, True)	#标准化数据
        yt = self.F(self.pattern, x)		#计算预测值
        return yt, self.rmse(y, yt)
class LinearRegressor(Regression, LineModel):
     '''线性回归模型'''

Regression类中第3~5行的rmse函数计算向量y和y1之间的均方根误差。第6~9行定义测试函数test,对表示测试数据的x和y先进行归一化处理,然后将训练所得的模式pattern和x代入拟合函数F,计算所得向量yt,最后调用rmse计算y和yt的均方根误差。需要提醒注意的是,Regression类不可实例化,因为它自身并没有计算中所需的pretreat、F函数和pattern属性。它需要配合一定的回归模型使用,第10~11行定义的LinearRegressor类继承了Regression和LineModel(见博文《最优化方法Python计算:无约束优化应用——线性回归模型》),尽管这个类定义中什么事也没做,却是一个可实例化的类,它拥有Regression和LineModel的所有函数和属性。
综合案例
文件SeoulBikeData.csv来自UC Irvine Machine Learning Repository,包含了某城市一共享单车运营公司从2017年12月1日0时至2018年11月30日23时共8760条记录(每行表示一条记录)。数据集包含日期信息(第0列)、每小时租赁的自行车数量(第1列)、时间(第2列)和气象信息:温度、湿度、风速、能见度、体感温度、太阳辐射、降雪量、降雨量(第3~10列)以及第11~13列的季节、假日和运营三个字段,其数据需数字化:约定

  • 季节:Spring:0,Summer:1,Autumn:2,Winter:3;
  • 假日:No Holiday:0,Holiday:1;
  • 运营:No:0,Yes:1。

下列代码读取数据,并按以上规定作数据类型的转换。此外,数据表中第0行是表示各项数据名称的表头,应予剔除。表中表示一小时单车租赁数的第1列为标签数据,应单列。表示日期的第0列数据在预测中并不适用,也应剔除。考虑到体感温度与气温和湿度相关,可忽略这一特征数据,故应将第7列剔除。

import numpy as np												#导入numpy
data = np.loadtxt('SeoulBikeData.csv', delimiter=',', dtype=str)#读取数据文件
X = np.array(data)												#转换为数组
X = X[1:,:]														#去掉表头
Y = X[:,1].astype(float)										#读取标签数据
X = X[:,[2,3,4,5,6,8,9,10,11,12,13]]							#去掉日期、租赁数、体感温度
X1 = X[:,8]														#读取季节列
X1 = np.array([0 if x == 'Spring' else							#串转换为数值
               1 if x == 'Summer' else
               2 if x == 'Autumn' else
               3 for x in X1])
X[:,8] = X1														#回填季节列
X1 = X[:,9]														#读取假日列
X1 = np.array([0 if x == 'No Holiday' else						#串转换为数值
               1 for x in X1])
X[:,9] = X1														#回填假期列
X1 = X[:,10]													#读取运营列
X1 = np.array([0 if x == 'No' else								#串转换为数值
               1 for x in X1])
X[:,10] = X1													#回填运营列
X = X.astype(float)												#所有数据转换为实数型
print('共享单车特征数据:')
print(X)
print('共享单车标签数:')
print(Y)
m=X.shape[0]													#读取样本个数
print('共有%d个数据样本'%m)

程序的第2行以串类型读取数据集文件SeoulBikeData.csv为data。第3行将data转换为Numpy数组X。第4行将X中表示表头的第0行去掉。第5行将表中第1列(租赁数)转存为表示标签数据的数组Y。第6行去掉原表中的第0列(日期)和第1列(租赁数,已转存),第7列体感温度,保留其他特征数据列。第7~12行将表中表示季节数据的第8列数据转换为数值数据‘Spring’转换为0,‘Summer’转换为1,‘Autumn’转换为2,‘Winter’转换为3。相仿地,第13~16行转换假日列数据,第17~20行转换运营列数据。第21行将表示样本特征数据的X中所有数据转为浮点型。运行程序,将输出

共享单车特征数据:
[[ 0.  -5.2 37.  ...  3.   0.   1. ]
 [ 1.  -5.5 38.  ...  3.   0.   1. ]
 [ 2.  -6.  39.  ...  3.   0.   1. ]
 ...
 [21.   2.6 39.  ...  2.   0.   1. ]
 [22.   2.1 41.  ...  2.   0.   1. ]
 [23.   1.9 43.  ...  2.   0.   1. ]]
 共享单车标签数:
[254. 204. 173. ... 694. 712. 584.]
共有8760个数据样本

下面,我们将X、Y中的数据随机地分成两部分:Xtrain、Ytrain为训练数据中的特征及标签,Xtest、Ytest为测试数据中的特征与标签。然后用Xtrain和Ytrain训练线性回归模型,并以Xtest、Ytest作为测试数据,计算均方根误差。在上述程序后添加下列代码完成训练和测试

……
a = np.arange(m)									#下标集
np.random.seed(2026)								#随机种子
index = np.random.choice(a, m//3, replace = False)	#随机取得三分之一作为训练集下标
index1 = np.setdiff1d(a,index)						#测试集下标
Xtrain = X[index]									#训练集特征数据
Ytrain = Y[index]									#训练集标签数据
Xtest = X[index1]									#测试集特征数据
Ytest = Y[index1]									#测试集标签数据
print('随机选取%d个样本训练线性回归模型。'%(m//3))
bikeSharing = LinearRegressor()						#构造线性回归模型
bikeSharing.fit(Xtrain, Ytrain)						#训练模型
print('模式:')
print(bikeSharing.pattern)
_, rmse = bikeSharing.test(Xtest, Ytest)			#测试数据预测
print('对其余%d个样本数据测试,均方根误差:%.4f'%(m - m//3,rmse))

程序第1行的省略号表示前段程序的代码。第2行构造序列 { 0 , 1 , ⋯   , 8759 } \{0,1,\cdots,8759\} {0,1,,8759}为a。第4行从a中随机选取三分之一(m//3)数据,作为训练数据的下标index。第5行从a中除去index的数据,剩下部分作为测试数据下标index1。第6、7行构造训练数据Xtrain,Ytrain。第8、9行构造测试数据Xtest,Ytest。11行创建LinearRegressor类对象bikeSharing。第12行调用fit函数,用Xtrain,Ytrain训练bikeSharingDmand。第13~14行输出训练所得模式pattern。第15行调用bikeSharing的测试函数test对测试特征数据Xtest和Ytest进行测试,将均方根误差赋予rmse。运行程序,输出

训练中...,稍候
随机选取2920个样本训练线性回归模型。
次迭代后完成训练。
模式:
[ 0.1855  0.5034  -0.2227 -0.0213  0.0152 -0.0945
 -0.4184  0.0320 -0.0213 -0.034  0.2314 -0.2268]
对其余5840个样本数据测试,均方根误差:0.1240

即模型经过75次迭代训练完毕,由所得模式:

  • 忽略其他特征,时间每增加1个纯数量单位,共享单车租用量约增加0.1855纯量单位;
  • 忽略其他特征,温度每增加1个纯数量单位,共享单车租用量约增加0.5034个纯数量单位;
  • 忽略其他特征,湿度每增加1个纯数量单位,共享单车租用量约减少0.2227个纯数量单位;
  • 忽略其他特征,风速每增加1个纯数量单位,共享单车租用量约减少0.0213个纯数量单位;
  • 忽略其他特征,能见度每增加1个纯数量单位,共享单车租用量约增加0.0152个纯数量单位;
  • 忽略其他特征,太阳辐射每增加1个纯数量单位,共享单车租用量约减少0.0945个纯数量单位;
  • 忽略其他特征,降雨量每增加1个纯数量单位,共享单车租用量约减少0.4185个纯数量单位;
  • 忽略其他特征,降雪量每增加1个纯数量单位,共享单车租用量约增加0.032个纯数量单位;
  • 忽略其他特征,季节每变化1个纯数量单位,共享单车租用量约减少0.0213个纯数量单位;
  • 忽略其他特征,假日共享单车租用量约减少0.034个纯数量单位;
  • 忽略其他特征,公司运营单车租用量约增加0.2314个纯数量单位;
  • 若所有特征归零,单车租赁数约减少0.2268个纯数量单位。

均方根误差为0.1240,意为平均每个小时预测租赁量与实际租赁量(标准化后)误差为12.4%。
写博不易,敬请支持:
如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!

  • 19
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值