提升有監(jiān)督學習效果的實戰(zhàn)解析



前言

最近很長時間沒有和大家分享東西了,最近一直在忙公司的項目,先說一聲抱歉。

之前寫過銷售預估算法,但是被諸多大佬吐槽有監(jiān)督學習部分毫無深度,其實我是想寫給一些剛?cè)腴T的朋友看的,這邊我boss最近也想讓我總結一些相對"上檔次"的一點的東西,我做了一些稍微深入一點的總結,希望能夠給新人朋友有稍微深入的方法介紹。


去年年末的那段時間里,看了很多天池大賽里面得高分的選手的算法思路,大概總結了有監(jiān)督學習中的一些核心流程及重要細節(jié):

  • feature processing tricks

這個是老生常談的問題,但是我還是看到了一些不錯的點,比如根據(jù)high importance feature剔除高度缺失的cases這些等等

  • single feature + crossing feature

交叉特征組合原始特征,可以顯著的提升auc,提高命中的準確程度,這邊除了FM,我們也可以在常規(guī)的算法中去實現(xiàn)這個trick

  • 有監(jiān)督學習架構思路

下面,我們來看看針對每個點,具體是如何實現(xiàn)的,及我們需要注意哪些相關的東西:

feature processing tricks

case and feature selection

我們在做模型訓練之前通常會對模型的feature做一些刪減,比如共線性檢驗,去除掉相似度過高的連續(xù)feature;比如變異度檢驗,去除掉一些數(shù)據(jù)變化差異過小的feature等等。然而,在常規(guī)的樣本處理中,我們通常只會根據(jù)初始的數(shù)據(jù)分布去看,比如用戶在feature上缺失大于來某個閾值才回去剔除這個用戶;其實,在深入的思考一下這個問題,會發(fā)現(xiàn),如果用戶在高重要性的feature缺失程度高去剔除才更合理一些,這樣想可能不是很清晰,這邊看下面這個feature flow:

針對uid來看,如果普通的統(tǒng)計的話,uid3的null的個數(shù)5個,uid5的null的個數(shù)4個,我們應該優(yōu)先剔除uid3,再考慮剔除uid5,因為null過多的用戶所能提供的信息量會相對的少,會增大泛化誤差。

但如果我們提前知道,對于判斷l(xiāng)abel的能力,feature3>feature5>feature6>feature8>其他,那么uid5在高重要性的缺失情況極度嚴重于uid3,所以我們應該優(yōu)先剔除uid5,相對于上面一種情況,我們預先知道feature的重要性排序就顯得很重要了。關于如何判斷提供了幾種簡單的方法:

  • 方差膨脹系數(shù):我們認為,在數(shù)據(jù)歸一化之后,數(shù)據(jù)波動的更大的feature能夠提供的信息量相對而言也是更大的,舉個很明顯的例子,如果feature1全都是1的話,它對我們判斷用戶是否下單這樣結果毫無意義。
  • 互信息:我一直認為,互信息是判斷feature重要性的非常好的方法。方差膨脹系數(shù)只單純了考慮feature本身的特征,而互信息在考慮feature的同時也考慮了label之間的關系,H(X,Y) = H(X) - H(X/Y),這個信息量的公式很好的解釋了這一點。
  • xgb's importance:如果互信息是方差膨脹系數(shù)的進階,那么xgb's importance則是互信息的進階,在考慮label與feature之間的關系的時候,同時還考慮了feature與feature之間的關系,這樣得出來的重要性排序更加全面了一些。

除此之外:

  • Logistic regression的params的參數(shù)
  • Recursive feature elimination(遞歸參數(shù)選擇方法)
  • Pearson Correlation
  • Distance correlation
  • Mean decrease impurity/Mean decrease accuracy
  • ...

諸如這樣的方法很多,需要根據(jù)數(shù)據(jù)的形式,目標變量的形式,時間成本,效率等等綜合考慮,這邊只是給大家梳理一下常規(guī)的方法,至于實際使用的情況,需要大家累積項目經(jīng)驗。

