天池---智慧交通預測挑戰賽總結(一)

2017/07 -- 2017/09 天池智慧交通預測賽思路及模型總結(一)


說在前面的話


ML的建模方法和數據處理方法看來是一個CS專業學生必備的技能了,但是課余時間單純的學習一些基礎的模型感覺并沒有實質性的進展,因此,決定在暑期參加一次比賽來更好地學習這樣一個領域。本篇博客就是為了自己整理一下暑期比賽的材料,思路簡要概述一下,然后附上源碼。有興趣的同學希望我們一起探討。
(ps:整體選用了三種模型,本篇博客先總結傳統機器學習模型:xgb和LGBM,關于LSTM和static后續再上。)

比賽鏈接: https://tianchi.aliyun.com/competition/introduction.htmspm=5176.100066.0.0.7dc8b4bacGhJST&raceId=231598

關于數據,如果需要的同學可以私信我。

第一賽季排名:61
復 賽 排 名: 12
隊員:moka,LRain,過把火

只可惜天池的比賽跟京東的不相同,只能前五名進決賽,區區千分位的差距,心里還是感覺有些不甘。


1 賽題介紹


移動互聯網時代的開啟使得每個出行者都成為了交通信息的貢獻者,超大規模的位置數據在云端進行處理和融合生成城市全時段,無盲區的交通信息。本屆算法挑戰賽以“移動互聯時代的智慧交通預測”為主題,邀請參賽者基于互聯網交通信息建立算法模型,精準預測各關鍵路段在某個時段的通行時間,實現對交通狀態波動起伏的預判,助力社會智慧出行和城市交通智能管控。組委會將通過計算參賽者提交預測值和記錄真實值之間的誤差確定預測準確率,評估所提交的預測算法。

1.1 數據源

移動APP數據實時匿名收集用戶地理位置信息, 處理和融合生成城市全時段,無盲區的交通信息。本次大賽將提供城市關鍵路段(link)的屬性信息,路段間網絡拓撲結構以及每條路段在歷史各時間段內的通行時間,供參賽者建立和測試算法模型。

1.2 數據介紹

a. 路段(link)屬性表
每條道路的每個通行方向由多條路段(link)構成,數據集中會提供每條link的唯一標識,長度,寬度,以及道路類型,如表1所示;圖1示例了地面道路link1和link2的屬性信息。

b. link上下游關系表
link之間按照車輛允許通行的方向存在上下游關系,數據集中提供每條link的直接上游link和直接下游link,如表2所示;圖2示例了link2的in_links和out_links。

c. link歷史通行時間表
數據集中記錄了歷史每天不同時間段內(2min為一個時間段)每條link上的平均旅行時間,每個時間段的平均旅行時間是基于在該時間段內進入link的車輛在該link上的旅行時間產出。字段解釋如表3所示:

1.3 目標說明

其實初賽跟復賽的要求是一樣的,都是基于已給數據來預測未來一段時間內的交通流量的情況。
初賽是預測2016年6月份[8:00-9:00)每條link上每兩分鐘時間片的平均旅行時間。
復賽:
復賽第一階段
預測2017年7月1日至7月15早高峰、日平峰和晚高峰三個時段中各一個小時的數據,預測時段為:

  1. 早高峰: [8:00 - 9:00)
  2. 日平峰: [15:00 - 16:00)
  3. 晚高峰: [18:00 - 19:00)

復賽第二階段
預測2017年7月1日至7月31早高峰、日平峰和晚高峰三個時段中各一個小時的數據,預測時段為:

  1. 早高峰:[8:00 - 9:00)
  2. 日平峰:[15:00 - 16:00)
  3. 晚高峰:[18:00 - 19:00 )

1.4 評估指標

指標說明:
ttp : 參賽者提交的預測通行時間
ttr: 真實通行時間
N: 預測link數量
T_i: 第i個link上的預測時間片數量
MAPE值越低說明模型準確度越高。

1.5 模型架構:

我們的模型分為三個:
LightGBM
LSTM
Static(線性規則)


2 賽題分析

