這次和一群好友在科賽網上參加了攜程的客戶流失概率預測比賽,最終33名完賽,雖然依然是渣渣成績,但又認識了好多大神,學到了不少東西。
這次這個比賽其實難點還不少,首先就是評分規則與眾不同,本來以為會用AUC或者F1 score之類的,但官方用的是precision≥97%下,recall的最大值。起初也不知道如何自定義metric,只能用一些默認的,跟線上完全對應不起來,很摸瞎。
一開始只覺得是簡單的分類問題,也沒太多想,處理一下特征,先跑個分類器吧。自從上次在天池吃癟了之后,這次在特征處理上算是好好下了些功夫,比如一些離散特征這回知道用啞變量處理了,當年真是naïve啊……有一些離散特征,比如decisionhabit_user(用戶行為類型)這種,有成百上千種,如果每個都對應一個dummy似乎不太實際,於是先觀察一下數據,發現>40的只占很少的比例,所以>40的都指定為50(這個值其實無所謂,你指定成10000都沒事),然后用0來填充nan(原來的decisionhabit_user里沒有0這個值),再用pd.get_dummies來轉化為啞變量矩陣。除此之外,諸如酒店價格、客戶的星級偏好、消費能力這些雖然都是連續特征,但可以通過分段來轉化為離散變量,比如0-20一段,20-40一段諸如此類。
此外,這個比賽另一個很蛋疼的地方就是數據缺失很多,填充這件事情真是讓人絞盡腦汁。擱以前估計我就全填0了,但這幾個月還是略有所學,知道填0 too simple!還是得觀察數據先。主要通過觀察每個特征的分布情況,比如值域,形態神馬的。Pandas里可以寫一句
df.a.value_counts().sort_index().plot()
來簡單地畫個圖了解一下特征的情況。有些填0明顯不合理,可以考慮用均值或中值填充(中值跟適合偏倚嚴重的數據)。后來又聽高手說了拉格朗日插值法來填充nan,頓感高大上,scipy里可以掉包,但似乎運行速度比較慢(時間復雜度貌似是平方級還是立方級來着),但發現可以嘗試一下簡單的線性插值
from scipy.interpolate import interp1d
這樣可以用不含nan的A特征來填充含有nan的B特征,前提當然是兩者要強相關啦。像消費能力和用戶價值這種就可以互相填充。
最后實在想不出辦法的就填0吧……另外第一次知道原來一行里na的數量也可以作為一個特征。
特征處理完差不多275個,想想以前只能做出幾個特征來,原來是打開方式不對啊……由於特征數量不算太多,所以也沒有用PCA之類的進行特征選擇,用MinMaxScaler縮放了一下之后(考慮到萬一要用線性模型)就直接放進算法里滾。一開始用了RF,但效果並不好,后來轉用xgboost,才發現原來大家都在用嘛~此間也在國外網站上找到了xgboost中自定義metric的方法,詳細可見:
http://www.cnblogs.com/silence-gtx/p/5812012.html
經過一波調參之后發現怎么也上不了0.05,線下似乎可以做到0.30+,感覺不是很科學,后來經世超大神指點才知道原來是不收斂了……訓練集和驗證集都在不斷上升,但線下不錯線上卻很差。之后又遇到一位朋友來交流,說可以用參數換特征,想想我特征也做得不好,換就換吧~得到了兩個很重要的信息,一個是訓練集和驗證集的划分不能隨機抽樣,而是要按天來划分,因為原題中有這樣一句話:如果用戶小王在2016年5月20日按照順序訪問了A,B,C,D四家酒店,最后選擇了D下單。則對應我們的數據,他會產生4條記錄(即4個sampleId),四條記錄的label都會為1。如果隨機抽樣的話,會割裂這樣的記錄,使准確性大幅下降。另外一個重要的信息就是xgb有個參數scale_pos_weight,這個參數可以均衡你結果中0與1的比例,他給了我一個值,雖然這下xgboost訓練時收斂了,但結果並不理想……后來還是世超大神告訴我要保證xgb預測訓練集和驗證集的0-1比例與它們真實的0-1比例非常接近。比如說,原來驗證集0-1比例是3:1,那你的分類器訓練完之后再預測驗證集,其0-1比例也應當非常接近3-1。通過調節這個參數再搭配上其他參數終於上了0.06,也發現原來這個參數根據特征的不同其取值是不同的(有人是0.50+,而我的是1.80)。最后幾天嘗試了一下模型融合,但效果並不理想,最后也就停留在33了。
這次比賽感覺把自己三個月來學到的大招全都放完了,卻又學到了很多新的大招~感謝這一路上一起交流的朋友們,感謝樂於分享的各位大神,沒有你們我還是個戰五渣,現在好歹是戰六渣了~