null-feature treatment method

在空值或者異常值的處理上,基本上分為2個派別,要么剔除這個feature或者case,要么填充這個feature或者case,它們的缺點也顯而易見,隨意剔除會減少判斷的信息,如果數(shù)據(jù)較少的時候,會降低模型的效果;填充的話會造成困惑,到底是眾數(shù)?平均數(shù)?中位數(shù)?最大值?最小值?現(xiàn)在很多人的處理方法都是觀察數(shù)據(jù)的分布,如果偏態(tài)分布就考慮分位數(shù)填充,如果是正態(tài)分布就考慮均值或者眾數(shù)填充,相對而言,這樣處理的時間成本會更高,而且很多時候解釋的說服力不是很強。

我在看了17年3月份JD的訂單預估賽,17年的天池工業(yè)賽等等的高分答案中,不得不說,有一個分箱的方法確實能夠提高0.5-1.5的auc,我之前思考過,可能存在的原因:

  • 保存了原始的信息,沒有以填充或者刪除的方式改變真實的數(shù)據(jù)分布
  • 讓feature存在的形式更加合理,比如age這個字段,其實我們在乎的不是27或者28這樣的差別,而是90后,80后這樣的差別,如果不采取分箱的形式,一定程度上夸大了27與26之前的差異
  • 在數(shù)據(jù)計算中,不僅僅加快了計算的速度而且消除了實際數(shù)據(jù)記錄中的隨機偏差,平滑了存儲過程中可能出現(xiàn)的噪音

這邊就直接給大家分享一下我的梳理:



這邊涉及到一個問題,連續(xù)數(shù)值特征是否一定要切為離散特征,建議綜合考慮以下幾個問題:a.所使用的算法是否為knn、svm這樣的距離計算的算法b.是否在實際業(yè)務中依賴于離散判斷c.連續(xù)數(shù)值特征的實際意義是否支持離散化。如果以上問題都沒有問題的話,我建議優(yōu)先考慮離散化連續(xù)特征,在一定程度上,離散完的feature有更好的解釋意義。

single feature + crossing feature

我們在之前的FM理論解析及應用中提到過特征交叉這個概念,當時的文章中緊接著通過矩陣的計算技巧:

構造了全部feature的C(n,2)的形式,后面追加了線性模型,這樣一定程度上可以提高分類算法的準確度。這是一個非常好的將低維特征向高維轉(zhuǎn)化的方式,所以在我們其他算法的過程中也可以借鑒這種思路,但是假設我們初始的feature量特別多,比如我在日常的CTR預估或者feature梳理的過程中,很容易就整理500以上的feature集合,如果僅考慮C(n,2)的形式的話,就有250*499個feature的新增組合,這個是不可能接受的,所以回到我們上面一節(jié)feature processing tricks中提到的case and feature selection就是一個非常好的解決辦法,我們可以先通過比如xgboost中的importance:


我這邊實際的畫出了我做下單概率預測時初始篩選完成后的417個feature經(jīng)過xgboost初步分類后的importance,可以很明顯看前37,前53,前94個feature對應了三次importance的拐點,我們可以在這些拐點中選擇一個既能夠涵蓋絕大多數(shù)的信息量,又不會造成后續(xù)交叉特征個數(shù)過多的值,比如我這邊選擇的是60,那么我接下來會生成的新的的交叉feature就是30*59個,比不做處理下的417*208要小很多倍,而且相對而言不會減少很多的信息量。

整體的流程我這邊也畫出來了,希望能夠給大家一個比較清晰的認識:


可以看到,樣本cases在經(jīng)過了最初的空值篩選及第一輪高重要性feature后的空值篩選后,就保持不變了,而特征feature的篩選過程則貫穿了整個交叉特征生成流。

bagging及stacking的思路架構

我相信在讀的各位,不論是機器學習從業(yè)者抑或是算法工程師甚至是其他研發(fā)工程師,一定看過類似如下的快速拖動的模塊流:

機器學習工具Clementine截圖