1、首先我們根據題目要求可以基本判斷這是一道回歸預測問題。
2、其次我們還可以很容易看出來賽題數據與時間序列相關,結合數據量還算較大,因此可以考慮使用LSTM。
3、原始數據的維數并不是很大,因此特征的挖掘局限但也較為容易,對于傳統的機器學習模型,xgboost和LightGBM都可以考慮拿來做baseline。
4、預測難點:
可能我們第一想法就是進行單點預測,也就是前一個來預測后一個,但是問題要求我們一次性預測出連續時間段的結果,即使這樣,可能我們也會嘗試去一個個預測,再將前一個預測值拿來預測后一個,但是這樣的誤差堆積會導致結果越來越差。經實驗表明,單點預測到第四個的時候,誤差就已經超出可接受范圍了。
因此我們考慮利用前一段時間的數據來將目標連續結果一起給出。這樣我們的數據貢獻來自于全部的前一段時間的數據,這樣的構造要求我們必須足夠好地去構造歷史數據以及前一段時間的數據。

有以上基本認識后,這個比賽的大致方向其實就差不多了,事實證明賽后top同學的思路也是這樣的,只是差別在于特征冊處理以及模型的調參。


3 數據分析

首先對數據進行一個大致的查閱。

3.1 數據可視化

借助Tableau,對數據進行了較為直觀的查閱。尤其是對于這些時序性數據,可視化的方法能夠給我們一個較為全面的參考和對比。
針對道路數據的特性,我們著重在Tableau上對同期數據進行對比,尤其是不同月的相同小時及分鐘的數據,一是為了驗證同期車流量整體趨勢是否上升或下降的猜想,而是為了選取合適的粗細粒度來設計統計特征。如下圖所示

上圖著重選取了幾條具有不同時序特征的道路進行分析,從圖中可以明顯看出大多數路段同期單位小時內的趨勢基本相似,但仍存在類似于淺藍色道路這種每個月趨勢性信息不明顯的道路。考慮到車流量受星期因素影響較大,因此我們又在工作日、周末維度對數據進行分析。如下圖所示:

在對數據細分到每周的星期之后,發現相同的道路受星期的因素較大,可以猜想,某些位于工業園區的道路周末由于休假的緣故,因此車流量在低位平緩,但在工作日會在早晚高峰呈現擁堵的情況;相反,對于某些靠近商業區或是休閑區的道路,工作日游客較少,因此相對較為平緩,但在周末甚至周五晚上,這些道路會出現較大的起伏。這樣的特點也在一定程度上幫助我們在設計線性加權模型時,將星期的因素進行單獨考慮。

3.2 離群點

監測數據的準確性以及個別抽樣算法所導致的數據誤差是不可避免的,我們在觀測了全部數據后的確發現有這樣數據的存在,因此,我們采用outliers的方式,剔除了首尾95%分位點的數據。

3.3 缺失值

時序數據的缺失很常見,目前也有很多研究是針對這一方面進行研究,例如我們實驗室的鄭宇老師(目前是微軟亞研院的主要負責人之一),他所做的城市計算方向中包含了城市時空數據缺失值的填補方向,具體可參閱鄭宇老師的主頁。

對于這一賽題的數據來說,由于只有單維數據(時域數據),而沒有空間或是其他相關數據,因此我們選擇填充的空間就比較有限。最終我們選用了前后均值來替代中間的缺失值。對于某些有頭無尾或是有尾無頭的數據,我們就選用最近鄰的數據來替代。

4 特征工程

特征工程可參考如下流程圖


image.png

4.1 嘗試

數據為時間序列數據,起初嘗試LGBM + 原始數據的前30個點來預測后30個點,但是效果很差(除了第一個點),打印出前30個點的特征重要性發現,只有最后2個點的重要性最高,前面的28個點都幾乎很小,因此放棄使用純原始數據來做時間序列預測。
(ps:因為不懂時間序列預測,所以后來發現在做時間序列預測的時候,不能直接使用純原始值,需要加上額外的統計特征)

4.2 時間特征

