任务描述
本关任务:认识线性模型及梯度更新的一般知识,并实现PM2.5值的线性回归。
相关知识
为了完成本关任务,你需要掌握:1.线性回归的一般知识,2.实现线性回归预测PM2.5值。
线性回归的一般知识
回归分析是一种预测性的建模技术,它研究的是因变量(目标)和自变量(预测器)之间的关系。这种技术通常用于预测分析,时间序列模型以及发现变量之间的因果关系。通常使用曲线/线来拟合数据点,目标是使曲线到数据点的距离差异最小。
线性回归是回归问题中的一种,线性回归假设目标值与特征之间线性相关,即满足一个多元一次方程。通过构建损失函数,来求解损失函数最小时的参数w和b。通常我们可以表达成如下公式:
y^=wx+b
y^为预测值,自变量x和因变量y是已知的,而我们想实现的是预测新增一个x,其对应的y是多少。因此,为了构建这个函数关系,目标是通过已知数据点,求解线性模型中w和b两个参数。
为了求解最佳参数,需要一个标准来对结果进行衡量,为此我们需要定量化一个目标函数式,使得计算机可以在求解过程中不断地优化。 针对任何樭型求解问题, 都是最终都是可以得到一組预则值 y^
,对比已有的真实值y, 数据行数为 n,可以将损失函数定义如下:
L=n1∑i=1n(y^i−yi)2
即预则值与真实值之间的平均的平方距离,统计中一般称其为 均方误差。 把之前的函数式代入损失函数,并且将需要求解的参数w和b看做是函数L的自变量,可得:
L(w,b)=n1∑i=1n(wxi+b−yi)2
现在的任务是求解最小化L时W和b的值,即核心目标优化式为
(w∗,b∗)=argmin(w,b)∑i=1n(wxi+b−yi)2
对于这个问题,我们可以使用梯度下降方法进行求解,梯度下降核心内容是对自变量进行不断的更新(针对w和b求偏导),使得目标函数不断逼近最小值的过程:
w←w−α∂w∂Lb←b−α∂b∂L
这也是我们进行编程实现线性回归的基础。
上述一般的梯度下降算法的梯度更新规则可以改写为:
θt+1,i=θt,i−η⋅gt,i
这里的更新规则中学习率是固定不变的,是开始给定的一个超参数。然而adagrad算法则是修改了学习率 ,使之成为一个可变参数,每一次学习率 的变化都是基于之前的梯度。即:
θt+1,i=θt,i−Gt,ii+εη⋅gt,i
其中, 是一个对角矩阵,其中每一个对角元素i是梯度的平方,即从 直到 , 则是平滑项,通常取值为1e-8,避免除数为0。 向量化的Adagrad处理梯度更新规则如下:
θt+1=θt−Gt+εη⋅gt
其中,Gt=θ12+…+θt2
,adagrad的初始学习率也需要人为设置,通常设初值为0.01。
实现线性回归预测PM2.5值
基于上述线性回归和梯度更新的相关知识我们进行PM2.5数据的线性回归。
首先是初始化权重、学习率 和 迭代次数:
w = np.zeros(len(x[0]))
l_rate = 10
repeat = 10
然后我们便可以进行模型的训练:
x_t = x.transpose() #x的转置
s_gra = np.zeros(len(x[0]))#记录之前梯度平方和
for i in range(repeat):#每一次迭代
hypo = np.dot(x,w)# w*x
loss = hypo - y #误差
# print(loss.shape)
cost = np.sum(loss**2) / len(x) #平方差
cost_a = math.sqrt(cost)#标准差
gra = np.dot(x_t,loss)
# print(gra.shape)
s_gra += gra**2
ada = np.sqrt(s_gra)
w = w - l_rate * gra/ada
# print ('iteration: %d | Cost: %f ' % ( i,cost_a))
模型训练完成后,我们便可以进行模型的存储,以便我们下次的使用:
# save model 这里由于服务器不可写,仅仅展示相关代码
# np.save('model.npy',w)
# read model 对训练好的模型进行读取
w = np.load('/data/shixunfiles/758ef4d7b2e0ac7ad1377ec761b6b05b_1636289441033.npy')
然后我们便可以利用训练好的模型进行测试数据的预测。数据的读取如上训练数据的读取。读取数据后,我们便可以进行预测:
ans = []
for i in range(len(test_x)):
ans.append(["id_"+str(i)])
a = np.dot(w,test_x[i])#使用训练好的权重来完成测试集的预测
ans[i].append(a)
# print("第%d个数据的预测结果为:"%i,a)
编程要求
完成右侧相关代码,实现线性回归预测PM2.5值。
测试说明
开始你的任务吧,祝你成功!
代码部分
import sys
import csv
import numpy as np
import pandas as pd
import math
import random
data = []
# 每一个维度处理一种污染物
for i in range(18):
data.append([])
# 训练数据的读取与处理
n_row = 0
text = open('/data/bigfiles/ab410c80-7695-4be3-9d57-b2c36fab9218', 'r',errors="ignore", encoding='big5') #big5是针对于文档中存在繁体字的编码
row = csv.reader(text , delimiter = ",")
# 将数据存储到data变量中
for r in row:
# 第0行沒有信息
if n_row > 0:
# 每一行只有第3-27格有值(即一天中24小时)
for i in range(3,27):
if r[i] != "NR":#其中有一个污染物全部值为‘NR’
data[(n_row-1)%18].append(float(r[i]))
else:
data[(n_row-1)%18].append(float(0))
n_row = n_row+1
text.close()
# 进行训练数据的处理和规整
x = []#特征
y = []#标签
# 共有12个月
for i in range(12):
# 每个月共有480列数据,连取10小时的分组可有471组。
for j in range(471):
x.append([])
# 共有18种污染物
for t in range(18):#把18行合成同一行
# 取前9小时为feature
for s in range(9):
x[471*i+j].append(data[t][480*i+j+s] )
y.append(data[9][480*i+j+9])#取PM2.5的标签
x = np.array(x)
y = np.array(y)
#在第一列添加一列1
x = np.concatenate((np.ones((x.shape[0],1)),x), axis=1)
########Begin######
# 训练参数的设置
w = np.zeros(len(x[0]))
l_rate = 10
repeat = 10
# 模型训练的过程
x_t = x.transpose() #x的转置
s_gra = np.zeros(len(x[0]))#记录之前梯度平方和
for i in range(repeat):#每一次迭代
hypo = np.dot(x,w)# w*x
loss = hypo - y #误差
# print(loss.shape)
cost = np.sum(loss**2) / len(x) #平方差
cost_a = math.sqrt(cost)#标准差
gra = np.dot(x_t,loss)
# print(gra.shape)
s_gra += gra**2
ada = np.sqrt(s_gra)
w = w - l_rate * gra/ada
# print ('iteration: %d | Cost: %f ' % ( i,cost_a))
# 保存训练模型 这里由于服务器不可写,仅仅展示相关代码
# np.save('model.npy',w)
# 对训练好的模型进行读取,地址为:'/data/bigfiles/9bf99672-565e-4c8b-ad2a-c469f6cdc1bb'
w = np.load('/data/bigfiles/9bf99672-565e-4c8b-ad2a-c469f6cdc1bb')
# 读取测试数据,地址为:'/data/bigfiles/226ef946-237b-4946-8bde-c3ea9061c40d'
test_x = []
n_row = 0
text = open('/data/bigfiles/226ef946-237b-4946-8bde-c3ea9061c40d', 'r', encoding = 'big5')
row = csv.reader(text, delimiter = ',')
for r in row:
if n_row %18 == 0:
test_x.append([])#每个18加一行
for i in range(2,11):
test_x[n_row//18].append(float(r[i]))#整除18,得到每次id的预测
else :
for i in range(2,11):
if r[i] !="NR":
test_x[n_row//18].append(float(r[i]))
else:
test_x[n_row//18].append(0)
n_row = n_row+1
text.close()
test_x = np.array(test_x)
# add square term
# test_x = np.concatenate((test_x,test_x**2), axis=1)
# add bias
test_x = np.concatenate((np.ones((test_x.shape[0],1)),test_x), axis=1)
# 进行预测
ans = []
for i in range(len(test_x)):
ans.append(["id_"+str(i)])
a = np.dot(w,test_x[i])#使用训练好的权重来完成测试集的预测
ans[i].append(a)
# print("第%d个数据的预测结果为:"%i,a)
#######End#######
# 打印预测结果的信息
print("共有预测结果%d条"%(len(ans)))