資料探勘實戰——交通大資料預測II
經過了近兩個月的艱苦工作,這次在阿里天池的比賽終於結束了。第一次正經的去參加資料探勘的比賽,從第一賽季開始到第二賽季結束,完整地經歷了整個流程,每天提出新想法,學習新的方法,然後用程式設計的方法去實現,看著自己的MAPE一天天的下降,那種感覺也是很棒的。覺得付出了很多,也收穫了很多,自己也找到了自己的方向,希望自己在未來可以朝著大資料和人工智慧方向繼續前行。而且這次比賽之後,自己在剩下三年的大學時光中還會繼續參加很多這種比賽的,覺得這種比賽要比基礎演算法比賽更有趣,漫長的週期也更適合我比較散漫的生活方式。在這裡回顧一下比賽,總結一下比賽的經驗和教訓吧。
第一賽季:
初次接觸資料探勘大賽。
第一次參加資料探勘比賽,雖然前面打過KDD CUP的比賽,而且型別都是差不多的,但是那次也只是分析了一下資料,然後用統計量做了一下填補而已。而這次我們要動真格的了,我們要用機器學習的模型去生成結果——大殺器Xgboost。至於Xgboost的厲害之處,我會在另一篇blog上寫一下,據老師私下裡給各個模型的排名,Xgboost除了在影象處理上略遜於深度學習,在其他領域上應該都是最厲害的模型了。
第一次提交結果。
第一天的時候,我們並沒有去分析什麼資料(其實以後也沒怎麼分析,我認為這也是我們犯下的一個很大的錯誤),而是直接去填了一個歷史中位數,我當時並沒有理解為什麼要用這麼個簡單的中位數去填補結果,只是在第二天早上起來睡得懵懵地看了一眼線上結果,MAPE在0.4284,在當天排名中佔25名。當時感覺還不錯的,也沒有在意什麼別的東西,到了第二賽季的時候想了想,這麼提交個中位數應該是為了獲得一個MAPE標準,看看建模比這個統計量能提升多少。當時沒有測試線下資料集的MAPE,也沒有對提交有一個詳細的日誌,導致到了第二賽季剛開始時,很多問題找不到原因,想與第一賽季同樣方法做出的結果做對比時卻沒有資料的尷尬。後來又對這個統計量做了一下優化,但是並沒有提升多少,可見這種在KDD CUP上做起來效果還不錯的方法在這次比賽上並不好。我覺得可能是這次比賽資料量比較大的原因吧,當資料量比較大時模型訓練的就越完備,預測的也就越接近真實值,這是我的理解。
Xgboost建模。
由於有了之前用Sklearn中的liner-regression建模的經驗,這次初次使用Xgboost建模並沒有遇到多少的困難,只是Xgboost的訓練集和測試集要求使用libsvm格式的檔案,我嘗試過把訓練集和資料集做成libsvm檔案的形式,但是出現了各種各樣的格式問題。後來發現可以直接用numpy的二維陣列匯入。。。真的坑。
第一次建模沒有采用任何的特徵工程,也沒有對資料採取任何的預處理,當時的資料純淨度還不是特別好。我們只用了歷史中位數和路長兩個特徵,用了6月份6-7點的資料作為訓練集,6月份8點的資料作為測試集來建模,最後的線上結果可以達到0.3540,相對於單純的使用統計特徵MAPE有了將近7%的提升,看來Xgboost果然名不虛傳。但是剛剛開始做的時候,我建模的時候感覺特別彆扭,因為感覺平時做建模的時候都不是這樣做的,後來想了想,這樣實際上是在歷史中位數和真實值之間做了一個對映,而不是通過特徵在歷史資料和未來資料中建立對映,所以才會感到很彆扭。
改變彆扭。
在第二次建模時,我們採用了另一種方式,之前的建模方式是以時間為主要維度進行建模的,而第二次建模我們選擇以日期為主要維度進行建模。這次我們選擇了歷史中位數,預測時間前兩小時的旅行時間,路長這三個特徵進行建模,最後的效果有了比較大的提升,在線上可以達到0.3273。之所以能夠取得這樣的提升,在後來我們考慮到了兩個原因,第一個可能是在小時時間軸上資料的波動性比較強,第二個可能是因為採用這樣的方式資料量比較少,所以我們在採用第二個方式建模時獲得了較大的提高。在第二賽季時,我們又嘗試過了基於更多特徵的第一種建模方式,但是效果也比第二種建模方式差了百分之2,當時我們想可以用第一種模型預測出的結果作為第二種模型的特徵,但是最後也沒有實現。
增加特徵。
在改進了建模方法之後,我們為模型增加了更多的特徵,例如把原有提取近3個月的中位數的特徵擴增為3個月的,2個月的,1個月的。基於類似的方法,我們為模型又增加了很多的特徵,這些增加的特徵對於模型有一定的提升,但是提升並不是特別大,後來我考慮可能是因為這些特徵都在同一緯度上,各個特徵之間差別比較小,所以對模型的提高不是特別大。
視窗平滑。
為了增加特徵,我們還對資料進行了平滑處理,讓資料在變化時變得更穩定,但是失去每個時間點和相鄰時間點的特點。我們基於兩個維度對資料進行了視窗平滑,一個是一天內每分鐘之間的維度,另一個是每天之間的維度,在雙重平滑處理後再提取特徵,這樣就增加了一倍的特徵。但是在採用視窗平滑後效果提升並不明顯,後來我們發現是由於在每分鐘直接的維度方向上,由於採用兩分鐘為一個時間視窗,時間視窗太短導致三個時間段為一個視窗平滑變化太小,在我們採取了五個時間段為要給視窗平滑後,效果提升的就比較明顯了。
更換目標函式。
在初賽進入到最後一天時,我們找到了一個讓模型提高的好方法,而這個方法也是讓我們能夠進入第二賽季的關鍵。在最開始我們使用Xgboost的時候,為了適應比賽MAPE的評價指標,我們採取了對標籤取ln運算,預測後再去exp的方法,當時我並不清楚採取這種方法的道理。xgboost的目標函式是殘差(y-y')^2而我們希望MAPE的評價函式是(y-y' /y)的方式,我們把y和y‘取ln後運算,結果就是ln(1+(y-y'/y)),而(y-y')/y就是其泰勒展示的第一項。但是問題是這只是泰勒展示的第一項而已,所以存在一些誤差,於是我們採取了自定義損失函式的方式,最終讓結果提升到了0.3064,讓我們順利進入了第二賽季。
第二賽季:
第二賽季比賽改為了線上平臺賦權的方式,只能用SQL去操作資料的方式讓我很不習慣,而且在線上操作需要等待很長時間,最後在我快要放棄的時候,比賽突然開放了資料集,允許線上下進行操作,這讓我又有了一點希望。
第二賽季的首次提交。
這一次提交,我們依然選擇填了個歷史中位數,由於更換了資料集,第一次提交效果就達到了0.3105,也進入了首頁。
建模。
我們用了之前的建模方式,在視覺化平臺上用GBDT進行了建模,但是由於在線上平臺真的很難調參,跑起來也很慢,我們的建模結果並不理想,效果僅達到了0.3050,這讓我們感到很失望,畢竟在第一賽季用合理的方法建模效果可以提升將近10%的!最開始我們考慮原因可能是三個時間段同時建模,對效果的影響會比較大,但是後來分開建模後效果也提升的並不是特別明顯。我想最重要的原因就是調參的問題吧,當然由於切換資料集的原因也是可能的。
開放平臺。
某天我早上正因為熬夜早起而頭痛時,老師突然發來訊息,說是可以線上下去做了,喜大普奔。在用第一賽季效果不錯的模型,換用第二賽季資料後,建模效果還是不怎麼好,提升到了0.2712,離我們的預期MAPE還是差了很多。但是總歸有了努力的方法,畢竟線上下的環境還是我們比較熟悉的,而在線上提取特徵簡直太困難了!
增加特徵。
按照以往的套路,當我們沒有可以提高模型的方法時,也就是能再提取特徵了。我們參考了2017KDD CUP答辯PPT的做法,又陸陸續續提取了最大值,最小值,標準差,鋒度,偏度等特徵。但是加上這些特徵對於模型的提升依然很緩慢,效果在一點點的提升,不過在當時看來已經沒有什麼能夠提高效果的方法了,只能一點點的增加特徵。
去噪。
對於中位數這種特徵,先天就有防止噪聲影響的特性,但是對於平均值尤其是最大最小值,及其容易受到噪聲的影響。所以我對資料進行了一次3δ去噪,將太偏離正態分佈的資料替換成了中位數,並沒有選擇直接剔除的原因是畢竟有些特徵還是可以包容噪聲的。而且不知道是不是增加了特徵的原因,進行了去噪後的資料建模的效果得到了較為明顯的提升。
ZSCORE變換
後來我們又知道了一個讓資料集增加資訊量而且正則化的方法,就是ZSCORE變換。進行了ZSCORE變換後效果提升的並不是特別明顯,但是迭代的次數顯然減少了,原來基本要4000步迭代完現在2500步基本就能迭代好,總體上對於效果的提升一般。
經驗和教訓。
基本上最大的問題還是線上線下的資料集構建的不好,程式碼寫得太亂,還有就是沒有作好記錄。
總計以我的菜逼水平,到rank28已經很開心了。