TIANCHI-全球城市计算挑战赛-完整方案及关键代码分享(季军)
TIANCHI-全球城市計(jì)算挑戰(zhàn)賽--參賽者將根據(jù)主辦方提供的地鐵人流相關(guān)數(shù)據(jù),挖掘隱藏在背后的出行規(guī)律,準(zhǔn)確預(yù)測(cè)各個(gè)地鐵站點(diǎn)未來(lái)流量的變化。主辦方希望通過(guò)這次挑戰(zhàn)賽,用大數(shù)據(jù)和人工智能等技術(shù)助力未來(lái)城市安全出行。
本文的開源方案作者:王賀
參賽成員介紹:
接下來(lái)將會(huì)呈現(xiàn)完整方案!!!滿滿干貨!!!
競(jìng)賽官網(wǎng):
https://tianchi.aliyun.com/competition/entrance/231708/introduction
數(shù)據(jù)集下載鏈接:
https://pan.baidu.com/share/init?surl=exjtkUqYPzdWKsCUYGix_g
提取碼:0qsm
賽題分析
大賽以“地鐵乘客流量預(yù)測(cè)”為賽題,參賽者可通過(guò)分析地鐵站的歷史刷卡數(shù)據(jù),預(yù)測(cè)站點(diǎn)未來(lái)的客流量變化,幫助實(shí)現(xiàn)更合理的出行路線選擇,規(guī)避交通堵塞,提前部署站點(diǎn)安保措施等,最終實(shí)現(xiàn)用大數(shù)據(jù)和人工智能等技術(shù)助力未來(lái)城市安全出行。
問(wèn)題簡(jiǎn)介,通過(guò)分析地鐵站的歷史刷卡數(shù)據(jù),預(yù)測(cè)站點(diǎn)未來(lái)的每十分鐘出入客流量。
比賽訓(xùn)練集包含1月1日到1月25日共25天地鐵刷卡數(shù)據(jù)記錄。分為A、B、C三個(gè)榜,分別增加一天的數(shù)據(jù)記錄,預(yù)測(cè)接下來(lái)一天每個(gè)站點(diǎn)每十分鐘出入客流量。評(píng)估指標(biāo)為MAE。
數(shù)據(jù)集
評(píng)估指標(biāo)
賽題難點(diǎn)
本次比賽分為三個(gè)榜,每個(gè)榜選取的日期不同,有周內(nèi),也有周末。我們將周內(nèi)看作正常日期,周末看作特殊日期。面對(duì)這兩類日期如何進(jìn)行建模,如何建模盡可能達(dá)到最大的預(yù)測(cè)準(zhǔn)確性。我們將本次比賽的難點(diǎn)歸納為如下幾點(diǎn)。
(1)本次比賽的label需要自己構(gòu)建, 如何建模使我們能在給定的數(shù)據(jù)集上達(dá)到盡可能大的預(yù)測(cè)準(zhǔn)確性?
(2)對(duì)于訓(xùn)練集不同時(shí)間段的選取對(duì)最終結(jié)果都很造成一定的影響,如何選用時(shí)間段,讓訓(xùn)練集分布和測(cè)試集分布類似,也是本次比賽的關(guān)鍵之一。
(3)如何刻畫每個(gè)時(shí)間段的時(shí)序特點(diǎn),使其能夠捕捉數(shù)據(jù)集的趨勢(shì)性,周期性,循環(huán)性。
(4)地鐵站點(diǎn)的流量存在太多影響因素,比如同時(shí)到站,突發(fā)情況,或者是盛大活動(dòng)等,所以該如何處理異常值&保證模型穩(wěn)定的情況。
針對(duì)上面的幾個(gè)難點(diǎn),下面我們分塊闡述我們團(tuán)隊(duì)算法設(shè)計(jì)的思路&細(xì)節(jié),我們的核心思路主要分為基于EDA的建模模塊、特征工程模塊以及模型訓(xùn)練&融合三個(gè)部分。
核心思路Part1- EDA-based建模框架
1.模型框架
模型我們采用滑窗滾動(dòng)(天)的方式進(jìn)行構(gòu)建,這樣可以防止因?yàn)槟骋惶齑嬖谄娈愔刀鴮?dǎo)致模型訓(xùn)練走偏。最后將所有滾動(dòng)滑窗的標(biāo)簽以及特征進(jìn)行拼接形成我們最終的訓(xùn)練集。
滑窗的方式可以參考下圖:
對(duì)于常見得時(shí)序問(wèn)題時(shí),都可以采樣這種方式來(lái)提取特征,構(gòu)建訓(xùn)練集。
2.模型細(xì)節(jié)
上面滑窗滾動(dòng)需要選擇分布于測(cè)試集類似的進(jìn)行l(wèi)abel的構(gòu)建才能取得較好的結(jié)果,所以在此之前我們需要對(duì)分布差異大的數(shù)據(jù)進(jìn)行刪除。
這里我們進(jìn)行了簡(jiǎn)單得EDA來(lái)分析label得分布情況。(好的EDA能夠幫助你理解數(shù)據(jù),挖掘更多細(xì)節(jié),在比賽中必不可少)
5號(hào)-10號(hào)各時(shí)刻入站流量分布12號(hào)-18號(hào)各時(shí)刻入站流量分布19號(hào)-25號(hào)各時(shí)刻入站流量分布從三幅圖中可以看出周末與周內(nèi)分布有很大差異,所以我們將測(cè)試集為周末和測(cè)試集為周內(nèi)經(jīng)行區(qū)別對(duì)待,保證訓(xùn)練集分布的穩(wěn)定。
23號(hào)和24號(hào)入站流量分布從圖中可以看出相同時(shí)間段流量突然相差巨大。可以考慮是因?yàn)橥话l(fā)性活動(dòng),特別事件等因素影響。
元旦節(jié)及之后幾天的入站流量分布由節(jié)假日流量分布,我們發(fā)現(xiàn),節(jié)假日的信息和非節(jié)假日的分布差異非常大,所以我們也選擇將其刪除。
核心思路Part2-特征工程
有了模型的框架,下面就是如何對(duì)每個(gè)站點(diǎn)不同時(shí)刻的流量信息進(jìn)行刻畫,此處需要切身地去思考影響地鐵站點(diǎn)流量的因素,并從能使用的數(shù)據(jù)中思考如何構(gòu)造相關(guān)特征來(lái)表示該因素。最終通過(guò)大量的EDA以及分析,我們通過(guò)以下幾個(gè)模塊來(lái)對(duì)地鐵流量的特征進(jìn)行構(gòu)建。
1.?強(qiáng)相關(guān)性信息
強(qiáng)相關(guān)性信息主要發(fā)生在每天對(duì)應(yīng)時(shí)刻,所以我們分別構(gòu)造了小時(shí)粒度和10分鐘粒度的出入站流量特征。考慮到前后時(shí)間段流量的波動(dòng)因素,所以又添加上個(gè)時(shí)段和下個(gè)時(shí)段,或者上兩個(gè)和下兩個(gè)時(shí)段的流量特征。同時(shí)還構(gòu)造了前N天對(duì)應(yīng)時(shí)段的流量。更進(jìn)一步,考慮到相鄰站點(diǎn)的強(qiáng)相關(guān)性,添加相鄰兩站對(duì)應(yīng)時(shí)段的流量。
2.?趨勢(shì)性
挖掘趨勢(shì)性也是我們提取特征的關(guān)鍵,我們主要構(gòu)造特征定義如下:
即表示前后時(shí)段的差值,這里可以是入站流量也可以是出戰(zhàn)流量。同樣,我們考慮了每天對(duì)應(yīng)當(dāng)前時(shí)段,每天對(duì)應(yīng)上個(gè)時(shí)段等。當(dāng)然我們也可以考慮差比:
關(guān)鍵代碼:
補(bǔ)充:上面是比賽所用代碼,但賽后才發(fā)現(xiàn)有部分邏輯錯(cuò)誤,這個(gè)錯(cuò)誤從A榜到C榜都沒發(fā)現(xiàn)
# 錯(cuò)誤代碼 dic_innums = df_d.groupby(['tmp_10_minutes_bf'])['inNums'].sum().to_dict() dic_outnums = df_d.groupby(['tmp_hours_bf'])['outNums'].sum().to_dict() # 修改后代碼 dic_innums = df_d.groupby(['tmp_10_minutes_bf'])['inNums'].sum().to_dict() dic_outnums = df_d.groupby(['tmp_10_minutes_bf'])['outNums'].sum().to_dict()3.周期性
由于周末分布類似,工作日分布類似。所以我們選擇對(duì)應(yīng)日期對(duì)應(yīng)時(shí)間段的信息進(jìn)行特征的構(gòu)建,具體地:
關(guān)鍵代碼:
columns = ['_innum_10minutes','_outnum_10minutes','_innum_hour','_outnum_hour'] # # 過(guò)去n天的sum,mean for i in range(2,left):for f in columns:colname1 = '_bf_'+str(i)+'_'+'days'+f+'_sum'df_feature_y[colname1] = 0for d in range(1,i+1):df_feature_y[colname1] = df_feature_y[colname1] + df_feature_y['_bf_'+str(d) +f]colname2 = '_bf_'+str(d)+'_'+'days'+f+'_mean'df_feature_y[colname2] = df_feature_y[colname1] / i# 過(guò)去n天的mean的差分 for i in range(2,left):for f in columns:colname1 = '_bf_'+str(d)+'_'+'days'+f+'_mean'colname2 = '_bf_'+str(d)+'_'+'days'+f+'_mean_diff'df_feature_y[colname2] = df_feature_y[colname1].diff(1)df_feature_y.loc[(df_feature_y.hour==0)&(df_feature_y.minute==0), colname2] = 04.stationID相關(guān)特征
主要來(lái)挖掘不同站點(diǎn)及站點(diǎn)與其它特征組合得熱度,關(guān)鍵代碼:
def get_stationID_fea(df):df_station = pd.DataFrame()df_station['stationID'] = df['stationID'].unique()df_station = df_station.sort_values('stationID')tmp1 = df.groupby(['stationID'])['deviceID'].nunique().to_frame('stationID_deviceID_nunique').reset_index()tmp2 = df.groupby(['stationID'])['userID'].nunique().to_frame('stationID_userID_nunique').reset_index()df_station = df_station.merge(tmp1,on ='stationID', how='left')df_station = df_station.merge(tmp2,on ='stationID', how='left')for pivot_cols in tqdm_notebook(['payType','hour','days_relative','ten_minutes_in_day']):tmp = df.groupby(['stationID',pivot_cols])['deviceID'].count().to_frame('stationID_'+pivot_cols+'_cnt').reset_index()df_tmp = tmp.pivot(index = 'stationID', columns=pivot_cols, values='stationID_'+pivot_cols+'_cnt')cols = ['stationID_'+pivot_cols+'_cnt' + str(col) for col in df_tmp.columns]df_tmp.columns = colsdf_tmp.reset_index(inplace = True)df_station = df_station.merge(df_tmp, on ='stationID', how='left')return df_station核心思路Part3-模型訓(xùn)練&融合
模型訓(xùn)練方面我們主要有三個(gè)方案,分別是傳統(tǒng)方案、平滑趨勢(shì)和時(shí)序stacking。最后將這三個(gè)方案預(yù)測(cè)的結(jié)果根據(jù)線下驗(yàn)證集的分?jǐn)?shù)進(jìn)行加權(quán)融合。
由于C榜分?jǐn)?shù)得優(yōu)越性,所以此處我們主要闡述C榜的方案。
1.傳統(tǒng)方案
由于C榜測(cè)試集為周內(nèi)數(shù)據(jù),所以我們移除了周末數(shù)據(jù),保證分布基本一致,為了保持訓(xùn)練集的周期性,我們移除了周一和周二。這也作為我們最基本的方案進(jìn)行建模。
2.平滑趨勢(shì)
我們?cè)O(shè)計(jì)了一種處理奇異值的方法,也就是第二個(gè)方案平滑趨勢(shì)。方案思想是,對(duì)于周內(nèi)分布大體相同的日期,如果相同時(shí)刻流量出現(xiàn)異常波動(dòng),那么我們將其定義為奇異值。然后選取與測(cè)試集有強(qiáng)相關(guān)性的日期作為基準(zhǔn),比如C榜測(cè)試集為31號(hào),那么選擇24號(hào)作為基準(zhǔn),對(duì)比24號(hào)與其它日期的相對(duì)應(yīng)時(shí)刻的站點(diǎn)流量情況。這里我們構(gòu)造其它日期對(duì)應(yīng)24號(hào)時(shí)刻流量的趨勢(shì)比,根據(jù)這個(gè)趨勢(shì)比去修改對(duì)應(yīng)時(shí)刻中每個(gè)10分鐘的流量。因?yàn)樾r(shí)的流量更具穩(wěn)定,所以根據(jù)小時(shí)確定趨勢(shì)比,再修改小時(shí)內(nèi)10分鐘的流量。對(duì)流量進(jìn)行修改后再進(jìn)行傳統(tǒng)方案的建模,這里我們回保留周一和周二的數(shù)據(jù)。
具體步驟:
刪除周六周日
平滑24號(hào)之前日期對(duì)應(yīng)24號(hào)的時(shí)刻流量趨勢(shì)
常規(guī)訓(xùn)練
下面將給出平滑趨勢(shì)關(guān)鍵代碼:
if (test_week!=6)&(test_week!=5):inNums_hour = data[data.day!=31].groupby(['stationID','week','day','hour'])['inNums' ].sum().reset_index(name='inNums_hour_sum')outNums_hour = data[data.day!=31].groupby(['stationID','week','day','hour'])['outNums'].sum().reset_index(name='outNums_hour_sum')# 合并新構(gòu)造特征data = data.merge(inNums_hour , on=['stationID','week','day','hour'], how='left')data = data.merge(outNums_hour, on=['stationID','week','day','hour'], how='left')data.fillna(0, inplace=True)# 提取24號(hào)流量test_nums = data.loc[data.day==24, ['stationID','ten_minutes_in_day','inNums_hour_sum','outNums_hour_sum']]test_nums.columns = ['stationID','ten_minutes_in_day','test_inNums_hour_sum' ,'test_outNums_hour_sum']# 合并24號(hào)流量data = data.merge(test_nums , on=['stationID','ten_minutes_in_day'], how='left')# 構(gòu)造每天與的趨勢(shì)data['test_inNums_hour_trend'] = (data['test_inNums_hour_sum'] + 1) / (data['inNums_hour_sum'] + 1 )data['test_outNums_hour_trend'] = (data['test_outNums_hour_sum'] + 1) / (data['outNums_hour_sum'] + 1)if (test_week!=6)&(test_week!=5):# 初始化新的流量data['inNums_new'] = data['inNums']data['outNums_num'] = data['outNums']for sid in range(0,81):print('inNums stationID:', sid)for d in range(2,24):inNums = data.loc[(data.stationID==sid)&(data.day==d),'inNums']trend = data.loc[(data.stationID==sid)&(data.day==d),'test_inNums_hour_trend']data.loc[(data.stationID==sid)&(data.day==d),'inNums_new'] = trend.values*(inNums.values+1)-1for d in range(25,26):inNums = data.loc[(data.stationID==sid)&(data.day==d),'inNums']trend = data.loc[(data.stationID==sid)&(data.day==d),'test_inNums_hour_trend']data.loc[(data.stationID==sid)&(data.day==d),'inNums_new'] = trend.values*(inNums.values+1)-1for sid in range(0,81):print('outNums stationID:', sid)for d in range(2,24):outNums = data.loc[(data.stationID==sid)&(data.day==d),'outNums']trend = data.loc[(data.stationID==sid)&(data.day==d),'test_outNums_hour_trend']data.loc[(data.stationID==sid)&(data.day==d),'outNums_online'] = trend.values*(outNums.values+1)-1for d in range(25,26):outNums = data.loc[(data.stationID==sid)&(data.day==d),'outNums']trend = data.loc[(data.stationID==sid)&(data.day==d),'test_outNums_hour_trend']data.loc[(data.stationID==sid)&(data.day==d),'outNums_new'] = trend.values*(outNums.values+1)-1# 后處理data.loc[data.inNums_new < 0 , 'inNums_new' ] = 0data.loc[data.outNums_new < 0 , 'outNums_new'] = 0data['inNums'] = data['inNums_new']data['outNums'] = data['outNums_new']3.時(shí)序Stacking
因?yàn)闅v史數(shù)據(jù)中存在一些未知的奇異值,例如某些大型活動(dòng)會(huì)導(dǎo)致某些站點(diǎn)在某些時(shí)刻流量增加,這些數(shù)據(jù)的影響很大,為了減小此類數(shù)據(jù)的影響,我們用了時(shí)序stacking的方式進(jìn)行解決,如果模型預(yù)測(cè)結(jié)果和我們的真實(shí)結(jié)果相差較大,那么此類數(shù)據(jù)就是異常的,方案的可視化如下,通過(guò)下面的操作,我們線下和線上都能得到穩(wěn)定的提升。
4.模型融合
三個(gè)方案各具優(yōu)勢(shì),線下的表現(xiàn)的相關(guān)性也較低,經(jīng)過(guò)過(guò)融合后線下的結(jié)果更加穩(wěn)定,最終我們依線下CV的表現(xiàn)對(duì)其進(jìn)行加權(quán)融合。
實(shí)驗(yàn)結(jié)果Part4
A榜結(jié)果第一BC榜綜合考慮第二名上面的代碼作者在線上A榜取得了第一名的成績(jī)。在BC榜去掉復(fù)現(xiàn)失敗的隊(duì)伍,也能取得第二的成績(jī)。
比賽經(jīng)驗(yàn)總結(jié)
1. 模型擁有較強(qiáng)的魯棒性,在A榜取得了第一,BC榜綜合成績(jī)上第二
2. 設(shè)計(jì)了一種處理奇異值的方法, 線下線上都取得了一致的提升
3. 較為完備的時(shí)序特征工程 + 不同時(shí)段的數(shù)據(jù)選擇
請(qǐng)關(guān)注和分享↓↓↓?
本站的知識(shí)星球(黃博的機(jī)器學(xué)習(xí)圈子)ID:92416895
目前在機(jī)器學(xué)習(xí)方向的知識(shí)星球排名第一
往期精彩回顧
良心推薦:機(jī)器學(xué)習(xí)入門資料匯總及學(xué)習(xí)建議(2018版)
黃海廣博士的github鏡像下載(機(jī)器學(xué)習(xí)及深度學(xué)習(xí)資源)
吳恩達(dá)老師的機(jī)器學(xué)習(xí)和深度學(xué)習(xí)課程筆記打印版
機(jī)器學(xué)習(xí)小抄-(像背托福單詞一樣理解機(jī)器學(xué)習(xí))
首發(fā):深度學(xué)習(xí)入門寶典-《python深度學(xué)習(xí)》原文代碼中文注釋版及電子書
機(jī)器學(xué)習(xí)的數(shù)學(xué)基礎(chǔ)
機(jī)器學(xué)習(xí)必備寶典-《統(tǒng)計(jì)學(xué)習(xí)方法》的python代碼實(shí)現(xiàn)、電子書及課件
吐血推薦收藏的學(xué)位論文排版教程(完整版)
Python環(huán)境的安裝(Anaconda+Jupyter notebook+Pycharm)
Python代碼寫得丑怎么辦?推薦幾個(gè)神器拯救你
總結(jié)
以上是生活随笔為你收集整理的TIANCHI-全球城市计算挑战赛-完整方案及关键代码分享(季军)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 首发:一份国内机器学习爱好者的性别比例的
- 下一篇: 推荐ApacheCN开源的一个机器学习路