解決機器學習問題有通法!看這一篇就夠了
一個中等水平的數(shù)據(jù)科學家每天都要處理大量的數(shù)據(jù)。一些人說超過60%到70%的時間都用于數(shù)據(jù)清理、數(shù)據(jù)處理及格式轉化,以便于在之后應用機器學習模型。
這篇文章的重點便在后者—— 應用機器學習模型(包括預處理的階段)。此文討論到的內容來源于我參加的過的數(shù)百次的機器學習競賽。請大家注意這里討論的方法是大體上適用的,當然還有很多被專業(yè)人士使用的非常復雜的方法。
接下來會使用到python。
數(shù)據(jù)
在應用機器學習模型之前,所有的數(shù)據(jù)都必須轉換為表格形式。如下圖所示,這個過程是最耗時、最困難的部分。
轉換完成之后,便可以將這些表格數(shù)據(jù)灌入機器學習模型。表格數(shù)據(jù)是在機器學習或是數(shù)據(jù)挖掘中最常見的數(shù)據(jù)表示形式。我們有一個數(shù)據(jù)表,x軸是樣本數(shù)據(jù),y軸是標簽。標簽可以是單列可以是多列,取決于問題的形式。我們會用X表示數(shù)據(jù),y表示標簽。
標簽的種類
標簽會定義你要解決何種問題,有不同的問題類型。例如:
- 單列,二進制值(分類問題,一個樣本僅屬于一個類,并且只有兩個類)
- 單列,實數(shù)值(回歸問題,只預測一個值)
- 多列,二進制值(分類問題,一個樣本屬于一個類,但有兩個以上的類)
- 多列,實數(shù)值(回歸問題,多個值的預測)
- 多個標簽(分類問題,一個樣本可以屬于幾個類)
評估指標
對于任何類型的機器學習問題,我們都一定要知道如何評估結果,或者說評估指標和目的是什么。舉例來說,對于不均衡的二進制分類問題,我們通常選擇受試者工作特征曲線下面積(ROC AUC或簡單的AUC);對于多標簽或多類別的分類問題,我們通常選擇分類交叉熵或多類對數(shù)損失;對于回歸問題,則會選擇均方差。
我不會再深入的講解不同的評估指標,因為根據(jù)問題的不同會有很多不同的種類。
庫
開始嘗試機器學習庫可以從安裝最基礎也是最重要的開始,像numpy和scipy。
- 查看和執(zhí)行數(shù)據(jù)操作:pandas(http://pandas.pydata.org/)
- 對于各種機器學習模型:scikit-learn(http://scikit-learn.org/stable/)
- 最好的gradient boosting庫:xgboost(https://github.com/dmlc/xgboost)
- 對于神經(jīng)網(wǎng)絡:keras(http://keras.io/)
- 數(shù)據(jù)繪圖:matplotlib(http://matplotlib.org/)
- 監(jiān)視進度:tqdm(https://pypi.python.org/pypi/tqdm)
Anaconda操作簡單而且?guī)湍銣蕚浜昧诉@些,可是我沒有使用,因為我習慣自己配置和自由使用。當然,決策在你手中。
機器學習總體框架
2015起,我開始制作一個自動機器學習框架,還在完善過程中,很快就會發(fā)布。下圖所示的框架圖就是這篇文章中將會提到的基礎框架:
圖片來源:A. Thakur and A. Krohn-Grimberghe, AutoCompete: A Framework for Machine Learning Competitions, AutoML Workshop, International Conference on Machine Learning 2015
上面的框架圖中,粉色的線代表最常用的路徑。結束提取數(shù)據(jù)并將其轉化為表格形式,我們就可以開始建造機器學習模型了。
第一步是識別(區(qū)分)問題。這個可以通過觀察標簽解決。你一定要知道這個問題是二元分類,還是多種類或多標簽分類,還是一個回歸問題。當識別了問題之后,就可以把數(shù)據(jù)分成訓練集和測驗集兩個部分。如下圖所示。
將數(shù)據(jù)分成訓練集和驗證集“必須”根據(jù)標簽進行。遇到分類問題,使用分層分割就對了。在Python中,用scikit-learn很容易就做到了。
遇到回歸問題,一個簡單的K-Fold分割就可以了。當然,也還有很多復雜的方法能夠在維持訓練集和驗證集原有分布的同時將數(shù)據(jù)分割開來。這個就留給讀者們自己去練習啦。
在以上的例子中我選擇用全數(shù)據(jù)的10%作為驗證集,當然你可以根據(jù)手中具體的數(shù)據(jù)決定取樣的大小。
分好數(shù)據(jù)之后,就可以把它放在一邊不要碰了。任何作用于訓練集的運算都必須被保存并應用于驗證集。驗證集無論如何都不可以和訓練集混為一談。因為混到一起之后雖然回到一個讓用戶滿意的評估指標值,但卻會因為模型過擬合而不能使用。
下一步是識別數(shù)據(jù)中不同的變量。通常有三種變量:數(shù)值變量、分類變量和文本變量。讓我們用很受歡迎的關于泰坦尼克號的數(shù)據(jù)集來舉個例子。 (https://www.kaggle.com/c/titanic/data).
在這里,“survival”(生存)就是標簽。在前一個步驟中我們已經(jīng)把標簽從訓練集中去掉了。接下來,有pclass,sex, embarked變量這些變量由不同的級別,因此是分類變量。像age, sibsp, parch等就是數(shù)值變量。Name是一個含有文本的變量,但我不認為它對預測是否生存有用。
先把數(shù)值變量分離出來。這些變量不需要任何形式的處理,所以我們可以開始對其歸一并應用機器學習模型。
處理分類變量有兩種變法:
把分類變量轉化為標簽
把標簽轉化為二進制變量
請記住在應用OneHotEncoder之前要用LabelEncoder把分類變量轉化為數(shù)值變量。
既然泰坦尼克數(shù)據(jù)里面沒有好的關于文本變量的例子,我們就自己制定一個處理文本變量的一般規(guī)則。我們可以把所有文本變量整合在一起然后用一些文本分析的算法把他們轉換成數(shù)字。
文本變量可以如下這樣整合:
然后就可以應用CoutVectorizer或者TfidfVectorizer在上面啦:
或者
TfidfVectorizer大多數(shù)時候比單純計數(shù)效果要好。下面的參數(shù)設置在大多數(shù)時候都有很好的結果。
如果你在訓練集上做了向量化處理(或者其他操作),請確保將其(相應的處理)轉存在硬盤上,以便以后在驗證集上應用。
接下來,就是堆疊器模塊。堆疊器模塊不是模型堆疊而是特征堆疊。上述處理步驟之后得到的不同特征可以通過堆疊器模塊整合到一起。
你可以水平地堆疊所有的特征,然后通過使用numpy hstack或sparse hvstack進行進一步處理,具體取決于是否具有密集或稀疏特征。
也可以通過FeatureUnion模塊實現(xiàn),以防萬一有其他處理步驟,如PCA或特征選擇(我們將在后文提到分解和特征選擇)。
一旦我們把特征找齊了,就可以開始應用機器學習模型了。在這個階段,你只需用到基于樹的模型,包括:
- 隨機森林分類器
- 隨機森林回歸器
- ExtraTrees分類器
- ExtraTrees回歸器
- XGB分類器
- XGB回歸器
由于沒有歸一化,我們不能將線性模型應用到上述特征上。為了能夠應用線性模型,可以從scikit-learn中使用Normalizer或者StandardScaler。
這些歸一化的方法僅限于密集特征,對稀疏特征,結果差強人意。當然,也可以在不使用平均值(參數(shù):with_mean=False)的情況下對稀疏矩陣使用StandardScaler。
如果以上步驟得到了一個“好的”模型,我們就可以進一步做超參數(shù)的優(yōu)化了。得不到的情況下,可以做如下步驟以改進模型。
接下來的步驟包括分解模型:
簡潔起見,我們跳過LDA和QDA轉化。對高維數(shù)據(jù),一般而言,PCA可以用來分解數(shù)據(jù)。對圖片而言,從10-15個組分起始,在結果質量持續(xù)改進的前提下,逐漸增加組分數(shù)量。對其它的數(shù)據(jù)而言,我們挑選50-60個組分作為起點(對于數(shù)字型的數(shù)據(jù),只要我們能夠處理得了,就不用PCA)
對文本型的數(shù)據(jù),把文本轉化為稀疏矩陣后,進行奇異值分解(Singular Value Decomposition (SVD)),可以在scikit-learn中找到一個SVD的變異版叫做TruncatedSVD。
一般對TF-IDF有效的奇異值分解成分(components)是120-200個。更多的數(shù)量可能效果會有所改進但不是很明顯,而計算機資源耗費卻很多。
在進一步評價模型的性能以后,我們可以再做數(shù)據(jù)集的縮放,這樣就可以評價線性模型了。歸一化或者縮放后的特征可以用在機器學習模型上或者特征選擇模塊里。
特征選擇有很多方法。最常用的方法之一是貪心算法選擇(正向或反向)。具體而言,選擇一個特征,在一個固定的評價矩陣上訓練一個模型,評價其性能,然后一個一個地往里面增加或移除特征,記錄每一步的模型性能。最后選擇性能得分最高時的那些特征。貪心算法和其評價矩陣的AUC的一個例子見鏈接: https://github.com/abhishekkrthakur/greedyFeatureSelection。
需要注意的是,這個應用并非完美,必須根據(jù)要求進行修改。
其他更快的特征選擇方法包括從一個模型中選取最好的特征。我們可以根據(jù)一個邏輯回歸模型的系數(shù),或者訓練一個隨機森林來選擇最好的特征,然后把它們用在其它的機器學習模型里。
記得把估計值或者超參數(shù)的數(shù)量控制得盡量少,這樣你才不會過擬合。
用Gradient Boosting Machine也可以實現(xiàn)特征選擇。如果能用xgboost就不要用GBM,因為前者要快得多,可擴展性更好。
對稀疏數(shù)據(jù)集,也可以用隨機森林分類器/隨機森林回歸器或xgboost做特征選擇。
從正性稀疏數(shù)據(jù)集里選擇特征的其它流行方法還有基于卡方的特征選擇,scikit-learn中即可應用。
這里,我們用卡方聯(lián)合SelectKBest的方法從數(shù)據(jù)中選擇了20個特征。這個本身也是我們改進機器學習模型的超參數(shù)之一。
別忘了把任何中間過程產生的轉化體轉存起來。在驗證集上你會要用它們來評價性能。
下一步(或者說,緊接著)主要的步驟是模型選擇+超參數(shù)優(yōu)化。
一般來說,我們用下面的算法來選擇機器學習模型:
- 分類
- 隨機森林
- GBM
- 邏輯回歸
- 樸素貝葉斯
- 支持向量機
- K最近鄰法
- 回歸
- 隨機森林
- GBM
- 線性回歸
- Ridge
- Lasso
- SVR
我需要優(yōu)化哪個參數(shù)?如何選擇最好的參數(shù)?這些是人們經(jīng)常會遇到的問題。沒有大量數(shù)據(jù)集上不同模型+參數(shù)的經(jīng)驗,無法得到這些問題的答案。有經(jīng)驗的人又不愿意把他們的秘訣公之于眾。幸運的是,我有豐富的經(jīng)驗,同時愿意分享。讓我們來看看不同模型下超參數(shù)的秘密:
RS* =不好說合適的值是多少,在這些超參數(shù)里隨機搜索一下。
以我個人淺見(原文作者個人意見),上述的這些模型比其他模型好,無需評價其它模型。
再說一次,記得保存這些轉化體:
然后對驗證集做相同的操作。
上面的規(guī)則和框架對我遇到的數(shù)據(jù)集而言運行良好。當然,在特別復雜的情況下也失敗過。天下沒有完美的東西,我們只能在學習中不斷改進,如同機器學習一樣。