之前參加了kaggle的一個Santander Customer Transaction Prediction比賽,共有達9038支隊伍參賽,一個號稱尋找magic的比賽。參加比賽的的忘不了被magic這個詞所支配的恐懼...
比賽鏈接 https://www.kaggle.com/c/santander-customer-transaction-prediction/overview
也算是第一次kaggle正式的做比賽吧,之前做了一個kaggle的Quora的文本分類的一個比賽,但是隻做了幾天,最後還沒選成 Final Score,所以最後也不算成績,也不知道排了多少名。
我是前期做了幾天,後來就沒做了,直到最後四天才又開始每天做10個小時大概...
然後自己的成績是 top4% for 9038 teams 。 300/9038
很可惜最後一天模型融合沒跑完比賽時間就截止了,跑完的話能再升100名.....
對自己的成績還算滿意吧。
最後感謝某位大佬的指點和帶飛。
下面來總結一下這個比賽自己的收穫。
<!--more-->
這個比賽訓練集給了20w條數據,共200個特徵,都是數值型特徵,都是匿名特徵,並沒有具體的每個特徵的含義。測試集也是20w條數據。
根據這200個特徵預測每個用戶是否會發生交易。一個2分類問題,最後評估是ROC_AUC。
Magic
這個比賽最最重要的兩個magic其實在討論區和kernel區已經有hint了。
1、其中最重要的就是區分測試集中合成樣本和真樣本。下邊的kernel是某大神提出區分合成樣本和真樣本的方法,通過判斷特徵的唯一值,如果一條樣本中200個特徵值中有一個特徵值在這20w樣本中是unique的,則該樣本是真樣本。通過這個方法劃分出來了10w條真樣本,和10w條合成樣本。具體代碼見下面的kernel。
https://www.kaggle.com/yag320/list-of-fake-samples-and-public-private-lb-split
2、第二個magic就是,frequency encoding 和 count encoding。當然是除去合成樣本,即將train+test_true合起來做特徵。
當然還有一個magic更神奇,只需要短短几行代碼就能到150名。下面再說。
下面貼一下top解決方案
1 Solution
https://www.kaggle.com/c/santander-customer-transaction-prediction/discussion/89003#latest-515385
2nd place solution
可以看到這位大神用了NN和LGB的模型來融合。其實我看很多大神都用了NN模型,NN模型在這個比賽效果還不錯,用的好的話,說不定能拿個金牌呢。
9 Solution
https://www.kaggle.com/c/santander-customer-transaction-prediction/discussion/88913#latest-515121
這位大神,首先將train+test_true合併,然後將unique的特徵用NaN代替,他說能到0.917,後來我自己嘗試分數能直接飆到0.919,什麼概念呢,在100名左右。
然後他繼續拿初始的200個特徵,將count>1的用NaN替代,然後將這400個特徵拼接起來,分數就能達到0.922,然後自己在改改參數,數據增強採樣一下,模型融合我估計能到top50。
賽後總結
當然現在開源的都能達到0.925+了,可以直接去看開源kernel。我只是總結一下自己當時比賽的一些情況。
我也是基於train+test_true做的frenquence encoding特徵,用lgb 十折LB在0.903,這個時候需要調調參數,把num_leaves調小點,結果會更好些。但是我當時沒調..當時時間確實很倉促,很多實驗都沒來得及做,比如沒有用XGB跑一下,用xgb跑的話,參數不改能直接提交達到0.91020.能在200名左右。。
然後最後也沒用上數據採樣增強..其實還是有用的。
最後我跑了lgb+ xgb + nn做stack可惜時間不夠了,第二天5.30定了鬧鐘起來看結果...因爲大概早上八點比賽就截止了,可惜kaggle的kernel只能跑9h,然後時間超了...遂fail...以後還是用服務器跑吧...血的教訓。
比賽結束後,自己將模型融合的結果提交了一波,發現lgb+ xgb + nn做stack,stack第二層 採用十折的Ridge效果最好。可惜當時時間不夠沒能提交。但是我當時NN的效果不好,只有0.89754的score。所以結果也不是太好,如下圖。
自己也嘗試了stack第二層採用邏輯迴歸,效果差一點..嘗試了xgb×0.7+lgb×0.3也只有0.909。
最好放一下stack的代碼
from sklearn.ensemble import RandomForestClassifier, ExtraTreesClassifier, GradientBoostingClassifier from sklearn.linear_model import BayesianRidge from sklearn.model_selection import StratifiedKFold from sklearn.linear_model import LogisticRegression import numpy as np stack_train = np.vstack([sub_oof['lgboof'], sub_oof['xgboof'],sub_oof['nnoof']]).transpose() stack_test = np.vstack([sub_pred['lgb_target'],sub_pred['xgb_target'],sub_pred['nn_target']]).transpose() folds = StratifiedKFold(n_splits=10, shuffle=False, random_state=42) oof_stack = np.zeros(len(sub_oof)) pred_ = np.zeros(len(test)) target = sub_oof['target'] ## LR for fold_, (trn_idx, val_idx) in enumerate(folds.split(stack_train, target.values)): print("Fold :{}".format(fold_ + 1)) clf = LogisticRegression(random_state=42, n_jobs=8).fit(stack_train[trn_idx], target.iloc[trn_idx]) oof_stack[val_idx] = np.array(clf.predict_proba(stack_train[val_idx]))[:, 1] pred_ += np.array(clf.predict_proba(stack_test))[:, 1] / folds.n_splits print("Stackinglr_CV score: {:<8.5f}".format(roc_auc_score(target, oof_stack))) ## Ridge oof_stack2 = np.zeros(len(sub_oof)) pred_2 = np.zeros(len(test)) for fold_, (trn_idx, val_idx) in enumerate(folds.split(stack_train, target.values)): print("Fold :{}".format(fold_ + 1)) clf = BayesianRidge().fit(stack_train[trn_idx],target.iloc[trn_idx]) oof_stack2[val_idx] = clf.predict(stack_train[val_idx]) pred_2 += (clf.predict(stack_test)) / folds.n_splits print("StackingBayes_CV score: {:<8.5f}".format(roc_auc_score(target, oof_stack2)))
收穫
之前自己一直處於眼高手低...比如xgb、lgb只僅限看了看別人的總結原理看了看官方文檔,並沒有去深究原理論文,各有什麼優點,但是參加了這個比賽,我去詳細讀了xgb、lgb的論文,哈哈主要是因爲當時在討論區大家都在討論爲什麼這些特徵有用,lgb能學到什麼不能學到什麼,懷着這樣的好奇心去讀了讀論文。其實本來還想寫一下GBDT、XGB、LGB各自的原理優缺點的,但是看了看網上這類文章很多...所以便沒有去寫了。。打算等之後空閒了可以在重複造個輪子寫一寫,也算是在複習一遍了。