從去年11月下旬開始入坑機器學習,到如今也已經有半年了,一開始就是學習機器學習理論方面的知識,可是學到兩三個月的時候總以爲沒點實際操做,因此感到知識點很空洞。本身是自學機器學習的,周圍又沒有實際項目能夠作,能拿來練手的恐怕只有各類數據算法競賽了。今年二月到三月第一次參加了kaggle上的Toxic文本分類比賽,可是因爲自身經驗嚴重不足,和理論知識的淺薄,致使此次比賽幾乎能夠以慘敗收場,雖然最後的排名也是在20%左右,這對於一個機器學習的小白來講也並非很是差,可是總以爲內心的落差仍是挺大的。kaggle的比賽結束不久,還想繼續參加,但是kaggle後來的比賽的數據量實在是太大,動輒幾十個G,仍是未解壓的,本身的渣渣筆記本實在是玩不起。這時候發現天池大數據有個阿里媽媽廣告轉化預估的比賽,看到初賽的數據量比kaggle小多了,而且比賽的背景也很是符合實際的應用,我很是感興趣,就立刻參加了,並積極準備起來。在接近兩個月的比賽的過程當中,數據不斷更換,本身的排名也不斷地跌宕起伏,天天除了看書就是想着怎麼把排名提上去以及怎麼才能進複賽,還好最終也是順利進複賽了,雖然排名比較落後,初賽第346名,不過能進複賽已是很是滿意了,畢竟比賽總共有5200多支隊伍參與,本身仍是個初學者,嗯,也不算不好吧,反正就這麼給本身打氣,但願複賽可以殺進前一百。複賽的數據要比初賽大不少,解壓後數據集有10多個G,這時個人渣渣筆記本又有了巨大的壓力,最後是僅使用了七分之一的訓練數據,要是整個數據都跑恐怕跑個baseline便Memory Error了。固然最後複賽的結果仍是沒能達到預期的前一百名,只有187名,這讓我知道了天池的比賽也是高手如雲,挺進前一百名那是至關不易啊。不過也好在事情是朝着好的方向發展的,畢竟複賽排187也比初賽的346名強不是?仍是在數據難度加大的狀況下,嗯,又來自我安慰了哈哈。閒話很少說,如今稍微總結一下我在天池上的這一場處女賽。代碼地址附在文末。html
此次的比賽的目標是預測商品的轉化率,就是用戶看到這個商品的各類廣告信息來估計這個用戶買這個商品的機率。原始的特徵給出了用戶的id,商品的id,商品所屬的類別和屬性以及上下文等信息,既有類別型特徵又有數值型特徵。評估預測結果的方法是log-loss,具體詳情見比賽網址。git
比賽給出的數據是用前幾天的數據狀況來預測最後一天的狀況,好比給出1到7號的歷史數據,裏面有各類用戶商品的信息做爲特徵,以及給出用戶是否購買的狀況,1爲成交,0爲未成交,因此這就是一個二分類問題。初賽的數據比較小,因此我用了所有的數據進行了訓練,可是複賽數據實在是太大了(對個人機器來講),徹底沒辦法使用所有的數據,僅僅加載數據進去就耗盡了70%多的內存了。這時候有兩種選擇,一種是進行樣本採樣,從原始的樣本數據中採樣出五分之一到八分之一的數據進行訓練,其他的拋棄;另外一種是僅使用最後一天的樣本進行訓練,以前天數的數據所有拋棄。我也不清楚哪種更好,固然,所有數據都保留,一塊訓練那是最好,但是硬件條件不容許。後來對複賽的訓練數據進行了簡單的分析,發現前面幾天的轉化率都差很少,可是最後幾天的轉化率明顯有異常,典型的是倒數最後三天的狀況,倒數第二和第三天的轉化率僅是開始那幾天的一半,而最後一天的轉化率居然是開始那幾天的4倍左右,而讓你預測的那天數據和訓練集最後一天的數據是同一天的,因此我就想這訓練集的最後一天多是相似於雙十一狂歡節這類的日子,只有在雙十一或雙十二的時候用戶會買不少商品,畢竟有活動,看到個優惠廣告就點進去,而後發現價格也不貴,嗯就買了吧,因此形成了那天的轉化率對比平時異常地變高。那麼爲何前兩天轉化率變低了呢,應該是人們早就知道狂歡節有優惠,故而在前兩天看好本身想買的東西,可是不急着買,等打折了再買,只看不買的行爲多了,不就形成了轉化率低了麼。因爲要你預測的日期和訓練集最後一天是同一天的,同時這一天的轉化率和其餘天還不同,某種程度上就是數據的‘分佈’不一樣,個人直覺認爲僅用最後一天進行訓練會比用採樣後的樣本訓練要好,因此就僅使用了訓練集最後一天來做爲訓練集。固然這是否是真的就比使用採樣樣原本訓練要好,就有待於對比檢驗了。github
先講下使用的算法吧,原本這應該是比賽流程中的最後一步,可是我在這方面花的時間很少,使用的也都是廣泛的東西,參數也沒怎麼調,就先說下吧。初賽的時候使用過兩三種算法,對於這種CTR預估的場景,最經典或者說最經常使用的大概就是邏輯迴歸(Logistic Regression, LR)了吧,確實邏輯迴歸算法簡單易用,訓練速度還比較快,獲得的結果精度也能知足大多數應用場合了。可是後面主要使用的算法是LightGBM,這種樹算法的訓練速度很是快,每次大概幾十秒就能夠出結果,保證了訓練的時間效率,關鍵得出的結果精度還挺高,因此當仁不讓地成爲我在此次比賽中的主力模型。隨機森林(Random Forest, RF)在初賽時候也使用了,相對來講它的結果精度不如前兩個模型,log-loss值差的有點多,訓練時間也多了幾倍。總之,初賽時候因爲數據集小,可使用多個模型進行嘗試,也花不了不少時間,就把三個模型都套用了一遍,最後的提交結果是三個預測的結果取的加權平均,按LightGBM,LR,RF依次取0.6,0.3,0.1來的。初賽的結果不如人意我想是本身特徵工程作的不行,複賽時候要注意了(雖然最後也仍是沒找到強特徵)。複賽僅使用了LightGBM這一種模型,沒有和其餘模型進行stack或blend,由於測試LR和RF模型的時候發現結果特別差,再加上時間和機器等雜七雜八的緣由,就沒有嘗試其餘模型了。其餘可用在CTR預估的算法諸如FM,FFM,DeepFM,GBDT+LR等,須要對數據進行必要的處理或者訓練時要GPU加速,本身因爲精力和硬件上的不足,沒有應用,下次要嘗試一下。GBDT+LR的模型其實也是在實際中用的比較多的,主要思想就是利用GBDT利用原始特徵生成一些葉子結點做爲新的特徵再輸入到LR裏,嗯,也算是一種特徵選擇吧,其實這是一種很是好的思想,可是不知爲什麼我在實驗的時候發現效果並很差,可能仍是使用方法上有些問題,當時並未仔細思考追究。下面說下特徵工程。算法
我使用的特徵主要分爲三大類,分別是組合統計特徵,時間差特徵以及轉化率特徵,這部分是本身想得比較多且用的比較多的地方。網絡
就是把各類屬性類別類特徵進行組合,而後統計它們在某一時間段內的行爲。舉個例子,好比user_id和item_id這兩個特徵,分別表明用戶名和商品名,可是同一個用戶可能看過好幾個商品(反過來也成立,即一個商品可能會被多個用戶看過),因此能夠統計該用戶在同一天內看過的商品個數,以及在這一天內,該用戶在看過了某個商品以前已經看過了多少個商品,或者在看某個商品以後還會看多少個商品,這就對這個用戶的行爲進行了必定的統計。固然,統計了同一天內,還能夠再統計一個小時內,一分鐘內,甚至是一秒鐘內用戶看商品的行爲。一秒鐘內一個用戶看好幾個商品的狀況是有可能出現的,緣由多是這個用戶同一秒鐘瘋狂地點擊好多個廣告,或者是由於網絡緣由這個用戶老是點擊同一個廣告,這些都是有可能的。另外,除了統計總數,還能夠統計這個用戶看到的商品有多少是惟一的,例如用戶一天內看了代號爲1,2,2,3,3這一共5個商品,按照上文敘述,這裏會統計爲5,可是惟一的商品只有1,2,3這三種,因此惟一商品的總數爲3,這也能夠做爲一個特徵,再者,兩者的比例一樣也能夠做爲一個特徵,即3/5。同時,這裏也能夠整理出商品的一些特徵,好比代號爲3的商品出現了兩次,那麼這個商品就能夠構造出2/5這樣的特徵,即某個用戶在某個時間段內,他看過的某個商品佔他全部看過的商品的比例。諸如此類的組合統計特徵能夠構造出至關多數量,關鍵點就在於怎樣才能構造出有利於預測轉化率的特徵組合,而後對其進行行爲統計。dom
這種特徵構造開始也須要像組合統計特徵同樣,要先對須要進行時間差計算的特徵進行組合。仍是以user_id和item_id特徵爲例,一個用戶看完當前商品以後,他可能還會再看另一個商品,即點擊另一個廣告,那麼統計這兩者的時間差或許會有所幫助。時間差有兩類,一類是當前點擊距離下次點擊的時間,另外一類是當前點擊距離上一次點擊的時間。機器學習
就是利用某種特徵的歷史轉化率來構造特徵。舉個例子,某個item_id,發現它在過去幾天中被人們點擊數是10,購買數是8,那麼這個商品就有8/10的轉化率,而另一個item_id點擊和購買數爲10和2,那麼轉化率就是2/10,大大低於前者,因此就能夠給前者設定一個比較大的數值而給後者設定一個比較小的數值,這便構造出了轉化率特徵。那麼假若你要預測的這天有的商品沒在前幾天出現怎麼辦,不是沒有轉化率特徵了麼?設爲0認爲其歷史轉化率爲0?這顯然不符合實際,這時候就須要貝葉斯平滑算法了,來利用先驗給其設定一個初值。而貝葉斯平滑的具體原理可能須要單獨學習一下。這裏就不說了。須要注意的是轉化率特徵一些事項,在個人我的實驗中,是這個類別屬性的多樣性越大越好,好比用戶的性別id,最多就三種狀況,男或女或用戶沒有設置,對這三種狀況進行貝葉斯平滑效果不見得有多好,而item_id,會有成千上萬種,這類屬性進行轉化率特徵構造可能會好得多。另外,千萬不要構造當天的轉化率特徵來預測當天的狀況,好比我7號的訓練集,我構造了7號的item_id的轉化率,而後再拿7號訓練集的一部分做爲訓練集,一部分做爲驗證集,固然驗證結果會表現的很好,可是要是用在預測你的預測集數據上,提交結果以後會發現線上效果不好,由於,已通過擬合了。這裏我用了除最後一天的數據來計算各類屬性的轉化率,這也是複賽中惟一一次用了除最後一天的訓練數據。post
其中有三個字符串特徵,分別是item_category_list,item_property_list和predict_category_property,意思是商品的類別,商品的屬性和商品的預測類別和屬性。這三個特徵是字符串型的,沒法直接輸入到模型裏,但直接扔了不用有點惋惜。我在這裏沒進行多少處理,就是把預測類別屬性的字符串給拆開,分紅預測類別和預測屬性,而後對比商品的真實類別和屬性,計算它的預測命中率,即它的預測屬性有多少在真實屬性中出現過,再除以它的預測屬性總數便獲得了命中率。這個命中率我想也能反映出一些問題吧,畢竟若是可以精確地猜出用戶輸入的搜索關鍵詞對應的類別和屬性,那麼用戶的使用體驗也會提升,購買商品的慾望也會強一些。我以前在初賽的時候有參考過天池官方論壇上的這篇文章,做者提出能夠用文本分類中的TF-IDF的方法去處理predict_category_property這個屬性,即把這個屬性經TF-IDF處理後變成一個稀疏矩陣,再把這個矩陣輸入到一個模型裏預測結果,再將結果做爲一個特徵。我嘗試了一下發現對預測結果影響不大就沒使用了,或許是本身的操做不是很正確,就沒有再去管它了,可是這個想法我以爲很好。學習
有幾個問題未能很好解決測試
類別屬性直接和數值屬性同樣,直接輸入到LightGBM模型中了,雖然感受不影響結果,LightGBM有比較好的處理類別特徵的能力,可是應該有更好的表示類別屬性的方法,曾經用過one-hot方法,但是對於
LightGBM,輸出的結果並很差,或許是由於LightGBM不能很好地處理大型稀疏矩陣。
特徵總數最後達到了三四百,這麼多的特徵對於我這渣渣筆記原本訓練十分夠嗆,包括構造特徵的時候都是用了不少繁瑣的方法才把這些特徵組合到一塊兒,時常會有Memory Error,內存不足是硬傷。最後也是勉強用這全部特徵預測出結果了,可是我認爲能夠進行特徵選擇,這麼多的特徵其實大多數是不起做用的,須要篩選出真正有做用的特徵,但是篩選的成本實在過高,時間和機器都不足,就沒又作了。關於特徵篩選,可參考這個帖子。
強特不足,渣特來湊,最後特徵篩選的方法其實很耗時間和資源的,關鍵點仍是在於對業務的深入理解上,以便構造出強有力的特徵,我在這方面仍是涉獵太少,找不出問題的關鍵所在,因此學習任重道遠。
最後感謝那些分享想法和代碼的朋友們,我從大家那裏收穫了不少,再次感謝!也但願本身下次比賽再接再礪。
求個星星!多謝!:)
再附上幾個前排大佬的解決方案: