本作业主要参考秋沐霖https://www.cnblogs.com/HL-space/p/10676637.html
自己代码的做的更改
1、考虑前5小时的PM2.5对第6小时的影响,有可能考虑太久以前的对当前的影响可能几乎为0.
2、考虑比较近的前2小时影响比较大,用2次项
3、随机抽样:样本打乱然后再取前90%样本数据作为训练集,取后10%样本数据作为验证集合。
4、画出了loss和No.of parameters updates的图,用来查看loss随着更新的次数的变化情况。
# 调整训练的数据集
# 这个是作者的改进版本,是用每5个小时为一组数据,然后前两个小时的平方(PM2.5可能跟前两个小时的相关性比较大),前5个小时到前3个小时使用一次方
# 来自: https://www.cnblogs.com/HL-space/p/10676637.html
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import random
# 数据预处理
def dataProcess(df):
x_list, y_list = [], []
# df替换指定元素,将空数据填充为0
df = df.replace(['NR'], [0.0])
# astype() 转换array中元素数据类型
array = np.array(df).astype(float)
# 将数据集拆分为多个数据帧
for i in range(0, 4320, 18):
for j in range(24-5): # 数据的调整, 用前5个小时预测第6个小时的数据,因为时间越早的数据可能跟后面的数据没有什么相关性
mat = array[i:i+18, j:j+5] # (18, 5)
label = array[i+5, j+5] # 第6行是PM2.5 (1,)
x_list.append(mat)
y_list.append(label) # (240*19)
# x = np.array(x_list) # 这样一共就有(240*19)
# y = np.array(y_list)
'''
# 将每行数据都scale到0到1的范围内,有利于梯度下降,但经尝试发现效果并不好
for i in range(18):
if(np.max(x[:, i, :]) != 0):
x[: , i, :] /= np.max(x[:, i, :])
'''
# print(x_list.shape) # (4560=240*19, 18, 5) 240天,每一天分成19组数据,每组数据18个特征,5个小时
# print(y_list.shape) # (4560,)
print(len(y_list))
return x_list, y_list, array
# 更新参数,训练模型
def train(x_train, y_train, epoch):
bias = 0 # 偏置值初始化
weights = np.ones(5) # 权重初始化
learning_rate = 1 # 初始学习率
reg_rate = 0.001 # 正则项系数
bg2_sum = 0 # 用于存放偏置值的梯度平方和
wg2_sum = np.zeros(5) # 用于存放权重的梯度平方和
loss_list = []
# print(x_train[1, 9, 0:3])
# print(x_train[1, 9, 3:])
# print(np.concatenate((x_train[1, 9, 0:3], x_train[1, 9, 3:]**2), axis=0))
for i in range(epoch):
b_g = 0
w_g = np.zeros(5)
# 在所有数据上计算Loss_label的梯度
# 这边是考虑到前两个小时的影响可能会更大,所以前两个小时使用平方项
for j in range(len(y_train)):
b_g += (y_train[j] - weights.dot(
np.concatenate((x_train[j, 9, 0:3], x_train[j, 9, 3:]**2), axis=0)) - bias) * (-1)
for k in range(5):
if k < 3:
w_g[k] += (y_train[j] - weights.dot(
np.concatenate((x_train[j, 9, 0:3], x_train[j, 9, 3:]**2), axis=0)) - bias) * (-x_train[j, 9, k])
else:
w_g[k] += (y_train[j] - weights.dot(
np.concatenate((x_train[j, 9, 0:3], x_train[j, 9, 3:] ** 2), axis=0)) - bias) * (-2*x_train[j, 9, k])
# 如果考虑更多的特征呢?
# 求平均
b_g /= len(y_train)
w_g /= len(y_train)
# 加上Loss_regularization在w上的梯度
for m in range(5):
w_g[m] += reg_rate * weights[m]
# adagrad
bg2_sum += b_g**2
wg2_sum += w_g**2
# 更新权重和偏置
bias -= learning_rate / np.sqrt(bg2_sum) * b_g
weights -= learning_rate / np.sqrt(wg2_sum) * w_g
# 每训练200轮,输出一次在训练集上的损失
if i%20 == 0:
loss = 0
for j in range(len(y_train)):
loss += (y_train[j] - weights.dot(x_train[j, 9, :]) - bias)**2
print('after {} epochs, the loss on train data is:'.format(i), loss/len(y_train))
loss_list.append(loss/len(y_train))
show_loss(loss_list)
return weights, bias
# 验证模型效果
def validate(x_val, y_val, weights, bias):
loss = 0
for i in range(len(y_val)):
loss += (y_val[i] - weights.dot(x_val[i, 9, :]) - bias)**2
return loss / len(y_val)
# loss随着迭代次数的增加的变化
def show_loss(loss_list):
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
plt.plot(range(len(loss_list)), loss_list, 'r')
ax1.set_title("gradient descent loss")
ax1.set_xlabel("No. of parameters updates")
ax1.set_ylabel("Loss")
plt.show()
def main():
# 从csv中读取有用的信息
# 由于大家获取数据集的渠道不同,所以数据集的编码格式可能不同
# 若读取失败,可在参数栏中加入encoding = 'gb18030'
df = pd.read_csv('train.csv', usecols=range(3,27))
x, y, _ = dataProcess(df)
#划分训练集与验证集
# 下面这一段代码非常重要
# 随机抽取90%作为训练集, 10%作为测试集
# 获得数据集长度
data_length = len(y)
print(data_length)
# 定义数据集每个数据的序号,根据序号读取数据
index_list = list(range(data_length))
# 随机打乱训练数据的索引序号
random.shuffle(index_list)
x_list = []
y_list = []
for i in index_list:
x_list.append(x[i])
y_list.append(y[i])
x_train, y_train = np.array(x_list[0: 4104]), np.array(y_list[0: 4104])
x_val, y_val = np.array(x_list[4104:]), np.array(y_list[4104:])
# x_train, y_train = x[0:3200], y[0:3200]
# x_val, y_val = x[3200:3600], y[3200:3600]
epoch = 2000 # 训练轮数
# 开始训练
w, b = train(x_train, y_train, epoch)
# 在验证集上看效果
loss = validate(x_val, y_val, w, b)
print('The loss on val data is:', loss)
if __name__ == '__main__':
main()
结果分析:
1、loss还是挺大的,可能就是一开始的模型设置有问题,只考虑到PM2.5这个特征,应该可以多考虑其它几个比较重要的特征。
2、梯度下降很慢,可能因为使用adagrad的原因。可以考虑使用其它方法的梯度下降。
3、训练结果再拿到测试集上取跑一跑,看看loss的情况,这时候的loss情况是最接近真实一个外部没有见过的数据传入模型,预测结果情况的、