由于是是時序數據,因此我們首先要對時間進行挖掘。因為只有時間給好了相關的數據處理才好進行,例如一些groupby等聚合操作。這里要感謝河北工大-“麻婆豆腐”學長的支援。代碼如下:

def AddBaseTimeFeature(df):
    df['time_interval_begin']=pd.to_datetime(df['time_interval'].map(lambdax:x[1:20]))
    df=df.drop(['date','time_interval'],axis=1)
    df['time_interval_month']=df['time_interval_begin'].map(lambdax:x.strftime('%m'))
    df['time_interval_day']=df['time_interval_begin'].map(lambdax:x.day)
    df['time_interval_begin_hour']=df['time_interval_begin'].map(lambdax:x.strftime('%H'))
    df['time_interval_minutes']=df['time_interval_begin'].map(lambdax:x.strftime('%M'))
    #Monday=1,Sunday=7
    df['time_interval_week']=df['time_interval_begin'].map(lambdax:x.weekday()+1)
    df['time_interval_point_num']=df['time_interval_minutes'].map(lambdax:str((int(x)+2)/2))
return df

link_info=pd.read_table(data_path+'/new_data'+'/gy_contest_link_info.txt',sep=';',dtype={'link_ID':'str'})
link_info=link_info.sort_values('link_ID')
training_data=pd.read_table(data_path+'/new_data'+'/gy_contest_traveltime_training_data_second.txt',sep=';',dtype={'link_ID':'str'})
feature_data=pd.merge(training_data,link_info,on='link_ID')
feature_data=feature_data.sort_values(['link_ID','time_interval'])
print('正在生成最終特征矩陣')
feature_data_date=AddBaseTimeFeature(feature_data)
print('正在寫最終特征矩陣')
feature_data_date.to_csv(data_path+'/new_data'+'/feature_data_2017.csv',index=False)

print('正在讀特征矩陣')
feature_data=pd.read_csv(data_path+'/data'+'/feature_data_2017_without_missdata.csv',dtype={"link_ID":str})##指定linkID為str(Object),方便對其進行oneHot
week=pd.get_dummies(feature_data['time_interval_week'],prefix='week')
delfeature_data['time_interval_week']
print('特征矩陣與week-oneHot拼接')
feature_data=pd.concat([feature_data,week],axis=1)

##加入每個點是第幾個點的類別信息
print('特征矩陣與point_num拼接')
point_num=pd.get_dummies(feature_data['time_interval_point_num'],prefix='point_num')
delfeature_data['time_interval_point_num']
feature_data=pd.concat([feature_data,point_num],axis=1)

4.3 travel_time 統計特征的處理

嘗試使用統計特征的時候,一股腦將常用的統計指標全部算出來,包括mean,mode,std,max,min等,同時外加前一個月此處需要感謝豆腐大佬(@麻婆豆腐)的代碼共享(初賽還沒結束,豆腐就把自己的源代碼貢獻在技術圈),Python代碼部分沒有很難懂的地方,但還是需要一點Dataframe的操作知識,其實多用幾次基本就爛熟于心。在前期對原始數據進行了日期格式處理的基礎上,我們開始進行統計值的特征處理部分。特征處理部分的代碼如下:

需要注意的是,為了對特征進行歸一化處理,我們將所有的數據在訓練前都做了ln處理,使其更近似服從正態分布。然后在最后將其預測值做exp處理,使其返回原始值。

