這是系列文最後一篇,
目前只剩下最後一個步驟也是最有成就感的步驟,
我們將用前面 training 好的機器來預測今年的兩次大雨事件!
開始!
------------------------------------------------------------------------------------------------------------
Step 7 : FORECASTING!
這次我們到防汛中心下載今年兩次雨量的資料。
為了加快速度這邊直接給下載連結 :)
下載完成後,讓我們繼續開始編碼。
因為一樣是政府的資料,記得也先看看有沒有'缺測'。
這次也一樣要把 Data 轉換成我們要的格式,
因為每次要預測 Data 時,都要經過一樣的轉換模式,
我這次決定寫一個方法來讀取 Data,程式碼如下:
def read_predict_file(file_name, start, stop_condition):
df = pd.read_csv(file_name)
df.columns = ['time2','waterlevel','rainfall']
df.drop(['time2'], 1, inplace=True)
df[df < 0] = 0
df['daysvalue'] = df['rainfall'].rolling(window = stop_condition).mean()
df.fillna(0.00000001, inplace=True)
df = df[df['daysvalue']>0]
#print (df)
time_index = []
startpoint = datetime(start[0],start[1],start[2],start[3],0,0)
for i in range(len(df.index)):
time_index.append(startpoint)
startpoint += interval
df['time'] = pd.Series(time_index, index = df.index)
df.set_index('time', inplace=True)
df[df < 0] = 0
for i in range(2,8):
df['rainfall'+str(i)] = df['rainfall'].shift(i)
#df['waterlevel1'] = df['waterlevel'].shift(1)
df['waterlevel2'] = df['waterlevel'].shift(2)
#df['waterlevel3'] = df['waterlevel'].shift(3)
df.dropna(inplace=True)
return df
df_0610 = read_predict_file('0610rain.csv', [2016, 6, 10, 0], 48)
df_0706 = read_predict_file('0706rain.csv', [2016, 7, 6, 0], 48)
方法裡面,先讀取檔案,然後一樣整理 columns。
因為原始檔案的 time column 都會有 ‘上午/下午’ 讓我們無法使用資料,
所以要丟掉 time columns 自己重新設置。
我每次抓的日子就是以大雨開始那天往後抓兩週,一共 14 天資料。
再利用紅色那行的條件,在超過兩天沒下雨後 drop data。
就這樣我們拿到可以用來預測資料的兩個 DataFrame, df_0610 & df_0706。
接下來我們就要預測水位,並且把預測資料圖像化跟現實資料做比對。
在程式下方加上預測的方法,
就這樣,我們拿到 df_0610['predict_wl'] 和 df_0706['predict_wl'],
這兩欄就是我們小機器學出來的資料,我們把他們分別放進 ax3 和 ax4 和 waterlevel 做比較。
一樣在終端機目標資料夾中輸入
應該會得到下面這張可愛的圖,
到這邊勉勉強強算大功告成了!
有些波峰拉近看後,是馬後砲波峰,但絕大部分都確實有達到預測能力!
------------------------------------------------------------------------------------------------------------
Step 8 : 誤差值與結果討論
這邊我們要分析一下到底這樣的結果有沒有意義,有意義的原因在哪,
以及要如何把誤差數值化。
在 matplotlib 中,我們試著把每個波峰拉開看看,到底我們預測了什麼。
以下取 6/10 號大雨的前兩個波峰放大來討論一下結果。
點 1 與紅線交點為我們在 22:00 時預測的 00:00 點水位高度,
點 1 與藍線交點為我們在 00:00 點 W 水位站的真實水位高度。
這邊肥了,誤差很小,意思是說晚上十點我們就會知道 12 點水位是 2.2 公尺高。
點 2 這邊就居掉了,誤差高達一公尺!
回頭看了一下 Data 發現凌晨一點的瞬時雨量是 27 毫米,
這已經是超大豪雨的級別了,但我們在晚上 12 點的時候,
並不會知道接下來一小時,會有這樣大的雨量,所以錯估了兩小時後的水位。
接下來大家可以自己看,基本上預測都算准,但只要有瞬間超大豪雨,
因為 input feature 都沒有未來預測資料,所以會容易有大誤差。
誤差值方面,參考湄公河的文章,我們採用 root mean square error 來計算,
在 predict_df 方法中,再加入以下程式碼,計算 RMSE,
在終端機目標資料夾中輸入
得出結果如下:
大概可以解釋成, 6 / 10 號整個大雨區間,我們平均預測誤差是 15 公分,
7 / 6 號尼伯特颱風則是 25 公分左右,其實算是很精準了。
------------------------------------------------------------------------------------------------------------
心得:
這邊紀錄一下可以讓 model 改良的方法,
在結果與討論時我們有發現,瞬間超大豪雨的問題,
因為我們沒有辦法預先知道未來降雨量。
所以在改良方面,有以下兩個可以做:
1. 取氣象局的未來雨量預測當做 feature 去 predict,當然 training 時用真實 Data 就可以。
2. training step 盡量不要匯入沒有下雨時的資料,因為我們只在乎水位高漲的狀態。
第二步,我已經做過,但效果似乎不大... ...
下面再放上預測一小時的資料,算是非常非常精準。
右邊兩張小圖,分別是 6 / 10 號大雨事件的兩次大雨區間。
############ Github link ############
------------------------------------------------------------------------------------------------------------
我覺得機器學習是非常好用的一項知識、技能、工具,
希望台灣可以每一個人都會機器學習,然後成為超強小國!
------------------------------------------------------------------------------------------------------------
因為原始檔案的 time column 都會有 ‘上午/下午’ 讓我們無法使用資料,
所以要丟掉 time columns 自己重新設置。
我每次抓的日子就是以大雨開始那天往後抓兩週,一共 14 天資料。
再利用紅色那行的條件,在超過兩天沒下雨後 drop data。
就這樣我們拿到可以用來預測資料的兩個 DataFrame, df_0610 & df_0706。
接下來我們就要預測水位,並且把預測資料圖像化跟現實資料做比對。
在程式下方加上預測的方法,
def predict_df(df):
# set up the feature set
df_feature_predict_me = df[['waterlevel2','rainfall2','rainfall3','rainfall4','rainfall5','rainfall6','rainfall7']]
X_predict_me = np.array(df_feature_predict_me)
#X_predict_me = preprocessing.scale(X_predict_me)
forecast_set = clf.predict(X_predict_me)
df['predict_wl'] = pd.Series(forecast_set, index = df.index)
predict_df(df_0610)
df_0610[['waterlevel','predict_wl']].plot(ax= ax3, linewidth = 1)
ax3.set_ylabel('0610_Waterlevel')
predict_df(df_0706)
df_0706[['waterlevel','predict_wl']].plot(ax= ax4, linewidth = 1)
ax4.set_ylabel('0706_Waterlevel')
plt.show()
# set up the feature set
df_feature_predict_me = df[['waterlevel2','rainfall2','rainfall3','rainfall4','rainfall5','rainfall6','rainfall7']]
X_predict_me = np.array(df_feature_predict_me)
#X_predict_me = preprocessing.scale(X_predict_me)
forecast_set = clf.predict(X_predict_me)
df['predict_wl'] = pd.Series(forecast_set, index = df.index)
predict_df(df_0610)
df_0610[['waterlevel','predict_wl']].plot(ax= ax3, linewidth = 1)
ax3.set_ylabel('0610_Waterlevel')
predict_df(df_0706)
df_0706[['waterlevel','predict_wl']].plot(ax= ax4, linewidth = 1)
ax4.set_ylabel('0706_Waterlevel')
plt.show()
就這樣,我們拿到 df_0610['predict_wl'] 和 df_0706['predict_wl'],
這兩欄就是我們小機器學出來的資料,我們把他們分別放進 ax3 和 ax4 和 waterlevel 做比較。
一樣在終端機目標資料夾中輸入
python DBriver.py
應該會得到下面這張可愛的圖,
到這邊勉勉強強算大功告成了!
有些波峰拉近看後,是馬後砲波峰,但絕大部分都確實有達到預測能力!
------------------------------------------------------------------------------------------------------------
Step 8 : 誤差值與結果討論
這邊我們要分析一下到底這樣的結果有沒有意義,有意義的原因在哪,
以及要如何把誤差數值化。
在 matplotlib 中,我們試著把每個波峰拉開看看,到底我們預測了什麼。
以下取 6/10 號大雨的前兩個波峰放大來討論一下結果。
點 1 與紅線交點為我們在 22:00 時預測的 00:00 點水位高度,
點 1 與藍線交點為我們在 00:00 點 W 水位站的真實水位高度。
這邊肥了,誤差很小,意思是說晚上十點我們就會知道 12 點水位是 2.2 公尺高。
點 2 這邊就居掉了,誤差高達一公尺!
回頭看了一下 Data 發現凌晨一點的瞬時雨量是 27 毫米,
這已經是超大豪雨的級別了,但我們在晚上 12 點的時候,
並不會知道接下來一小時,會有這樣大的雨量,所以錯估了兩小時後的水位。
接下來大家可以自己看,基本上預測都算准,但只要有瞬間超大豪雨,
因為 input feature 都沒有未來預測資料,所以會容易有大誤差。
誤差值方面,參考湄公河的文章,我們採用 root mean square error 來計算,
在 predict_df 方法中,再加入以下程式碼,計算 RMSE,
error_square_sum = 0
for i in range(len(df.index)):
error_square = ((df['predict_wl'][i] - df['waterlevel'][i]) ** 2)
error_square_sum += error_square
rmse = sqrt(error_square_sum / len(df.index))
print ('root mean square error', rmse)
for i in range(len(df.index)):
error_square = ((df['predict_wl'][i] - df['waterlevel'][i]) ** 2)
error_square_sum += error_square
rmse = sqrt(error_square_sum / len(df.index))
print ('root mean square error', rmse)
在終端機目標資料夾中輸入
python DBriver.py
得出結果如下:
大概可以解釋成, 6 / 10 號整個大雨區間,我們平均預測誤差是 15 公分,
7 / 6 號尼伯特颱風則是 25 公分左右,其實算是很精準了。
------------------------------------------------------------------------------------------------------------
心得:
這邊紀錄一下可以讓 model 改良的方法,
因為我們沒有辦法預先知道未來降雨量。
所以在改良方面,有以下兩個可以做:
1. 取氣象局的未來雨量預測當做 feature 去 predict,當然 training 時用真實 Data 就可以。
2. training step 盡量不要匯入沒有下雨時的資料,因為我們只在乎水位高漲的狀態。
第二步,我已經做過,但效果似乎不大... ...
下面再放上預測一小時的資料,算是非常非常精準。
右邊兩張小圖,分別是 6 / 10 號大雨事件的兩次大雨區間。
############ Github link ############
------------------------------------------------------------------------------------------------------------
我覺得機器學習是非常好用的一項知識、技能、工具,
希望台灣可以每一個人都會機器學習,然後成為超強小國!
------------------------------------------------------------------------------------------------------------
Reference
[1] " Forecasting Time Series Water Levels on Mekong River Using Machine Learning Models ", 10.1109/KSE.2015.53
[2] '' Application of Support Vector Machine in Lake Water Level Prediction " , http://ascelibrary.org/doi/abs/10.1061/(ASCE)1084-0699(2006)11%3A3(199)
[3] " Integrating Support Vector Regression and a geomorphologic Artificial Neural Network for daily rainfall-runoff modelling", http://www.sciencedirect.com/science/article/pii/S1568494615006304
[4] Scikit-Learn, http://machine-learning-python.kspax.io
[5] Scikit-Learn, http://scikit-learn.org/stable/
[6] 水文資訊網, http://gweb.wra.gov.tw/hyis/index.aspx
[7] 水利署防災資訊服務網, http://fhy.wra.gov.tw/fhy/
[8] 典寶溪排水治理計畫 - 經濟部水利署
[1] " Forecasting Time Series Water Levels on Mekong River Using Machine Learning Models ", 10.1109/KSE.2015.53
[2] '' Application of Support Vector Machine in Lake Water Level Prediction " , http://ascelibrary.org/doi/abs/10.1061/(ASCE)1084-0699(2006)11%3A3(199)
[3] " Integrating Support Vector Regression and a geomorphologic Artificial Neural Network for daily rainfall-runoff modelling", http://www.sciencedirect.com/science/article/pii/S1568494615006304
[4] Scikit-Learn, http://machine-learning-python.kspax.io
[5] Scikit-Learn, http://scikit-learn.org/stable/
[6] 水文資訊網, http://gweb.wra.gov.tw/hyis/index.aspx
[7] 水利署防災資訊服務網, http://fhy.wra.gov.tw/fhy/
[8] 典寶溪排水治理計畫 - 經濟部水利署
[9] Scikit cheat sheet, http://scikit-learn.org/stable/tutorial/machine_learning_map/
你好,我在read_predict_file裡
回覆刪除df = pd.read_csv(file_name)
df.columns = ['time2','waterlevel','rainfall']
這裡會有錯誤:
ValueError: Length mismatch: Expected axis has 285 elements, new values have 3 elements
這和python版本有關嗎? 我是 v3.6,請教該如何修改比較好!!!
哭哭,這太久之前寫的,東西都亂七八糟...
刪除我剛也有試出這個問題,主要是我寫法不好才讓 read_csv 格式跑掉,
你改成這樣,
df = pd.read_csv(file_name)
cols = []
for c in df.columns[:3]:
cols.append(c)
df = df[cols]
df.columns = ['time2','waterlevel','rainfall']