它相當于把每個功能封裝到一個固定的盒子中,當我們需要使用某個模塊的時候,進行模塊的操作,不需要的時候直接切斷模塊的流向即可,我們甚至可以空值每個模塊的var及bias的偏向程度,在bagging和stacking的思路框架中,我非常常用的就是類似這樣的思想:確定好我要進行的組合模塊的組合方式(stacking還是bagging還是blending),再確定這次為想要做的子模塊是什么,在根據(jù)組合形式及子模塊細微調(diào)節(jié)每個子模塊。

首先,子模塊可以有哪些?

  • svm分類/回歸
  • logistic分類/回歸
  • 神經(jīng)網(wǎng)絡分類/回歸
  • xgboost分類/回歸
  • gbdt分類/回歸
  • xgboost葉子節(jié)點index
  • gbdt葉子節(jié)點index
  • randomforest分類/回歸
  • elastic net

除了這些,還有么?當然,如果你愿意的話,每一個你自己構造出來的分類或者回歸的single model都可以成為你bagging或者stacking或者blending之前的子模塊。

如何訓練子模塊?

這邊的方法可謂是多種多樣,百花齊放,很大程度上來講,你在天池也好,kaggle也好,你能前十還是前十開外決定因素是你的feature處理的好壞,但是你能拿第一還是第十很大程度上就是依賴你的子模塊構造及子模塊組合上。這邊給大家分享我最近看到的比較有意思的三個子模塊形式:

1.wepon的Large-Scale SVM

讀過我之前寫的SVM理論解析及python實現(xiàn)這篇文章的朋友應該還記得,我當時說過svm在10.7%的數(shù)據(jù)集中取得第一,算是傳統(tǒng)的機器學習方法中非常值得一學的算法,但是實際應用中,在處理大規(guī)模數(shù)據(jù)問題時存在訓練時間過長和內(nèi)存空間需求過大的問題比較讓人頭疼,wepon同學采取的方法如下:

這種方法看似增加了計算復雜度,實際上是卻是減小的,假設原始訓練數(shù)據(jù)大小是n,則在原始數(shù)據(jù)上訓練的復雜度是o(n2),將數(shù)據(jù)集n分成p份,則每份數(shù)據(jù)量是(n/p),每一份訓練一個子svm,復雜度是o((n/p)2),全加起來o(n^2/p),復雜度比在原始數(shù)據(jù)上訓練減小了p倍。變向的解決了在量大的數(shù)據(jù)集合上使用svm,提高速度同時保證質(zhì)量這個問題。論文支持建議參考Ensemble SVM。

2.愛奇藝 Gbdts' Node Leafs

我們分別來解釋一下左右的Dense features 和 Spare Features。

首先,左側(cè)這塊很好理解,在上一次的文章中,我們已經(jīng)講了如何利用xgboost或者gbdt獲得用戶的數(shù)據(jù)落在的每棵樹上面的葉子節(jié)點的index值:


如果有不清楚的同學,請回顧一下上次講的內(nèi)容。

右側(cè)這塊分別寫了user preference 和video content,當然這是因為它是視頻公司的原因,在我實際的使用中,我用的是user preference 和 item content,這里的preference和content其實就是你個人信息及行為的向量化的形式。

最簡單的表示就是把你的基本信息和item信息先onehotencoding,再首尾相接成一個超長的vector,這就是一個稀疏的Spare Features。

當然除了這種粗暴的辦法,還有比如我們在若干天之前講過的深度學習下的電商商品推薦中的word2vec的技巧,先將所有的用戶隨機生成為我們需要的長度N維下一一對應的向量,在通過huffman編碼的形式找到每個item對應的Huffman樹子的唯一路徑,再通過在每個節(jié)點上生成一個logsitic分類的辦法,使得所有該路徑成立的概率最高,以此來修正我們最初隨便生成的N維向量,最后這個N維向量就可以看作是一個Spare Features。

