预测成都市PM2.5的值
为李宏毅老师的作业内容,自己实现梯度下降来预测未来的PM2.5的值。
但是我并没有完全按照作业内容来,我是读取了2021年4月份的成都市PM2.5的值,并读取前25天的内容,对后五天PM2.5的值进行预测
url = https://www.aqistudy.cn/historydata/daydata.php?city=%E6%88%90%E9%83%BD&month=202104
详细的公式推导请参考李宏毅老师的教学视频,AIstudio上面就有有字幕版本的看起来挺舒服。
数据集介绍
数据集的地址为work/data.txt里面。本来尝试爬下来,但是有反爬机制,只能手动复制下来,大佬们可以试试爬更多的数据。
每组数据有三行分别是
- 日期 AQI
- 质量等级
- PM2.5 PM10 SO2 CO NO2 O3_8h
数据读取部分
由于直接复制过来会有一些奇怪的问题,导致一组数据为三行,而且只有第三行是我们需要的数据,所以我们进行了每三行进行读取并存放在list里面。
def dataReader():
with open("./work/data.txt") as f:
lines=f.readlines()
i = 0
dataList=[]
PM2_5s=[]
for line in lines:
if i % 3 ==2:
sLine = line.split('\t')
PM2_5 = float(sLine[0])
PM10 = sLine[1]
SO2 = sLine[2]
CO = sLine[3]
NO2 = sLine[4]
O3_8H = sLine[5]
dataList.append(sLine)
PM2_5s.append(PM2_5)
#print(sLine)
i += 1
return dataList,PM2_5s
数据划分
利用前25天的数据我们作为训练集,后面5天的数据我们作为测试集,进行划分,利用前面的日期对后面进行预测和处理。
Alldatas,PM2_5s = dataReader()
knowDatas=[]
PredictDatas=[]
knowPM2_5s=[]
Predict2_5s=[]
#分别划分成25个已知的和5个预测的
for n in range(len(Alldatas)):
if n <= 24:
knowDatas.append(Alldatas[n])
knowPM2_5s.append(PM2_5s[n])
else:
PredictDatas.append(Alldatas[n])
Predict2_5s.append(PM2_5s[n])
print(knowDatas)
print(PredictDatas)
梯度下降算法部分实现
整个逻辑分成三步
-
- 计算loss function的值,对于这里而言我们使用的则是非常常见的欧氏距离
l o s s = ( y 预 − y 真 ) 2 loss = (y_{预} - y_{真})^2 loss=(y预−y真)2
y 预 = ∑ i = 0 n ( w i x i + b ) y_{预} = \sum_{i=0}^{n}(w_{i}x_{i} + b) y预=∑i=0n(wixi+b)
-
- 计算对应wi的偏导梯度和b的梯度
g r a d w i = 2 ( y 预 − y 真 ) ∗ ( − x i ) gradw_{i} = 2(y_{预} - y_{真})*(-x_{i}) gradwi=2(y预−y真)∗(−xi)
g r a d b = − 2 ( y 预 − y 真 ) gradb = -2(y_{预} - y_{真}) gradb=−2(y预−y真)
- 3.更新梯度以及重复2步骤
w i = w i − g r a d w i w_{i} = w_{i} - gradw_{i} wi=wi−gradwi
b = b − g r a d b b = b - gradb b=b−gradb
实际上我发现,对于简单的梯度下降实现难度不大。在期间值得注意的一点就是,我们需要确保符号等正确,不要粗细。我在编写相对应的代码过程中由于求导后是-x,从而导致没有梯度下降,而是梯度上升hhhh。
import random
import numpy as np
import matplotlib.pyplot as plt
#初始数据
lr = 0.0000001 #学习率
epochs = 100000 #训练次数
y_predict=0 #预测值
y_true = 0 #真实值
#w和b参数初始化
w_grad = [.0,.0,.0,.0,.0]
w=[.0,.0,.0,.0,.0]
for n in range(0,5):
w[n] = random.uniform(0,1)
b = random.uniform(0,1)
b_grad = 0
losses=[]
for epoch in range(epochs):
for data in knowDatas:
y_true = float(data[0]) #真实的PM2.5数据
#计算function计算的预测值
y_sum = 0 #wx 的和每次清零
for n in range(0,5): #5个变量乘x相加
y_sum += w[n]*float(data[n+1])
y_predict = y_sum+b #预测值
#计算梯度
for n in range(0,5):
w_grad[n] = -2*(y_true-y_predict)*float(data[n+1])
b_grad = -2*(y_true-y_predict)*1.0
#梯度下降
for n in range(0,5):
w[n] = w[n] - lr * w_grad[n]
b = b - lr * b_grad
loss = (y_true-y_predict) ** 2
losses.append(loss)
x = range(epochs)
plt.plot(x,losses)