前言
这个是课程第一个作业,用线性回归模型做PM2.5的预测,优化方法用Adagrad,李老师提供了训练集和测试集以及示例代码,并推荐使用Linux或者Mac系统来做作业。而我准备用win10系统来完成这项作业。
一、要求
给定训练集train.csv和测试集test.csv,要求根据前9个小时的空气监测情况预测第10个小时的PM2.5含量。
二、环境
Win10系统,使用Pycharm,Python3.7。
三、数据介绍
首先熟悉一下数据,训练集train.csv包含每个月前20天的完整观测数据,因为数据的编码方式是big5,使用Pycharm打开文件后显示乱码,先选择文件编码方式为“Big5-HKSCS”,reload之后就能正常打开。
训练集包含2014年1-12月中每个月前20天的数据,每个小时均记录一次数据,每次记录18个特征数据,包括AMB_TEMP, CH4, CO, NHMC, NO, NO2, NOx, O3, PM10, PM2.5, RAINFALL, RH, SO2, THC, WD_HR, WIND_DIREC, WIND_SPEED, WS_HR。其中RAINFALL指标的值不是数值格式。总共有4230行、24列有效数据(4320 = 12个月20天18个特征),部分训练集数据如下图。
测试集test.csv的格式与训练集类似,共有240个id(类似训练集的240个日期),每个id有18项特征,均有9个小时的数据,以此来预测第10小时的PM2.5。总共有240行、9列有效数据。部分测试集数据如下图所示。
四、训练集数据预处理
在Pycharm中新建一个Python工程,在venv文件夹中新建文件夹data,将train.csv和test.csv放入其中。
1. 数据清洗
训练集中前三列不是数值部分,因此要从第四列开始取值,且需要将RAINFALL行的内容‘NR’替换为数值(以0代替)。
import pandas as pd
import numpy as np
data = pd.read_csv('./data/train.csv', encoding='Big5')
data = data.iloc[:, 3:] #iloc是根据行列号来取数据
data[data == 'NR'] = 0 #将RAINFALL行的字符替换为0
raw_data = data.to_numpy() #转换为numpy数组
清洗完后,raw_data大小为4320*24。
2. 提取特征
按月份来看,清洗后的数据(raw_data)是可看成由12份360*24的二维数组组成(360 = 20天*18个特征)。将每份360*24的数组转换成18*480的数组,如下图所示。
转换后的数组将变成如下形式:
将12组18*480数组以放入一个字典中。
month_data = {
}
for month in range(12):
sample = np.empty([18, 480]) #空的18*480数组
for day in range(20):
sample[:, day*24:(day+1)*24] = raw_data[18*(day+20*month):18*(day+1+20*month), :]
month_data[month] = sample
由于最终目的是根据前9小时的数据预测第10小时的PM2.5,所以要把10小时的数据分为一组,其中前9小时的18*9个特征作为输入x,第10个小时的第10个特征作为输出y。上述转换后的18*480数组中,480列依次为同一个月1号到20号各小时的数据,也就是480个小时的数据。以1月份的数据为例,1-10列是1-10小时的数据,作为第1组数据;2-11列是2-10小时的数据,作为第2组数据;以步长为1的方式取值到第480列为止。如下图所示。
这样,一个月就有471组数据,12个月就有12*471组数据,每组数据中,前9小时的数据(18*9的数组)转换成18*9维行向量作为输出;将第10小时的数据(18维列向量)中的第10行的数据(即第10个特征PM2.5的值)作为输出。12个月的12*471组数据的输出放入总的输入x中(12*471行,18*9列的数组),同理输出y为12*471维列向量。
reshape(1, -1):转换成一个行向量
x = np.empty([12*471, 18*9], dtype=float)
y = np.empty([12*471, 1], dtype=float)
for month in range(12):
for day in range(20):
for hour in range(24):
if hour > 14 and day == 19:
continue
x[month*471 + day*24 + hour, :] = month_data[month][:, day*20 + hour:day*20 + hour + 9].reshape(1, -1)
y[month*471 + day*24 + hour, :] = month_data[month][9, day*20 + hour + 9]
3. 标准化
方法是减去列均值再除以列标准差。
np.mean():求均值。axis = 0:压缩行,对各列求均值,返回 1* n 矩阵。
np.std():求标准差。axis=0:计算每一列的标准差。
mean_x = np.mean(x, axis = 0) #18 * 9
std_x = np.std(x, axis = 0) #18 * 9
for i in range(len(x)): #12 * 471
for j in range(len(x[0])): #18 * 9
if std_x[j] != 0:
x[i][j] = (x[i][j] - mean_x[j]) / std_x[j]
#print(x)
六、训练
模型:线性回归
y = [ y 1 y 2 ⋮ y m ] = [ b + w 1 x 1 , 1 + w 2 x 1 , 2 + . . . + w n x 1 , n b + w 1 x 2 , 1 + w 2 x 2 , 2 + . . . + w n x 2 , n ⋮ b + w 1 x m , 1 + w 2 x m , 2 + . . . + w n x m , n ] = [ 1 x 1 , 1 x 1 , 2 ⋯ x 1 , n 1 x 2 , 1 x 2 , 2 ⋯ x 2 , n ⋮ ⋮ ⋮ ⋱ ⋮ 1 x m , 1 x m , 2 ⋯ x m , n ] [ b w 1 w 2 ⋮ w n ] = [ x 1 x 2 ⋮ x m ] w = X w n = 18 ∗ 9 , m = 12 ∗ 471 \mathbf{y}=\left[\begin{matrix}y_1\\y_2\\\vdots\\y_{m}\end{matrix}\right]=\left[\begin{matrix}b+w_{1}x_{1,1}+w_{2}x_{1,2}+...+w_{n}x_{1,n}\\b+w_{1}x_{2,1}+w_{2}x_{2,2}+...+w_{n}x_{2,n}\\\vdots\\b+w_{1}x_{m,1}+w_{2}x_{m,2}+...+w_{n}x_{m,n}\end{matrix}\right]\\=\left[\begin{matrix}1&x_{1,1}&x_{1,2}&\cdots&x_{1,n}\\1&x_{2,1}&x_{2,2}&\cdots&x_{2,n}\\\vdots&\vdots&\vdots&\ddots&\vdots\\1&x_{m,1}&x_{m,2}&\cdots&x_{m,n}\end{matrix}\right]\left[\begin{matrix}b\\w_1\\w_2\\\vdots\\w_n\end{matrix}\right]=\left[\begin{matrix}\mathbf{x}_1\\\mathbf{x}_2\\\vdots\\\mathbf{x}_m\end{matrix}\right]\mathbf{w}=\mathbf{X}\mathbf{w}\\n=18*9,m=12*471 y=⎣⎢⎢⎢⎡y1y2⋮ym⎦⎥⎥⎥⎤=⎣⎢⎢⎢⎡b+w1x1,1+w2x1,2+...+wnx1,nb+w1x2,1+w2x2,2+...+wnx2,n⋮b+w1xm,1+w2xm,2+...+wn