根據時間特征,為了極大化前段時間數據對后面一段時間連續數據的影響,采用了滑窗方法來對前一段時間的travel_time進行處理。

    '''
    train data 4月訓練
    '''
    train = pd.DataFrame()
    train4 = pd.DataFrame()
    for curHour in [8,15,18]:
        print("train4 curHour", curHour)
        trainTmp = feature_data.loc[(feature_data.time_interval_month == 4)&
               (feature_data.time_interval_begin_hour==curHour)
              # &(feature_data.time_interval_day<=15)
               ,:]
    
        for i in [58,48,38,28,18,0]:
            tmp = feature_data.loc[(feature_data.time_interval_month == 4)&
                    (feature_data.time_interval_begin_hour==curHour-1)
                                            &(feature_data.time_interval_minutes >= i),:]
            tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                    'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                        ('mode_%d' % (i), mode_function)]).reset_index()
            #train = pd.merge(train,tmp,on=['link_ID','time_interval_day','time_interval_begin_hour'],how='left')
            trainTmp = pd.merge(trainTmp,tmp,on=['link_ID','time_interval_day'],how='left')
            
        train4 = pd.concat([train4,trainTmp], axis=0)
        print("     train4.shape", train4.shape)
    
    train4_history = feature_data.loc[(feature_data.time_interval_month == 3),: ]
    train4_history = train4_history.groupby(['link_ID', 'time_interval_minutes'])[
                'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                    ('mode_m', mode_function)]).reset_index()
    
    train4 = pd.merge(train4,train4_history,on=['link_ID','time_interval_minutes'],how='left')
    
    train_history2 = feature_data.loc[(feature_data.time_interval_month == 3),: ]
    train_history2 = train_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
                'travel_time'].agg([ ('median_h', np.median),
                                    ('mode_h', mode_function)]).reset_index()
                
    train4 = pd.merge(train4, train_history2,on=['link_ID','time_interval_begin_hour'],how='left')
    print("train4.shape", train4.shape)
    train = train4
    
    train_label = np.log1p(train.pop('travel_time'))
    train_time = train.pop('time_interval_begin')
    
    train.drop(['time_interval_month'],inplace=True,axis=1)
    train_link=train.pop('link_ID') #(253001, 35)
    print("train.shape", train.shape)
    
    '''
    test   評測6月整月    
    '''
    
    test = pd.DataFrame()
    for curHour in [8,15,18]:
        print("test curHour", curHour)
        testTmp = feature_data.loc[(feature_data.time_interval_month == 6)&
               (feature_data.time_interval_begin_hour==curHour)
               ,:]
    
        for i in [58,48,38,28,18,0]:
            tmp = feature_data.loc[(feature_data.time_interval_month == 6)&
                    (feature_data.time_interval_begin_hour==curHour-1)
                                            &(feature_data.time_interval_minutes >= i),:]
            tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                    'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                        ('mode_%d' % (i), mode_function)]).reset_index()
            testTmp = pd.merge(testTmp,tmp,on=['link_ID','time_interval_day'],how='left')
        
        test = pd.concat([test,testTmp], axis=0)
        print("test.shape", test.shape)
    
    test_history = feature_data.loc[(feature_data.time_interval_month == 5),: ]
    test_history = test_history.groupby(['link_ID', 'time_interval_minutes'])[
                'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                    ('mode_m', mode_function)]).reset_index()
    
    test = pd.merge(test,test_history,on=['link_ID','time_interval_minutes'],how='left')
    
    test_history2 = feature_data.loc[(feature_data.time_interval_month == 5),: ]
    test_history2 = test_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
                'travel_time'].agg([ ('median_h', np.median),
                                    ('mode_h', mode_function)]).reset_index()
                
    test = pd.merge(test,test_history2,on=['link_ID','time_interval_begin_hour'],how='left')
    
    test_label = np.log1p(test.pop('travel_time'))
    test_time = test.pop('time_interval_begin')
    
    
    test.drop(['time_interval_month'],inplace=True,axis=1)
    
    #去掉link_ID
    test_link=test.pop('link_ID')


5 機器學習模型

我們首先使用了競賽中的兩大殺器:xbg和LGBM.
模型我就不介紹了畢竟真的太出名了。
具體的實現流程如下圖:

訓練集使用前面特征選取部分提到的3月和4月的數據,測試集分別有5月下半月和6月一整月。
在訓練過程中的驗證集test我們傳入的是6月一整月,只不過在最后我們會預測出5月下半月和6月一整月的數據作為輸出,以便手動在計算一次MAPE指標。
下面我只給出源碼。

需要注意的是,我們需要自定義MAPE的損失函數,如下:

