◆ ◆ ◆
前言
kaggle上有篇名為「approaching (almost) any machine learning problem」的部落格(點選底部<code>閱讀原文</code>),作者是kaggle比賽的專業戶,部落格是他參加kaggle比賽的經驗總結。在進入正題前随便扯幾句:
本文并非原部落格的翻譯版,而是90%的原創,是在原部落格基礎上融合自己的經驗,重寫了大部分章節和代碼。是以當你看到本文跟原部落格差别很大時,請不要懷疑人生 ;-p 原部落格題目直譯過來是『解決(幾乎)任一機器學習問題的方法』,但原部落格内容更偏資料挖掘之『術』而非機器學習之『道』,因為講解了很多實際操作的trick和代碼,是以我給本文取名為『資料挖掘比賽通用架構』。為簡化描述,後續用<code>ml</code>指代<code>機器學習</code>,<code>dm</code>指代<code>資料挖掘</code> 本文可以看做是一篇科普性質的文章,内容簡單基礎,關鍵在于結合實際實踐這些想法,所謂 practice makes perfect. 本人連續多天利用數個晚上寫成此文,請尊重原創,轉載請注明。也希望本文能給各位帶來收獲,如有疏漏,歡迎背景留言積極指正,先行謝過
◆ ◆ ◆
背景
dm流程通常分兩個階段
step1. 資料清洗,資料格式調整 step2. 特征建構,模型選擇,效果評估
step1.是整個流程中最耗時的,這點想必大家早有耳聞,dm界有句名言 garbage in ,garbage out ,可見清洗資料非常重要。從我的經驗看,這部分工作跟實際處理的業務問題關系很大,比較dirty,也沒有統一流程,是以本文重點放在step2.
前期準備
1、資料變換
先把原始資料通過一定變換,變成通用的多列資料類型,作為ml模型的輸入,也就是上面的step1。用x代表樣本及其特征集合,y代表樣本标簽集合,整個流程如下:
根據标簽y的不同,可以把dm問題分為以下幾類:
二分類問題(這種問題在工業界最為常見,比如廣告點選率預估、推薦系統購買行為預測),此時y隻有一維,取值隻有兩個(比如0-1),每個樣本有唯一的标簽。比如預測廣告是否會被使用者點選;使用者是否會購買某種商品
多分類問題(比如微網誌使用者情感分析、使用者對理财産品偏好性分析),通常此時y有多元,每維代表一個類标簽,取值隻有兩個(比如0-1),每個樣本有唯一的标簽;當然,y也可以隻有一維,取值有多個,每個值代表一個類标簽。比如通過微網誌分析出使用者情感屬于喜怒哀樂等哪類;将理财産品的使用者群體分為偏好型/溫和型/厭惡型
多标簽問題(比如音樂的标簽劃分),y有多元,跟多分類的差別在于,樣本可以同時屬于多個标簽。作為一枚鋼琴愛好者,這裡以鋼琴作品舉例,假設标簽集合為{獨奏,協奏,浪漫主義,印象主義},最愛之一的德彪西「月光」無疑屬于{獨奏,印象主義},朗總成名作柴一則可歸為{協奏,浪漫主義},雲迪家喻戶曉的肖邦夜曲是{獨奏,浪漫主義},而中國特色的「保衛黃河」可歸為{協奏}
單回歸問題(比如股價預測),y隻有一維,取值為連續值。比如預測阿裡明天的股價
多回歸問題(比如天氣預測),y有多元,取值連續。比如預測明天的氣溫、空氣濕度、降雨量
預測結果的好壞需要用一些名額來衡量,通常不同類型的dm問題有不同的評價名額。對于二分類問題,很多時候類别本身不均衡(比如正樣本很多負樣本極少),是以我們通常用auc值——即roc曲線下的面積——來評價二分類結果;在多分類或者多标簽問題中,我們通常選取評價名額為交叉熵(cross-entropy)或者log損失(log loss);對于回歸問題,則可以選用mse(mean square error)
4、 工具
我跟原部落格作者一樣,提倡使用<code>python</code>解決dm問題,因為python的第三方庫非常齊全,以下是常見的、用于dm問題的python庫:
pandas: 仿照了r語言的資料結構、資料操作,一般用來做資料預處理,特征工程,其dataframe資料格式用起來相當便利
scikit-learn: 家喻戶曉的ml庫,各種聚類、分類、回歸模型等,也可以用來做預處理
xgboost: 陳天奇大神的傑作,改進了傳統的gbdt模型,在底層用一些trick加速模型訓練,非常值得一試,可以取代其他ml庫裡的gbdt系列模型 (很早就聽說過這個碉堡的庫,但一直沒有上手實踐,實在汗顔…後面我會結合gbdt做特征工程,實踐下效果,釋出到公衆号)
keras: 神經網絡相關的庫,可以選擇基于tensorflow或theano,趕腳很強大,我也是剛接觸
matplotlib: 作圖必備,語言風格跟matlab很像,很好上手
tpdm: 我沒聽過,原作者提到的,感興趣的童鞋可以了解下
這裡我補充說一下python開發環境和上面幾個庫的安裝方法。首先我跟原作者一樣,因為追求自(裝)由(逼),是以不用python ide(比如anaconda, pycharm),當然,裝ide可能省很多事情,個人建議安裝pycharm。然後我自己的python開發環境(純屬個人習慣,僅供參考):
windows: notepad++及其插件nppexec/explorer,結合我昨天釋出的<code>『一個神奇的腳本,一鍵運作各類程式』</code>,裡面的nppexec腳本可一鍵執行python。以及linux風格的shell: git bash (git bash是基于msys的,跟cygwin略有不同)
mac: sublime及其插件package control/anaconda,以及iterm2,或者自帶的terminal。(sublime中import某些python庫,比如matplotlib/sklearn/tensorflow會出點bug,需要修改下環境變量啥的,遇到相關問題可以微信我,盡量幫你解決)
linux: vim(因為我一般在指令行模式下開發)。如果是界面linux,應該可以有其他選擇
另外,jupyter notebook(前身是ipython notebook)是個好東西,可以逐漸執行python代碼片段,不依賴于平台,可在浏覽器中打開,非常适合學習過程中練手。
再說庫的安裝,首先強烈建議安裝64位python2.7,然後針對不同作業系統:
windows[不推薦]: 略蛋疼,64位的庫大多沒有官方版本,具體安裝方式見我之前寫過的一篇文章<code>『在windows下安裝64位python及資料挖掘相關庫』</code>(後續我會完善該文,但隻發送給指定分組,具體見文末bonus)。大多數庫的安裝都類似,但xgboost稍微複雜些,不能直接pip install,而是要裝vs來編譯其中相關檔案,再安裝,遇到問題可以微信我。另外tensroflow目前沒有windows版本
mac[推薦]: 最新的python2.7一般都自帶pip,是以裝好python後,直接在terminal中 pip install 相關庫就可以了,注意庫的依賴關系,一般先安裝numpy,scipy,matplotlib,再裝其他庫
linux[推薦]: 基本跟mac類似
dm問題架構
終于到了最核心的部分,原作者總結了一個他參加各類dm比賽常用的ml流程圖,真是一圖勝千言
這裡我擅自補充一下,這張圖看着眼花缭亂,其實就兩點,這兩點也是dm比賽中最核心的
兩點:
特征工程(包括各種離散化、組合、選擇) 模型選擇、模型融合(即ensemble)
能把這兩點做好,實屬不易,但其實在工業界,特征工程和模型融合是否需要做到極緻,是要看具體問題的。有些業務的資料次元本身就很稀少,并不足以支撐龐大的特征體系;有些業務需要很強的可解釋性(比如金融領域),于是很多模型不能直接用;有些業務則要系統的實時性和穩定性,過于複雜的ensemble雖然能提升一點名額,但也許得不償失。
上圖當中的粉色部分是最常用的一些步驟,簡單梳理一下:先确定dm問題的類型,然後對資料集劃分,接着對常見的數值變量和類别變量做相應處理,可以進行特征選擇,最後選擇合适的模型做預測,評估模型并輸出結果。下面将詳細展開。
1. 問題定義
首先搞清楚要解決的問題屬于哪一類,結合上節所講,我們一般通過觀察y标簽類來定義dm問題的類型。
在明确了問題的分類後,我們将對資料集劃分成訓練集(training data)和驗證集(validation data)(補充:很多時候還要劃分出測試集(test data),先用訓練集驗證集的交叉驗證來尋找模型的最優超參數,模型調優完畢後,最終用測試集來評估模型最終效果,具體參考我之前在公衆号釋出的<code>『新手資料挖掘中的幾個常見誤區』</code>第二節)。劃分方式如下:
這裡我用自己本地的一個小資料集(名為<code>toy_data.txt</code>)做展示,擷取方式見文末bonus,加載以上小資料集的代碼如下:
運作結果:
最後一個字段<code>label</code>就是我們要預測的y,在我的資料集裡取值0或1,是以是一個二分類問題。
對于分類問題,要根據标簽來劃分資料集,比如每種标簽采樣多少,這樣才能保證訓練集跟驗證集的樣本标簽分布接近,另外采樣方式也不限于随機采樣,可以根據實際業務問題選擇合适的采樣方式。這裡我們可以借助scikit-learn來實作分層的k折交叉驗證,代碼如下
用以下代碼驗證一下訓練集和驗證集中的正樣本的占比:
結果為<code>0.69713 0.69565</code>,兩者非常接近。
注意,不太推薦使用<code>iter(kf)</code>,這裡隻是為了展示标簽分布,具體我會在本文第五節『實戰』中介紹如何高效地使用交叉驗證。
如果是回歸問題,則不存在分類問題中類别标簽分布不均的情況,是以我們隻需采用普通的k折交叉驗證即可:
毫不誇張地說,特征工程是dm重要的一環,也是決定dm比賽的關鍵因素。縱觀dm比賽,幾年間已由追求模型是否fancy轉向無盡的特征工程,主要得益于越來越标準化的ml模型,以及更好的計算能力。
特征工程可以做的很複雜很龐大,但受限于本人目前的水準,這裡隻結合原部落格内容講解一些最基本(也是最經典)的處理方法。
類别變量(categorial data)是一種常見的變量,在我之前寫的<code>『新手資料挖掘中的幾個常見誤區』</code> 一文的第三節中讨論過為何要對類别變量編碼
在<code>toy_data</code>當中,字段<code>continent, country, product, brand, treeid, industry, saler</code>都可以看做是類别變量。處理類别變量一般是先标簽化,然後再二值化編碼。标簽化的目的是将字段的原始值(如字元串、不連續的數字等)轉換成連續的整數值,再對整數值二值化編碼,如果原始值是整數,則直接二值化即可
我們拿<code>toy_data</code>前幾個樣本的<code>continent</code>字段舉例,對其進行編碼:
運作結果如下
可以看到,原來的一列<code>continent</code>字段變成了三列,分别代表<code>[ 'am', 'ep', 'la' ]</code>,取值1表明是,取值0表明否。這就是常說的one-hot編碼。如果類别變量的取值是整數,則直接用<code>sklearn.preprocessing.onehotencoder()</code>即可,把上面代碼中<code>labelbinarizer()</code>替換掉
注意我們必須将對訓練集上的變換原封不動的作用到測試集,而不能重新對測試集的資料做變換(詳見我之前寫的<code>『新手資料挖掘中的幾個常見誤區』</code>第一節)。
一般而言,數值變量不用做太多處理,隻需做正規化(normalization)和标準化(standardization)即可,分别對應scikit-learn中的<code>normalizer</code>和<code>standardscaler</code>。不過對于稀疏變量,在做标準化的時候要注意,選擇不去均值。
其實數值型變量最好也進行離散化,離散手段從基本的等距離散法、按分隔點人為指定,到聚類、輸入樹模型等,手段很多,在此不詳細展開,我會在後續文章中提及。
文本在實際問題中很常見,比如使用者評論、新聞摘要、視訊彈幕等等。我們用的<code>toy_data</code>不包含文本變量,是以這裡我參考了scikit-learn的文檔,一個小的corpus作為我們的訓練資料集。
corpus有四句話,可以看做是四個樣本。接下來我們先用一個簡單的方法處理文本變量——統計corpus中每個詞出現次數,代碼如下:
第一行是corpus中所有詞,下面的ndarray每行代表該詞在該樣本中出現次數,比如第2行第6列的<code>2</code>代表<code>second</code>這個詞在第二句話中出現了2次。一般我們不會直接用這個結果,而是會将每行歸一化之類。
這種處理方式簡單粗暴,沒有考慮詞與詞之間的關系。我們改進一下這個方法,除了考慮單個詞之外,還考慮corpus中成對出現的詞(類似nlp裡n-gram的 bi-gram,具體請自行google),代碼如下
然而,這還不夠,像<code>a is this</code>這類的助詞、介詞等,詞頻将非常高(在nlp中又叫停止詞 stop word),是以需要減小他們的權重。一種做法是,不再簡單統計該詞在文檔中出現的詞頻,而且還要統計 出現該詞的文檔的占比,這在nlp中叫tfidf。說的有點繞,具體到我們的例子中可以寫成如下表達式:
分子即tf,分母即1/idf,有時需要用<code>log sqrt</code>之類的函數作用在tf或者 1/idf上,以減弱某項的影響。同樣,我們可以:
仔細觀察不難發現,<code>is this</code>這類的停止詞在變換後數值變小了。
!!注意!!跟處理類别變量、數值變量一樣,我們在處理文本變量時,必須将訓練集上的變換方式原封不動地作用到驗證集或測試集上,而不能重新對驗證集或者測試集做變換。比如在得到上面的<code>vectorizer3</code>後,我們将其作用在一個新的樣本 <code>['a new sentence']</code>上,代碼如下
我們可以看到,結果是 <code>[[0 0 0 0 0 0 0 0 0]]</code>,因為這個樣本裡的三個詞從未出現在訓練集corpus中,這是正确的結果!
為了友善将變換作用在未來的測試集,我們可以先把<code>vectorizer3</code>用<code>pickle</code>儲存到本地,用的時候再load,儲存方式如下:
用的時候再 <code>vectorizer = pickle.load(open('vectorizer3.pkl','r'))</code>即可。
todo 差別對待稠密特征和稀疏特征,
todo pca等
todo
原文釋出時間為:2016-08-16
本文來自雲栖社群合作夥伴“大資料文摘”,了解相關資訊可以關注“bigdatadigest”微信公衆号