李宏毅机器学习作业1:预测PM2.5(含训练数据)
1.要求
給定訓練集train.csv,要求根據前9個小時的空氣監測情況預測第10個小時的PM2.5含量。
訓練集介紹:
- CSV文件,包含臺灣豐原地區240天的氣象觀測資料(取每個月前20天的數據做訓練集,12月X20天=240天,每月后10天數據用于測試)
- 每天的監測時間點為0時,1時…到23時,共24個時間節點;
- 每天的檢測指標包括CO、NO、PM2.5、PM10等氣體濃度,是否降雨、刮風等氣象信息,共計18項;
- 數據集地址:https://pan.baidu.com/s/1o2Yx42dZBJZFZqCa5y3WzQ,提取碼:qgtm。
2. 思路分析
前注:下文中提到的“數據幀”并非指pandas庫中的數據結構DataFrame,而是指一個二維的數據包。
2.1 數據預處理
訓練集中數據排列形式符合人類觀察數據的習慣,但并不能直接拿來喂給模型進行訓練,因此需要對數據進行預處理。
瀏覽數據可知,數據中存在一定量的空數據NR,且多存在于RAINFALL一項。對于空數據,常規的處理方法無非就是刪除法和補全法兩種。查閱資料后發現,RAINFALL表示當天對應時間點是否降雨,有降雨值為1,無降雨值為NR,類似于布爾變量。因此可以采用補全法處理空數據:將空數據NR全部補為0即可。
根據作業要求可知,需要用到連續9個時間點的氣象觀測數據,來預測第10個時間點的PM2.5含量。針對每一天來說,其包含的信息維度為(18,24)(18項指標,24個時間節點)??梢詫?到8時的數據截取出來,形成一個維度為(18,9)的數據幀,作為訓練數據,將9時的PM2.5含量取出來,作為該訓練數據對應的label;同理可取1到9時的數據作為訓練用的數據幀,10時的PM2.5含量作為label…以此分割,可將每天的信息分割為15個shape為(18,9)的數據幀和與之對應的15個label。
訓練集中共包含240天的數據,因此共可獲得240X15=3600個數據幀和與之對應的3600個label
# 數據預處理 def dataProcess(df):x_list, y_list = [], []# df替換指定元素,將空數據填充為0df = df.replace(['NR'], [0.0])array = np.array(df).astype(float)#astype就是轉換numpy數組的數據類型為float型# 將數據集拆分為多個數據幀for i in range(0, 4320, 18):for j in range(24 - 9):mat = array[i:i + 18, j:j + 9]label = array[i + 9, j + 9] # 第10行是PM2.5x_list.append(mat)y_list.append(label)x = np.array(x_list)y = np.array(y_list)return x, y, array x.shape:(3600,18,9) y.shape:(3600,)2.2 模型建立
2.2.1 回歸模型
采用最普通的線性回歸模型,并沒有用上訓練集中所有的數據,只用到了每個數據幀樣本中的9個PM2.5含量值:
y=∑i=08wixi+by=\sum_{i=0}^{8} w_{i} x_{i}+b y=i=0∑8?wi?xi?+b
xix_{i}xi?為對應數據幀中第i個PM2.5含量,wiw_{i}wi?為其對應的權重值,bbb為偏置項,yyy為該數據幀樣本的預測結果。
2.2.2 損失函數
用預測值與label之間的平均歐式距離來衡量預測的準確程度,并充當損失函數(這里的損失指的是平均損失;乘1/2是為了在后續求梯度過程中保證梯度項系數為1,方便計算):
Loss?hocl?=12num?∑n=0num?1(y^n?yn)2\operatorname{Loss}_{\text {hocl }}=\frac{1}{2 \text { num }} \sum_{n=0}^{ { num }-1}\left(\hat{y}^{n}-y^{n}\right)^{2} Losshocl??=2?num?1?n=0∑num?1?(y^?n?yn)2
y^n\hat{y}^{n}y^?n為第n個label,yny^{n}yn為第n個數據幀的預測結果,numnumnum為參加訓練的數據幀樣本個數。
為了防止過擬合,加入正則項:
Loss?regularization=12∑i=08wi2\operatorname{Loss}_{\text {regularization}}=\frac{1}{2} \sum_{i=0}^{8} w_{i}^{2} Lossregularization?=21?i=0∑8?wi2?
Loss?=Losslabel?+β?Lossregularization?=12[1mum?∑n=0num?1(y^n?yn)2+β∑i=08wi2]\text {Loss }=L o s s_{\text {label }}+\beta \cdot L o s s_{\text {regularization }}=\frac{1}{2}\left[\frac{1}{\operatorname{mum}} \sum_{n=0}^{n u m-1}\left(\hat{y}^{n}-y^{n}\right)^{2}+\beta \sum_{i=0}^{8} w_{i}^{2}\right] Loss?=Losslabel??+β?Lossregularization??=21?[mum1?n=0∑num?1?(y^?n?yn)2+βi=0∑8?wi2?]
β\betaβ為正則項系數。
2.2.3 梯度更新
梯度計算:需明確此時的目標是使Loss最小,而可優化的參數為權重w和偏置值b,因此需要求Loss在w上的偏微分和Loss在b上的偏微分。
?Loss?wi=?Losslabel??y?y?wi+?Lossregularization?wi=1mum∑n=0num?1(y^n?∑i=08wixi?b)?(?xi)+β?∑i=08wi?Loss?b=?Losslabel??y?y?b+?Lossregularization?b=1mum∑n=0num?1(y^n?∑i=08wixi?b)?(?1)\begin{array}{l}{\frac{\partial L o s s}{\partial w_{i}}=\frac{\partial L o s s_{\text {label }}}{\partial y} \frac{\partial y}{\partial w_{i}}+\frac{\partial L o ss_{\text {regularization}}}{\partial w_{i}}=\frac{1}{{mum}} \sum_{n=0}^{num-1}\left(\hat{y}^{n}-\sum_{i=0}^{8} w_{i} x_{i}-b\right) \cdot\left(-x_{i}\right)+\beta \cdot \sum_{i=0}^{8} w_{i}} \\ {\frac{\partial L o s s}{\partial b}=\frac{\partial L o s s_{\text {label }}}{\partial y} \frac{\partial y}{\partial b}+\frac{\partial L o ss_{\text {regularization}}}{\partial b}=\frac{1}{m u m} \sum_{n=0}^{num-1}\left(\hat{y}^{n}-\sum_{i=0}^{8} w_{i} x_{i}-b\right) \cdot(-1)}\end{array} ?wi??Loss?=?y?Losslabel????wi??y?+?wi??Lossregularization??=mum1?∑n=0num?1?(y^?n?∑i=08?wi?xi??b)?(?xi?)+β?∑i=08?wi??b?Loss?=?y?Losslabel????b?y?+?b?Lossregularization??=mum1?∑n=0num?1?(y^?n?∑i=08?wi?xi??b)?(?1)?
計算出梯度后,通過梯度下降法實現參數更新。
wnewi=wi?ηw?Loss?wi,bnew=b?ηb?Loss?bw_{n e w i}=w_{i}-\eta_{w} \frac{\partial L o ss}{\partial w_{i}}, b_{n e w}=b-\eta_ \frac{\partial L o s s}{\partial b} wnewi?=wi??ηw??wi??Loss?,bnew?=b?ηb??b?Loss?
ηw\eta_{w}ηw?為權重w更新時的學習率,ηb\eta_ηb?為偏置b更新時的學習率。
2.2.3 學習率更新
為了在不影響模型效果的前提下提高學習速度,可以對學習率進行實時更新:即讓學習率的值在學習初期較大,之后逐漸減小。這里采用比較經典的adagrad算法來更新學習率。
ηn=ηn?1∑i=1n?1gradi2\eta_{n}=\frac{\eta_{n-1}}{\sqrt{\sum_{i=1}^{n-1} g r a d_{i}^{2}}} ηn?=∑i=1n?1?gradi2??ηn?1??
ηn\eta_{n}ηn?為更新后的學習率,ηn?1\eta_{n-1}ηn?1?為更新前的學習率。∑i=1n?1gradi2\sqrt{\sum_{i=1}^{n-1} g r a d_{i}^{2}}∑i=1n?1?gradi2??為在此之前所有梯度平方和的二次根。
3.完整代碼與結果分析
3.1 testPM2.5.py
import pandas as pd import numpy as np# 數據預處理 def dataProcess(df):x_list, y_list = [], []# df替換指定元素,將空數據填充為0df = df.replace(['NR'], [0.0])array = np.array(df).astype(float)#astype就是轉換numpy數組的數據類型為float型# 將數據集拆分為多個數據幀for i in range(0, 4320, 18):for j in range(24 - 9):mat = array[i:i + 18, j:j + 9]label = array[i + 9, j + 9] # 第10行是PM2.5x_list.append(mat)y_list.append(label)x = np.array(x_list)y = np.array(y_list)return x, y, array# 更新參數,訓練模型 def train(x_train, y_train, epoch):bias = 0 # 偏置值初始化weights = np.ones(9) # 權重初始化learning_rate = 1 # 初始學習率reg_rate = 0.001 # 正則項系數bg2_sum = 0 # 用于存放偏置值的梯度平方和wg2_sum = np.zeros(9) # 用于存放權重的梯度平方和for i in range(epoch):b_g = 0w_g = np.zeros(9)# 在所有數據上計算Loss_label的梯度#Loss在w上的偏微分和Loss在b上的偏微分#參加訓練的數據幀樣本個數num采用了3200,0~3200是訓練集,3200~3600是驗證集for j in range(3200):b_g += (y_train[j] - weights.dot(x_train[j, 9, :]) - bias) * (-1)for k in range(9):w_g[k] += (y_train[j] - weights.dot(x_train[j, 9, :]) - bias) * (-x_train[j, 9, k])# 求平均,除以numb_g /= 3200w_g /= 3200# 加上Loss_regularization在w上的梯度for m in range(9):w_g[m] += reg_rate * weights[m]# adagrad,相當于grad**2的加權和,adagrad算法來更新學習率bg2_sum += b_g ** 2wg2_sum += w_g ** 2# 更新權重和偏置bias -= learning_rate / bg2_sum ** 0.5 * b_gweights -= learning_rate / wg2_sum ** 0.5 * w_g# 每訓練200輪,輸出一次在訓練集上的損失if i % 200 == 0:loss = 0for j in range(3200):loss += (y_train[j] - weights.dot(x_train[j, 9, :]) - bias) ** 2print('after {} epochs, the loss on train data is:'.format(i), loss / 3200)return weights, bias# 驗證模型效果 #驗證集3400~3600 def validate(x_val, y_val, weights, bias):loss = 0for i in range(400):loss += (y_val[i] - weights.dot(x_val[i, 9, :]) - bias) ** 2return loss / 400def main():# 從csv中讀取有用的信息# 由于大家獲取數據集的渠道不同,所以數可據集的編碼格式能不同# 若讀取失敗,可在參數欄中加入encoding = 'gb18030'df = pd.read_csv('train.csv', usecols=range(3, 27))x, y, _ = dataProcess(df)# 劃分訓練集與驗證集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()3.2 結果顯示
after 0 epochs, the loss on train data is: 955.3009375 after 200 epochs, the loss on train data is: 49.86823677027294 after 400 epochs, the loss on train data is: 46.20101423801224 after 600 epochs, the loss on train data is: 44.88913061600439 after 800 epochs, the loss on train data is: 44.26903588227097 after 1000 epochs, the loss on train data is: 43.950109190566856 after 1200 epochs, the loss on train data is: 43.78092633274224 after 1400 epochs, the loss on train data is: 43.68982565130423 after 1600 epochs, the loss on train data is: 43.640314303297686 after 1800 epochs, the loss on train data is: 43.61322589236443 The loss on val data is: 40.35422383809947可以看出,模型在驗證集上的損失為40左右,即預測值與label之間的平均差異在6到7之間,由此可見,模型的整體效果還是比較差的。
總結
以上是生活随笔為你收集整理的李宏毅机器学习作业1:预测PM2.5(含训练数据)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【ML】 李宏毅机器学习一:Regres
- 下一篇: 【ML】 李宏毅机器学习一:error