def mape_ln(y,d):
    c=d.get_label()
    result= -np.sum(np.abs(np.expm1(y)-np.abs(np.expm1(c)))/np.abs(np.expm1(c)))/len(c)
    return "mape",result
其中y為預測值,d為真實值

xgboost訓練、驗證及預測源碼:

import xgboost as xgb
xlf = xgb.XGBRegressor(max_depth=8,
                       learning_rate=0.01,
                       n_estimators=1000,
                       silent=True,
                       objective=mape_object,
                       #objective='reg:linear',
                       nthread=-1,
                       gamma=0,
                       min_child_weight=6,
                       max_delta_step=0,
                       subsample=0.9,
                       colsample_bytree=0.8,
                       colsample_bylevel=1,
                       reg_alpha=1e0,
                       reg_lambda=0,
                       scale_pos_weight=1,
                       seed=9,
                       missing=None)

xlf.fit(train.values, train_label.values, eval_metric=mape_ln, 
        verbose=True, eval_set=[(test.values, test_label.values)],
        early_stopping_rounds=10)


'''
預測sub,并保存結果   5月下
'''
sub = pd.DataFrame()
for curHour in [8,15,18]:
    print("sub curHour", curHour)
    subTmp = feature_data.loc[(feature_data.time_interval_month == 5)&
           (feature_data.time_interval_begin_hour==curHour)
           #&(feature_data.time_interval_day>15)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 5)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        subTmp = pd.merge(subTmp,tmp,on=['link_ID','time_interval_day'],how='left')
    
    sub = pd.concat([sub,subTmp], axis=0)
    print("sub.shape", sub.shape)

sub_history = feature_data.loc[(feature_data.time_interval_month == 4),: ]
sub_history = sub_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

sub = pd.merge(sub,sub_history,on=['link_ID','time_interval_minutes'],how='left')

sub_history2 = feature_data.loc[(feature_data.time_interval_month == 4),: ]
sub_history2 = sub_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
sub = pd.merge(sub,sub_history2,on=['link_ID','time_interval_begin_hour'],how='left')
sub_label = np.log1p(sub.pop('travel_time'))
sub_time = sub.pop('time_interval_begin')

sub.drop(['time_interval_month'],inplace=True,axis=1)
#去掉link_ID
sub_link = sub.pop('link_ID')

#預測
sub_pred = xlf.predict(sub.values, ntree_limit=xlf.best_iteration)
mape_ln1(sub_pred, sub_label) #('mape', -0.27325180044232567)

sub_out = pd.concat([sub_link, sub], axis=1)
sub_out = pd.concat([sub_out,np.expm1(sub_label)],axis=1)
sub_out['xgb_pred'] = np.expm1(sub_pred)
sub_out.to_csv('./predict_result/xgb_pred_m5.csv', index=False)

'''
預測sub,并保存結果   6月整月
'''
sub = pd.DataFrame()
for curHour in [8,15,18]:
    print("sub curHour", curHour)
    subTmp = feature_data.loc[(feature_data.time_interval_month == 6)&
           (feature_data.time_interval_begin_hour==curHour)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 6)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        subTmp = pd.merge(subTmp,tmp,on=['link_ID','time_interval_day'],how='left')
    
    sub = pd.concat([sub,subTmp], axis=0)
    print("sub.shape", sub.shape)

sub_history = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history = sub_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

sub = pd.merge(sub,sub_history,on=['link_ID','time_interval_minutes'],how='left')

sub_history2 = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history2 = sub_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
sub = pd.merge(sub,sub_history2,on=['link_ID','time_interval_begin_hour'],how='left')
sub_label = np.log1p(sub.pop('travel_time'))
sub_time = sub.pop('time_interval_begin')

sub.drop(['time_interval_month'],inplace=True,axis=1)
#去掉link_ID
sub_link = sub.pop('link_ID')

#預測
sub_pred = xlf.predict(sub.values, ntree_limit=xlf.best_iteration)
mape_ln1(sub_pred, sub_label)

sub_out = pd.concat([sub_link, sub], axis=1)
sub_out = pd.concat([sub_out,np.expm1(sub_label)],axis=1)
sub_out['xgb_pred'] = np.expm1(sub_pred)
sub_out.to_csv('./predict_result/xgb_pred_m6.csv', index=False)

'''
預測sub,并保存結果   7月上
'''
sub = pd.DataFrame()
for curHour in [8,15,18]:
    print("sub curHour", curHour)
    subTmp = feature_data.loc[(feature_data.time_interval_month == 7)&
           (feature_data.time_interval_begin_hour==curHour)
          # &(feature_data.time_interval_day<=15)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 7)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        subTmp = pd.merge(subTmp,tmp,on=['link_ID','time_interval_day'],how='left')
    
    sub = pd.concat([sub,subTmp], axis=0)
    print("sub.shape", sub.shape)

sub_history = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history = sub_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

sub = pd.merge(sub,sub_history,on=['link_ID','time_interval_minutes'],how='left')

sub_history2 = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history2 = sub_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
sub = pd.merge(sub,sub_history2,on=['link_ID','time_interval_begin_hour'],how='left')
sub_label = np.log1p(sub.pop('travel_time'))
sub_time = sub.pop('time_interval_begin')

sub.drop(['time_interval_month'],inplace=True,axis=1)
#去掉link_ID
sub_link = sub.pop('link_ID')

#預測
sub_pred = xlf.predict(sub.values, ntree_limit=xlf.best_iteration)
mape_ln1(sub_pred, sub_label)

sub_out = pd.concat([sub_link, sub], axis=1)
sub_out = pd.concat([sub_out,np.expm1(sub_label)],axis=1)
sub_out['xgb_pred'] = np.expm1(sub_pred)
sub_out.to_csv('./predict_result/xgb_pred_m7.csv', index=False)

LGBM訓練及預測:

# 中位數
def mode_function(df):
    counts = mode(df)
    return counts[0][0]

feature_data = pd.read_csv('E:/data/all_data_M34567.csv',dtype={'link_ID':str})

'''
train data 4月訓練
'''

train = pd.DataFrame()
train4 = pd.DataFrame()
for curHour in [8,15,18]:
    print("train4 curHour", curHour)
    trainTmp = feature_data.loc[(feature_data.time_interval_month == 4)&
           (feature_data.time_interval_begin_hour==curHour)
          # &(feature_data.time_interval_day<=15)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 4)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        
        trainTmp = pd.merge(trainTmp,tmp,on=['link_ID','time_interval_day'],how='left')
        
    train4 = pd.concat([train4,trainTmp], axis=0)
    print("     train4.shape", train4.shape)

train4_history = feature_data.loc[(feature_data.time_interval_month == 3),: ]
train4_history = train4_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

train4 = pd.merge(train4,train4_history,on=['link_ID','time_interval_minutes'],how='left')

train_history2 = feature_data.loc[(feature_data.time_interval_month == 3),: ]
train_history2 = train_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([ ('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
train4 = pd.merge(train4, train_history2,on=['link_ID','time_interval_begin_hour'],how='left')
print("train4.shape", train4.shape)
train = train4

train_label = np.log1p(train.pop('travel_time'))
train_time = train.pop('time_interval_begin')

train.drop(['time_interval_month'],inplace=True,axis=1)
train_link=train.pop('link_ID') #(253001, 35)
print("train.shape", train.shape)

'''
test   評測6月整月    [374]   valid_0's mape: 0.284432
'''

test = pd.DataFrame()
for curHour in [8,15,18]:
    print("test curHour", curHour)
    testTmp = feature_data.loc[(feature_data.time_interval_month == 6)&
           (feature_data.time_interval_begin_hour==curHour)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 6)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        testTmp = pd.merge(testTmp,tmp,on=['link_ID','time_interval_day'],how='left')
    
    test = pd.concat([test,testTmp], axis=0)
    print("test.shape", test.shape)

test_history = feature_data.loc[(feature_data.time_interval_month == 5),: ]
test_history = test_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

test = pd.merge(test,test_history,on=['link_ID','time_interval_minutes'],how='left')

test_history2 = feature_data.loc[(feature_data.time_interval_month == 5),: ]
test_history2 = test_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([ ('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
test = pd.merge(test,test_history2,on=['link_ID','time_interval_begin_hour'],how='left')

test_label = np.log1p(test.pop('travel_time'))
test_time = test.pop('time_interval_begin')


test.drop(['time_interval_month'],inplace=True,axis=1)

#去掉link_ID
test_link=test.pop('link_ID')


def mape_ln1(y,d):
    #c=d.get_label()
    c=d
    result= -np.sum(np.abs(np.expm1(y)-np.abs(np.expm1(c)))/np.abs(np.expm1(c)))/len(c)
    return "mape",result


def mape_object(d,y):
    # print(d)
    # print(y)
    grad=1.0*(y-d)/d
    hess=1.0/d
    return grad,hess


def mape_ln_gbm(d,y):
    # c=d.get_label()
    result=np.sum(np.abs(np.expm1(y)-np.abs(np.expm1(d)))/np.abs(np.expm1(d)))/len(d)
    return "mape",result,False


import lightgbm as lgb
lgbmodel = lgb.LGBMRegressor(num_leaves=32,
                             # max_depth=9,
                             max_bin=511,
                       learning_rate=0.01,
                       n_estimators=2000,
                       silent=True,
                       objective=mape_object,
                       min_child_weight=6,
                       colsample_bytree=0.8,
                       reg_alpha=1e0,
                       reg_lambda=0)
lgbmodel.fit(train.values, train_label.values, eval_metric=mape_ln_gbm,
        verbose=True, eval_set=[(test.values, test_label.values)],
        early_stopping_rounds=100)
pred = lgbmodel.predict(test.values, num_iteration= lgbmodel.best_iteration)


'''
預測sub,并保存結果   5月下
'''

test
sub = pd.DataFrame()
for curHour in [8,15,18]:
    print("sub curHour", curHour)
    subTmp = feature_data.loc[(feature_data.time_interval_month == 5)&
           (feature_data.time_interval_begin_hour==curHour)
        #   &(feature_data.time_interval_day>15)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 5)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        subTmp = pd.merge(subTmp,tmp,on=['link_ID','time_interval_day'],how='left')
    
    sub = pd.concat([sub,subTmp], axis=0)
    print("sub.shape", sub.shape)

sub_history = feature_data.loc[(feature_data.time_interval_month == 4),: ]
sub_history = sub_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

sub = pd.merge(sub,sub_history,on=['link_ID','time_interval_minutes'],how='left')

sub_history2 = feature_data.loc[(feature_data.time_interval_month == 4),: ]
sub_history2 = sub_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
sub = pd.merge(sub,sub_history2,on=['link_ID','time_interval_begin_hour'],how='left')
sub_label = np.log1p(sub.pop('travel_time'))
sub_time = sub.pop('time_interval_begin')

sub.drop(['time_interval_month'],inplace=True,axis=1)
#去掉link_ID
sub_link = sub.pop('link_ID')

#預測
sub_pred = lgbmodel.predict(sub.values, num_iteration= lgbmodel.best_iteration)
#mape_ln1(sub_pred, sub_label)   ('mape', -0.27112186522435494)

sub_out = pd.concat([sub_link, sub], axis=1)
sub_out = pd.concat([sub_out,np.expm1(sub_label)],axis=1)
sub_out['gbm_pred'] = np.expm1(sub_pred)
sub_out.to_csv('./predict_result/gbm_pred_m5.csv', index=False)


'''
預測sub,并保存結果   6月整月
'''

sub = pd.DataFrame()
for curHour in [8,15,18]:
    print("sub curHour", curHour)
    subTmp = feature_data.loc[(feature_data.time_interval_month == 6)&
           (feature_data.time_interval_begin_hour==curHour)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 6)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        subTmp = pd.merge(subTmp,tmp,on=['link_ID','time_interval_day'],how='left')
    
    sub = pd.concat([sub,subTmp], axis=0)
    print("sub.shape", sub.shape)

sub_history = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history = sub_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

sub = pd.merge(sub,sub_history,on=['link_ID','time_interval_minutes'],how='left')

sub_history2 = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history2 = sub_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
sub = pd.merge(sub,sub_history2,on=['link_ID','time_interval_begin_hour'],how='left')
sub_label = np.log1p(sub.pop('travel_time'))
sub_time = sub.pop('time_interval_begin')

sub.drop(['time_interval_month'],inplace=True,axis=1)
#去掉link_ID
sub_link = sub.pop('link_ID')

#預測
sub_pred = lgbmodel.predict(sub.values, num_iteration= lgbmodel.best_iteration)
#mape_ln1(sub_pred, sub_label)  

sub_out = pd.concat([sub_link, sub], axis=1)
sub_out = pd.concat([sub_out,np.expm1(sub_label)],axis=1)
sub_out['gbm_pred'] = np.expm1(sub_pred)
sub_out.to_csv('./predict_result/gbm_pred_m6.csv', index=False)


'''
預測sub,并保存結果   7月上
'''

sub = pd.DataFrame()
for curHour in [8,15,18]:
    print("sub curHour", curHour)
    subTmp = feature_data.loc[(feature_data.time_interval_month == 7)&
           (feature_data.time_interval_begin_hour==curHour)
         #  &(feature_data.time_interval_day<=15)
           ,:]

    for i in [58,48,38,28,18,0]:
        tmp = feature_data.loc[(feature_data.time_interval_month == 7)&
                (feature_data.time_interval_begin_hour==curHour-1)
                                        &(feature_data.time_interval_minutes >= i),:]
        tmp = tmp.groupby(['link_ID', 'time_interval_day'])[
                'travel_time'].agg([('mean_%d' % (i), np.mean), ('median_%d' % (i), np.median),
                                    ('mode_%d' % (i), mode_function)]).reset_index()
        subTmp = pd.merge(subTmp,tmp,on=['link_ID','time_interval_day'],how='left')
    
    sub = pd.concat([sub,subTmp], axis=0)
    print("sub.shape", sub.shape)

sub_history = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history = sub_history.groupby(['link_ID', 'time_interval_minutes'])[
            'travel_time'].agg([('mean_m', np.mean), ('median_m', np.median),
                                ('mode_m', mode_function)]).reset_index()

sub = pd.merge(sub,sub_history,on=['link_ID','time_interval_minutes'],how='left')

sub_history2 = feature_data.loc[(feature_data.time_interval_month == 5),: ]
sub_history2 = sub_history2.groupby(['link_ID', 'time_interval_begin_hour'])[
            'travel_time'].agg([('median_h', np.median),
                                ('mode_h', mode_function)]).reset_index()
            
sub = pd.merge(sub,sub_history2,on=['link_ID','time_interval_begin_hour'],how='left')
sub_label = np.log1p(sub.pop('travel_time'))
sub_time = sub.pop('time_interval_begin')

sub.drop(['time_interval_month'],inplace=True,axis=1)
#去掉link_ID
sub_link = sub.pop('link_ID')

#預測
sub_pred = lgbmodel.predict(sub.values, num_iteration= lgbmodel.best_iteration)
#mape_ln1(sub_pred, sub_label)

sub_out = pd.concat([sub_link, sub], axis=1)
sub_out = pd.concat([sub_out,np.expm1(sub_label)],axis=1)
sub_out['gbm_pred'] = np.expm1(sub_pred)
sub_out.to_csv('./predict_result/gbm_pred_m7.csv', index=False)

總結

本次就先總結基本用到的特征處理和機器學習模型,重點還是看代碼吧,因為個人時間問題,沒能一氣呵成把所有模型寫完,后面會陸續完善。如有錯誤請大家交流指正。

我的博客 : https://NingSM.github.io

轉載請注明原址,謝謝

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,406評論 6 538
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,034評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,413評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,449評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,165評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,559評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,606評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,781評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,327評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,084評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,278評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,849評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,495評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,927評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,172評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,010評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,241評論 2 375

推薦閱讀更多精彩內容