還有么?當然,我私下問了我之前在該公司任職的同學,他們還有一種思路就是劃分數(shù)據(jù)集到M個子集,每個子集上面生成一個xgboost,然后每個子集取xgboost的葉子節(jié)點,相當于把左側(cè)的Dense features復制了M份Dense features放在了右邊的Spare Features,最后會得到一個M+1個Dense features。實際使用起來的效果完全不比word2vec的結果差。

3.基于GRU的潛藏層

Domonkos Tikk和Alexandros Karatzoglou在《Session-based Recommendations with Recurrent Neural Networks》文章中提到了可以用循環(huán)神經(jīng)網(wǎng)絡RNN來預估用戶的行為,如下圖:

我們可以清晰的看到,針對每個用戶Session1,他的行為由i1.1變化至i1.4其實是一個有序的過程,我們可以設計一個從i1.1---->i1.2,i1.2---->i1.3,i1.3---->i1.4這樣的一個循環(huán)流程。同時在他的文章中還解釋了這樣的設計解決的兩個問題:

  • the length of sessions can be very different
  • breaking down into fragments

一來通過了首尾相接,解決不同用戶的session不同長度;二來通過了embedding layer,解決了不完整session下預測的可能。具體網(wǎng)絡設計如下:


模型的更新流可以參考下面:


我們只需要拿到每個用戶的item流下所對應的state即可,這state就包含了這個用前M次的操作潛藏信息,同時我們還可以隨意定義這個信息向量的長度,這個就可以看作用戶狀態(tài)向量,作為子模塊的輸出。

這個思路的缺點就是,要預測的基礎數(shù)據(jù)不存在時序性,效果極差。比如滴滴打車的下單過程,從登陸到打到車的時間最短在20s,最長在1分鐘,否則用戶就退出了app,這樣的情況下,時序性質(zhì)就顯得格外薄弱,強行用這樣的RNN獲得的用戶屬性非常不存在代表性。

如何組合子模塊?

bagging

這個是我們Kaggle&TianChi分類問題相關純算法理論剖析就強調(diào)過的bagging的最簡單的形式,在每個子模塊的設計選擇過程中要盡可能的保證:

  • low biase
  • high var

也就是說子模塊可以適當?shù)倪^擬合,增加子模型擬合準確程度,通過加權平均的時候可以降低泛化誤差

stacking

這個是我們Kaggle&TianChi分類問題相關純算法理論剖析就強調(diào)過的stacking的最簡單的形式,在每個子模塊1、子模塊2的設計選擇過程中要盡可能的保證:

  • high biase
  • low var

在子模塊3的時候,要保證:

  • low biase
  • high var

也就是說,在子模塊1,2的選擇中,我們需要保證可稍欠擬合,在子模塊3的擬合上再保證擬合的準確度及強度

blending

我們知道單個組合子模塊的結果不夠理想,如果想得到更好的結果,需要把很多單個子模塊的結果融合在一起:



這種方法也可以提高我們最后的預測的效果。

關于有監(jiān)督學習的方法大概就梳理到這邊,最后希望能夠給一些新人同學對有監(jiān)督的理解和實戰(zhàn)有一些幫助。


歡迎大家關注我的個人bolg,更多代碼內(nèi)容歡迎follow我的個人Github,如果有任何算法、代碼疑問都歡迎通過公眾號發(fā)消息給我哦。

少年,掃一下嘛


Reference:
[1] 周志華。《機器學習》,清華大學出版社,3.7,2016
[2] wepon。 《PPD_RiskControlCompetition
[3] 愛奇藝技術產(chǎn)品團隊。 《愛奇藝個性化推薦排序?qū)嵺`
[4] slade。 《Kaggle&TianChi分類問題相關純算法理論剖析
[5] E Cernadas,D Amorim。 《Do we need hundreds of classifiers to solve real world classification problems?
[6] slade。 《深度學習下的電商商品推薦
[7] Domonkos Tikk,Alexandros Karatzoglo。 《Session-based Recommendations with Recurrent Neural Networks》
[8] slade. 《FM理論解析及應用

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容