kaggle | talkingdata廣告反欺詐 top 4% 總結
來自專欄 kaggle玩中學
比賽題目鏈接: TalkingData AdTracking Fraud Detection Challenge
TalkingData是一家中國公司,我將其理解成一個第三方的移動數據平台,移動端的廣告分發是其一個重要業務,其中會出現一些惡意的點擊,這個比賽的意義在於:他們想要通過機器學習的方式抓出其中的欺詐類型的點擊。
紀念一下自己的第一個solo 銀牌
之前有個比賽進過前5%的,不過由於用了兩個賬號在輪番提交,被取消成績了。這次算是記住教訓了,就一個賬號玩,依然solo,排名122/3967,public LB score 0.9898130, private LB 0.9821300, mark一下,離自己的mater目標邁出了重要的一步。
另外值得慶幸的是,這是第5次比賽成績出來後,我的私榜排名是比公榜排名進步的,證明我的模型的泛化能力一直還行,至少是領先於kaggle上的平均水平的。
這次比賽的最後一次ensemble結果提交是在回湖南的火車上完成的,正好看到kaggle社區總積分的新晉No.1--bestfitting的訪談博客,這位同學竟然是長沙人,也是蠻意外的。我努力向老鄉學習吧。
自評:又一場內存的戰役
學到了很多,這些知識大概不會有哪本書籍有寫,也不會有哪個視頻教程說,都是自己摸爬滾打得來的,主要是對於大量數據的存,取,和運算。公司也沒有給我集群機器玩的情況下(放棄spark MLlib),只能自己在谷歌雲上玩了。當自費的玩大容量雲主機的時候,全都按時收費,每一個GB內存和硬碟都要收費,每一個cpu core都收費的情況下,我會格外的在意,我會最大化的利用cpu,內存等"昂貴"資源。窮嘛,省時間就是省錢。
接下來就說一些在有關方面的技巧吧:
- 習慣性的del不再使用的數據,then gc.collect() could save your asshole
- 很多時候調整模型都要考慮使用或者更改不同的特徵,當你有幾十個特徵,每個特徵的存放都會佔用GB級別的資源的時候,不要嘗試一次性處理所有的特徵。一個一個來,180Million的數據,一個特徵,一次開一個進程,只計算一個特徵,比如groupby過程中會爆炸到20多GB的內存,雖然最後計算完結果只有1GB內存
- 不要嘗試將包含所有特徵的大表存成一個文件,將每一個特徵保存成一個單獨文件。之後要用到這個特徵的時候,再讀取進來join到dataframe中。提高靈活性,用哪些我就只載入哪些
- pandas讀取大體積(1GB或者更大)csv文件速度很慢,特別是當我有幾十個特徵,每個特徵都有一兩GB的時候,pandas讀取一個30GB的csv文件所花費的時間,絕對會讓你崩潰。這個時候
pandas.read_feather()
和pandas.to_feather()
是一個很好的方式,直接把一個dataframe的內容,以feather的格式,從內存dump到磁碟,不用管csv的index等等相關參數,就是dump什麼樣的內容到磁碟,讀取回來還是什麼內容在內存,重點是,速度比read_csv快了一個數量級 - 關於pandas計算大量數據有點慢的問題,期間還認真嘗試過dask和pandas on ray兩個開源工具,dask功能齊全一些,在有一些操作比pandas快很多,不過在這次實踐中對我的時間節約沒有太多的幫助,所以沒用。pandas on ray的話,顯然還不太成熟,各種常用函數缺失,遂放棄
- 每一次探索新特徵的時候,一定要有一個較小的可用的可靠的快速的validation的方案,來驗證新的特徵是否有效。不然每次都用全量的數據來計算,時間成本太高
- 每一次運行時間較長的實驗(比如全量數據,比如超小的學習率)之前,一定得有一個debug pipeline,快速走完整個過程
- 養成隨時save model的好習慣。之前做圖像深度學習的時候還知道存下很多個epoch完畢之後的模型文件,沒成想lightGBM在遇到稍微大點的數據集的也會有各種坑。比如有時候會遇到訓練到一半,內存炸了,程序崩了,比如有時候會train完畢後沒有及時清理刪除訓練數據集,predict的時候內存炸了。想起mxnet的李沐博士的視頻里說的,我就是不小心把整棟機房弄停電了嘛,你們跑了三四天的程序都不保存中間模型,那能怪我嘍,誰叫你們不隨時保存的
- 哎呀,說多了都是淚,對於我個人來說都是浪費的錢啊,以後想起來什麼淚點,我再補充到這個段落來
他山之石,可以攻玉
欣賞大神們的玩法,都是摘抄了,附名次-id-原文鏈接,部分圓括弧里的內容為我個人評論
3rd, bestfitting, NN based solution
在同時做另外一個google landmark的題目,正好發現最近的NN模型可以用,就在這裡也直接用NN了。(大神就是可以模型廣泛應用到各個業務上,難道以後深度模型要統治所有,徹底打敗樹么)。他的主要嘗試了的是23個特徵,用single LGBM做到了在public LB分數0.9817。(這分數比我最終提交的分數還高),這是他第一次在kaggle里用LGBM。
設計了基於那23個特徵,並且適當處理後(NA, out of vocabulary, scale),用NN做到了公榜0.9820,然後論壇上發現click delta是個重要線索,於是多做了前五個和後五個click的時間序列加到網路里,用RNN來尋找點擊序列的模式,模型可以做到公榜9821了。然後設計了不同的神經網路來增加多樣性,都是很簡單的,比如增加一些殘差鏈接到dense層。四個模型,不單獨考慮分數,只考慮綜合起來的多樣性帶來的提升。在組裝了神經網路和lgbm模型的成績之後,分數到了9827。
再加上n-fold和全部數據。稍微有點花時間了,一個fold就兩個多小時,一塊1080i的GPU.
然後用之前的模型在整個數據集上預測的結果,再加上一些特徵(基於IP的,app-os-channel),做了第二層神經網路,分數到了9833。最後的這個提升做好的時候,離比賽時間結束只有30個小時了,來不及其他改進了,時間限制,NN模型的弱點,等等,就醬。他用到的一些特徵如下:
channel 1011os 544hour 472app 468ip_app_os_device_day_click_time_next_1 320app_channel_os_mean_is_attributed 189ip_app_mean_is_attributed 124ip_app_os_device_day_click_time_next_2 120ip_os_device_count_click_id 113ip_var_hour 94ip_day_hour_count_click_id 91ip_mean_is_attributed 74ip_count_click_id 73ip_app_os_device_day_click_time_lag1 67app_mean_is_attributed 67ip_nunique_os_device 65ip_nunique_app 63ip_nunique_os 51ip_nunique_app_channel 49ip_os_device_mean_is_attributed 46device 41app_channel_os_count_click_id 37ip_hour_mean_is_attributed 21
(可以看出來幾類特徵比較有效,click_time_next,target mean code,count,unique count,還有就是大多特徵都是基於ip和其他特徵組合來的)
為了讓神經網路可以工作,預處理非常重要,如下:1.Fill-NA, Fill max value for delta features, fill mean for other feature
2.Log of delta features. part of count features when values are large and all the nunique features
3.StandardScale
最後他談到了,關於私榜分數估計,我就直接引用過來好了:
As to private score estimation,its always a interesting part of my competition :).
There is not certain method to do so,I just bear in mind:
Distribution variances lead to score variances.For example,in this competition,some category values in test-set are not in trainset,so I changed the same ratio of category value of validation set to values unseen in trainset.And the App19 is a very important app with high ratios of download and is imbalance in train and test-set.Whats more,the ratio is differenct between the public and private set,so I tried to keep the ratio of my validatition as test set...We can also use a submission which I believe it is stable as True label,and caculate AUC based on it,if the public and private score as close,then we can believe it too.
4th, KazAnova, brief tips
先贊一下我的隊友們,無比努力。在贊一下大家。贊一下所有分享代碼和思路的人。特別感謝anttip帶來的wordbatch的kernel,讓大家眼前一亮,簡直了。
我最喜歡拿第一名和第四名了,第一名可以得到最多的點數和錢,第四名沒有那麼多點數,但是不用復現自己的解決方案。(大神對名次的看法就是不一樣,看樣子常拿前幾名,吾等只能最求名次越高越好,沒得選)
我的驗證方案如下:用day78來訓練,用day9的hour[4,14]來做預測。對於測試集的預測,用day789來訓練。
1)當我們開始做stack的時候,可以得到一兩個點的提升,從9818到9820,在用所有特徵加入到我們的標準模型後,加到了3點的提升,到了9823,一共大約50個模型,大部分是lightgbm,也有nn,FMs和線性模型。
2)提升了4個點,厲害了我的哥,用了WoE思路來做特徵工程,各種他們(ip,app,device,os)的組合。發現一個有點奇怪的地方哈,相似的特徵的列的不同的順序,帶來了不同的結果。可能這個和lgbm的binning方式有關。
3)又提升了4點,把group of ip,app,device,os等按照時間排序,同一時間裡同樣的點擊,然後總是把attributed=1的排到最後。
普通的特徵count之類的,groupby不同的組合。比較重要的特徵有next click previous click等等。最重要的特徵,是把app當做categorial來看待。因為可以發現有些app里存在非常高的概率出現is_attributed。極其有效。
6th, CPMP, link
鑒於是個人solo而且數據集還這麼大,那麼一次提交的計算可能要花費數個小時,所以決定只focus一個類型的單模型,LightGBM。時間花費大致如下:80%的時間做特徵工程,10%的時間儘快做好有效的local validation,5%超參數調優,5%組合模型。
花了大量的時間做特徵選擇,由於自己的機器資源,無法搞定50個特徵,要是早點看到這個帖子,那麼有可能使用更多的特徵。
我的最終成績是一個單模型,48個特徵,9825 public and 9835 private, 另外有一個5模型組合的成績更好,不過最後沒有選擇那次submit。我的機器是20核心,64GB內存和64GB swap。機器稍微有點慢了,不過可以有20個線程。我還有另外一個機器是4核心i7+2GPU的用來跑keras。
validation 這個是關鍵,如果沒有一個好的驗證方案,那麼只能靠LB來驗證,就會很容易導致對public LB的過擬合。最後我這麼設置的:用day 8來做訓練,然後用day9-hour4 和 day9-hour5,9,10,13,14兩種方式來做驗證。用所有數據訓練的時候,樹的數量用之前部分數據時的1.2倍。
用兩個驗證集來確保自己沒有嚴重的過擬合。選擇這些小時數據是因為test set里的小時。在早些時候,我也關注了train auc,有些特徵提高了validation的分數,但是同時也拉大了與訓練集分數的gap,放棄掉這部分特徵。後來為了加速訓練,放棄了關注train auc.
同時也關注LB,只有特徵同時提升了local auc和LB,才選用。
這個策略非常有效,用hour4來做驗證機可以做到和LB分數基本一致,或者有大約千分之一的方差。然而,為了獲得earlystopping而一直計算auc,這個是很消耗時間的。為了快速的feature evaluation,我嘗試了兩個加速方案,第一個是:只用day9中,hour4的5%的數據來做validation,其他的用來訓練。這個跑一次只用不到一個小時,用來過濾特徵。這個方案很有效,分數對於LB的分數也有不錯的相關性,但是對於lag類的features不太有效。所以後來我選用day8的數據了。第二個是:每一個feature都分別存放在一個feather文件中。一個特徵一個特徵的添加到訓練中,如果local validation分數至少提升了0.00005才保留這個特徵。也會這麼干,一次添加進來多個特徵,remove one by one。整個比賽期間,就是在不停的選擇特徵。
FE 用了這麼幾類特徵:
- 原始特徵列中,只保留了app和os。這個被當做categorical來處理。這兩個是最強的特徵,第三個強原始特徵類是hour in day
- 中國時間,24小時制,從4pm開始(中國東八區)。這些被用來生成lag feature
- 用戶有關:ip,device,os,triplets
- 不同特徵組的聚合,很多公開kernel里都有,我用的有count, unique count, delta with previous value, next value, time to next click when grouped by user was important.其他有用的但是在公共kernel里沒找到的有,delta with previous app
- Lag feature, 基於中國時區的值,一些group的 previous count,previous target mean
- not last, 這個可以用來抓到leak
- target mean code,也是用來抓leak的。先是group by了user, app, click time等。這類特徵帶來了0.0004到0.0005的提升
- 矩陣因式分解(這個厲害了)。這個是用來捕捉users和app之間的相似性的。首先,構造一個矩陣,log of click counts.我用了這三個:ip x app, user x app, and os x device x app。這些矩陣都極其稀疏。前面兩個,用了sklearn里的svd,,得到ip和user的embedding。對於最後一個,有三個因子,我實現了libfm with keras,也得到了對應的embeddings。有了這五個embedding,給我的分數提升帶來了0.0010.這個直接帶我進入top10了。我在一些不同的模型使用了不同的embedding
超參數調優 沒怎麼調,scale position用的大約為400,為了防止過擬合,31個葉子,深度為8
ENSEMBLE 直接平均的幾個預測。本來想用validation的預測結果,加幾個day9的特徵,來進行訓練,但是時間太久沒搞定。可能即使搞定了也對我的LB提升不大了,畢竟我的模型多樣性很小。看到bestfitting用了這一招,贊他一個
TAKE AWAY kind of crazy for solo people, 對於一個人來說工作量太大了。我很羨慕那些走了同樣的道路的人。一旦solo了,路就不一樣了,或許不solo的話,我可以嘗試更多的數量的特徵。最後,我在最後一天有了很多進展,從9824提升到9832,這告訴我永不放棄(我也是一個人哎,一個人搞這個,確實是有些累的,所有的工作都自己一個人扛)
推薦閱讀:
※雨沐田:不要忽視簡單數據文本的力量
※剪刀石頭布的數據分析闖關之路——仗劍走天涯之鑄劍練劍篇
※給自己一個努力的機會(一)
※數據分析遇到瓶頸?提升銷售管理,思維需要升級!
※Ch3-數據預處理(思維導圖) 171129