做者:寒小陽html
時間:2016年1月。python
出處:http://www.lai18.com/content/2440126.htmlgit
聲明:版權全部,轉載請聯繫做者並註明出處算法
1.引言提起筆來寫這篇博客,忽然有點愧疚和尷尬。愧疚的是,工做瑣事多,加之懶癌嚴重,致使這個系列一直沒有更新,向關注該系列的同窗們道個歉。尷尬的是,按理說,機器學習介紹與算法一覽應該放在最前面寫,詳細的應用建議應該在講完機器學習經常使用算法以後寫,忽然莫名奇妙在中間插播這麼一篇,好像有點打亂主線。網絡
老話說『亡羊補牢,爲時未晚』,前面開頭忘講的東西,咱在這塊兒補上。咱們先帶着你們過一遍傳統機器學習算法,基本思想和用途。把問題解決思路和方法應用建議提早到這裏的想法也很簡單,但願能提早給你們一些小建議,對於某些容易出錯的地方也先給你們打個預防針,這樣在理解後續相應機器學習算法以後,使用起來也有必定的章法。數據結構
2.機器學習算法簡述按照不一樣的分類標準,能夠把機器學習的算法作不一樣的分類。app
2.1 從機器學習問題角度分類咱們先從機器學習問題自己分類的角度來看,咱們能夠分紅下列類型的算法:dom
監督學習算法機器學習
機器學習中有一大部分的問題屬於 『監督學習』的範疇,簡單口語化地說明,這類問題中,給定的訓練樣本中,每一個樣本的輸入xx都對應一個肯定的結果yy,咱們須要訓練出一個模型(數學上看是一個x→yx → y的映射關係ff),在未知的樣本x′x’給定後,咱們能對結果y′y’作出預測。函數
這裏的預測結果若是是
離散值(不少時候是類別類型,好比郵件分類問題中的垃圾郵件/普通郵件,好比用戶會/不會購買某商品),那麼咱們把它叫作分類問題(classification problem);若是預測結果是
連續值(好比房價,股票價格等等),那麼咱們把它叫作迴歸問題(regression problem)。
有一系列的機器學習算法是用以解決
監督學習問題的,好比最經典的用於分類問題的樸素貝葉斯、邏輯迴歸、支持向量機等等;好比說用於迴歸問題的線性迴歸等等。
無監督學習
有另一類問題,給咱們的樣本並無給出『標籤/標準答案』,就是一系列的樣本。而咱們須要作的事情是,在一些樣本中抽取出通用的規則。這叫作 『無監督學習』。包括關聯規則和聚類算法在內的一系列機器學習算法都屬於這個範疇。
半監督學習
這類問題給出的訓練數據,有一部分有標籤,有一部分沒有標籤。咱們想學習出數據組織結構的同時,也能作相應的預測。此類問題相對應的機器學習算法有自訓練(Self-Training)、直推學習(Transductive Learning)、生成式模型(Generative Model)等。
整體說來,最多見是前兩類問題,而對應前兩類問題的一些機器學習算法以下:
2.2 從算法的功能角度分類咱們也能夠從算法的共性(好比功能,運做方式)角度對機器學習算法分類。下面咱們根據算法的共性去對它們歸個類。不過須要注意的是,咱們下面的歸類方法可能對分類和迴歸有比較強的傾向性,而這兩類問題也是最常遇到的。
2.2.1 迴歸算法(Regression Algorithms)
迴歸算法是一種經過最小化預測值與實際結果值之間的差距,而獲得輸入特徵之間的最佳組合方式的一類算法。對於連續值預測有線性迴歸等,而對於離散值/類別預測,咱們也能夠把邏輯迴歸等也視做迴歸算法的一種,常見的迴歸算法以下:
Ordinary Least Squares Regression (OLSR)
Linear Regression
Logistic Regression
Stepwise Regression
Locally Estimated Scatterplot Smoothing (LOESS)
Multivariate Adaptive Regression Splines (MARS)
2.2.2 基於實例的算法(Instance-based Algorithms)
這裏所謂的基於實例的算法,我指的是咱們最後建成的模型,對原始數據樣本實例依舊有很強的依賴性。這類算法在作預測決策時,通常都是使用某類類似度準則,去比對待預測的樣本和原始樣本的相近度,再給出相應的預測結果。常見的基於實例的算法有:
k-Nearest Neighbour (kNN)
Learning Vector Quantization (LVQ)
Self-Organizing Map (SOM)
Locally Weighted Learning (LWL)
2.2.3 決策樹類算法(Decision Tree Algorithms)
決策樹類算法,會基於原始數據特徵,構建一顆包含不少決策路徑的樹。預測階段選擇路徑進行決策。常見的決策樹算法包括:
Classification and Regression Tree (CART)
Iterative Dichotomiser 3 (ID3)
C4.5 and C5.0 (different versions of a powerful approach)
Chi-squared Automatic Interaction Detection (CHAID)
M5
Conditional Decision Trees
2.2.4 貝葉斯類算法(Bayesian Algorithms)
這裏說的貝葉斯類算法,指的是在分類和迴歸問題中,隱含使用了貝葉斯原理的算法。包括:
Naive Bayes
Gaussian Naive Bayes
Multinomial Naive Bayes
Averaged One-Dependence Estimators (AODE)
Bayesian Belief Network (BBN)
Bayesian Network (BN)
2.2.5 聚類算法(Clustering Algorithms)
聚類算法作的事情是,把輸入樣本聚成圍繞一些中心的『數據團』,以發現數據分佈結構的一些規律。經常使用的聚類算法包括:
k-Means
Hierarchical Clustering
Expectation Maximisation (EM)
2.2.6 關聯規則算法(Association Rule Learning Algorithms)
關聯規則算法是這樣一類算法:它試圖抽取出,最能解釋觀察到的訓練樣本之間關聯關係的規則,也就是獲取一個事件和其餘事件之間依賴或關聯的知識,常見的關聯規則算法有:
Apriori algorithm
Eclat algorithm
2.2.7 人工神經網絡類算法(Artificial Neural Network Algorithms)
這是受人腦神經元工做方式啓發而構造的一類算法。須要提到的一點是,我把『深度學習』單拎出來了,這裏說的人工神經網絡偏向於更傳統的感知算法,主要包括:
Perceptron
Back-Propagation
Radial Basis Function Network (RBFN)
2.2.8 深度學習(Deep Learning Algorithms)
深度學習是近年來很是火的機器學習領域,相對於上面列的人工神經網絡算法,它一般狀況下,有着更深的層次和更復雜的結構。有興趣的同窗能夠看看咱們另外一個系列機器學習與計算機視覺,最多見的深度學習算法包括:
Deep Boltzmann Machine (DBM)
Deep Belief Networks (DBN)
Convolutional Neural Network (CNN)
Stacked Auto-Encoders
2.2.9 降維算法(Dimensionality Reduction Algorithms)
從某種程度上說,降維算法和聚類其實有點相似,由於它也在試圖發現原始訓練數據的固有結構,可是降維算法在試圖,用更少的信息(更低維的信息)總結和描述出原始信息的大部份內容。
有意思的是,降維算法通常在數據的可視化,或者是下降數據計算空間有很大的做用。它做爲一種機器學習的算法,不少時候用它先處理數據,再灌入別的機器學習算法學習。主要的降維算法包括:
Principal Component Analysis (PCA)
Principal Component Regression (PCR)
Partial Least Squares Regression (PLSR)
Sammon Mapping
Multidimensional Scaling (MDS)
Linear Discriminant Analysis (LDA)
Mixture Discriminant Analysis (MDA)
Quadratic Discriminant Analysis (QDA)
Flexible Discriminant Analysis (FDA)
2.2.10 模型融合算法(Ensemble Algorithms)
嚴格意義上來講,這不算是一種機器學習算法,而更像是一種優化手段/策略,它一般是結合多個簡單的弱機器學習算法,去作更可靠的決策。拿分類問題舉個例,直觀的理解,就是單個分類器的分類是可能出錯,不可靠的,可是若是多個分類器投票,那可靠度就會高不少。經常使用的模型融合加強方法包括:
Random Forest
Boosting
Bootstrapped Aggregation (Bagging)
AdaBoost
Stacked Generalization (blending)
Gradient Boosting Machines (GBM)
Gradient Boosted Regression Trees (GBRT)
2.3 機器學習算法使用圖譜scikit-learn做爲一個豐富的python機器學習庫,實現了絕大多數機器學習的算法,有至關多的人在使用,因而我這裏很無恥地把machine learning cheat sheet for sklearn搬過來了,原文能夠看這裏。哈哈,既然講機器學習,咱們就用機器學習的語言來解釋一下,這是針對實際應用場景的各類條件限制,對scikit-learn裏完成的算法構建的一顆決策樹,每一組條件都是對應一條路徑,能找到相對較爲合適的一些解決方法,具體以下:
首先樣本量若是很是少的話,其實全部的機器學習算法都沒有辦法從裏面『學到』通用的規則和模式,so多弄點數據是王道。而後根據問題是有/無監督學習和連續值/離散值預測,分紅了 分類、 聚類、 迴歸和 維度約減四個方法類,每一個類里根據具體狀況的不一樣,又有不一樣的處理方法。
3. 機器學習問題解決思路上面帶着代價蜻蜓點水過了一遍機器學習的若干算法,下面咱們試着總結總結在拿到一個實際問題的時候,若是着手使用機器學習算法去解決問題,其中的一些注意點以及核心思路。主要包括如下內容:
拿到數據後怎麼了解數據(可視化)
選擇最貼切的機器學習算法
定位模型狀態(過/欠擬合)以及解決方法
大量極的數據的特徵分析與可視化
各類損失函數(loss function)的優缺點及如何選擇
多說一句,這裏寫的這個小教程,主要是做爲一個通用的建議和指導方案,你不必定要嚴格按照這個流程解決機器學習問題。
3.1 數據與可視化咱們先使用scikit-learn的make_classification函數來生產一份分類數據,而後模擬一下拿到實際數據後咱們須要作的事情。
#numpy科學計算工具箱import numpy as np#使用make_classification構造1000個樣本,每一個樣本有20個featurefrom sklearn.datasets import make_classificationX, y = make_classification(1000, n_features=20, n_informative=2, n_redundant=2, n_classes=2, random_state=0)#存爲dataframe格式from pandas import DataFramedf = DataFrame(np.hstack((X, y[:, None])),columns = range(20) + ["class"])
咱們生成了一份包含1000個分類數據樣本的數據集,每一個樣本有20個數值特徵。同時咱們把數據存儲至pandas中的 DataFrame數據結構中。咱們取前幾行的數據看一眼:
df[:6]
不幸的是,肉眼看數據,尤爲是維度稍微高點的時候,頗有可能看花了也看不出看不出任何線索。幸運的是,咱們對於圖像的理解力,比數字好太多,而又有至關多的工具能夠幫助咱們『可視化』數據分佈。
咱們在處理任何數據相關的問題時,瞭解數據都是頗有必要的,而可視化能夠幫助咱們更好地直觀理解數據的分佈和特性
數據的可視化有不少工具包能夠用,好比下面咱們用來作數據可視化的工具包Seaborn。最簡單的可視化就是數據散列分佈圖和柱狀圖,這個能夠用Seanborn的 pairplot來完成。如下圖中2種顏色表示2種不一樣的類,由於20維的可視化沒有辦法在平面表示,咱們取出了一部分維度,兩兩組成pair看數據在這2個維度平面上的分佈情況,代碼和結果以下:
import matplotlib.pyplot as pltimport seaborn as sns#使用pairplot去看不一樣特徵維度pair下數據的空間分佈情況_ = sns.pairplot(df[:50], vars=[8, 11, 12, 14, 19], hue="class", size=1.5)plt.show()
咱們從散列圖和柱狀圖上能夠看出,確實有些維度的特徵相對其餘維度,有更好的區分度,好比第11維和14維看起來頗有區分度。這兩個維度上看,數據點是近似線性可分的。而12維和19維彷佛呈現出了很高的負相關性。接下來咱們用Seanborn中的 corrplot來計算計算各維度特徵之間(以及最後的類別)的相關性。代碼和結果圖以下:
import matplotlib.pyplot as pltplt.figure(figsize=(12, 10))_ = sns.corrplot(df, annot=False)plt.show()
相關性圖很好地印證了咱們以前的想法,能夠看到第11維特徵和第14維特徵和類別有極強的相關性,同時它們倆之間也有極高的相關性。而第12維特徵和第19維特徵卻呈現出極強的負相關性。強相關的特徵其實包含了一些冗餘的特徵,而除掉上圖中顏色較深的特徵,其他特徵包含的信息量就沒有這麼大了,它們和最後的類別相關度不高,甚至各自之間也沒什麼先慣性。
插一句,這裏的維度只有20,因此這個相關度計算並不費太大力氣,然而實際情形中,你徹底有可能有遠高於這個數字的特徵維度,同時樣本量也可能多不少,那種情形下咱們可能要先作一些處理,再來實現可視化了。彆着急,一下子咱們會講到。
3.2 機器學習算法選擇數據的狀況咱們大體看了一眼,肯定一些特徵維度以後,咱們能夠考慮先選用機器學習算法作一個baseline的系統出來了。這裏咱們繼續參照上面提到過的機器學習算法使用圖譜。
咱們只有1000個數據樣本,是分類問題,同時是一個有監督學習,所以咱們根據圖譜裏教的方法,使用 LinearSVC(support vector classification with linear kernel)試試。注意, LinearSVC須要選擇正則化方法以緩解過擬合問題;咱們這裏選擇使用最多的L2正則化,並把懲罰係數C設爲10。咱們改寫一下sklearn中的學習曲線繪製函數,畫出訓練集和交叉驗證集上的得分:
from sklearn.svm import LinearSVCfrom sklearn.learning_curve import learning_curve#繪製學習曲線,以肯定模型的情況def plot_learning_curve(estimator, title, X, y, ylim=None, cv=None,train_sizes=np.linspace(.1, 1.0, 5)): """ 畫出data在某模型上的learning curve. 參數解釋 ---------- estimator : 你用的分類器。 title : 表格的標題。 X : 輸入的feature,numpy類型 y : 輸入的target vector ylim : tuple格式的(ymin, ymax), 設定圖像中縱座標的最低點和最高點 cv : 作cross-validation的時候,數據分紅的份數,其中一份做爲cv集,其他n-1份做爲training(默認爲3份) """ plt.figure() train_sizes, train_scores, test_scores = learning_curve(estimator, X, y, cv=5, n_jobs=1, train_sizes=train_sizes) train_scores_mean = np.mean(train_scores, axis=1) train_scores_std = np.std(train_scores, axis=1) test_scores_mean = np.mean(test_scores, axis=1) test_scores_std = np.std(test_scores, axis=1) plt.fill_between(train_sizes, train_scores_mean - train_scores_std, train_scores_mean + train_scores_std, alpha=0.1, color="r") plt.fill_between(train_sizes, test_scores_mean - test_scores_std, test_scores_mean + test_scores_std, alpha=0.1, color="g") plt.plot(train_sizes, train_scores_mean, 'o-', color="r", label="Training score") plt.plot(train_sizes, test_scores_mean, 'o-', color="g", label="Cross-validation score") plt.xlabel("Training examples") plt.ylabel("Score") plt.legend(loc="best") plt.grid("on") if ylim:plt.ylim(ylim) plt.title(title) plt.show()#少樣本的狀況狀況下繪出學習曲線plot_learning_curve(LinearSVC(C=10.0), "LinearSVC(C=10.0)", X, y, ylim=(0.8, 1.01), train_sizes=np.linspace(.05, 0.2, 5))
這幅圖上,咱們發現隨着樣本量的增長,訓練集上的得分有必定程度的降低,交叉驗證集上的得分有必定程度的上升,但整體說來,二者之間有很大的差距,訓練集上的準確度遠高於交叉驗證集。這其實意味着咱們的模型處於
過擬合的狀態,也即模型太努力地刻畫訓練集,一不當心把不少噪聲的分佈也擬合上了,致使在新數據上的泛化能力變差了。
3.2.1 過擬合的定位與解決問題來了,
過擬合咋辦?
針對過擬合,有幾種辦法能夠處理:
增大樣本量
這個比較好理解吧,過擬合的主要緣由是模型太努力地去
記住訓練樣本的分佈情況,而加大樣本量,可使得訓練集的分佈更加具有普適性,噪聲對總體的影響降低。恩,咱們提升點樣本量試試:
#增大一些樣本量plot_learning_curve(LinearSVC(C=10.0), "LinearSVC(C=10.0)", X, y, ylim=(0.8, 1.1), train_sizes=np.linspace(.1, 1.0, 5))
是否是發現問題好了不少?隨着咱們增大訓練樣本量,咱們發現訓練集和交叉驗證集上的得分差距在減小,最後它們已經很是接近了。增大樣本量,最直接的方法固然是
想辦法去採集相同場景下的新數據,若是實在作不到,也能夠試試在已有數據的基礎上作一些人工的處理生成新數據(好比圖像識別中,咱們可能能夠對圖片作鏡像變換、旋轉等等),固然,這樣作必定要謹慎,強烈建議想辦法採集真實數據。
減小特徵的量(只用咱們以爲有效的特徵)
好比在這個例子中,咱們以前的數據可視化和分析的結果代表,第11和14維特徵包含的信息對識別類別很是有用,咱們能夠只用它們。
plot_learning_curve(LinearSVC(C=10.0), "LinearSVC(C=10.0) Features: 11&;14", X[:, [11, 14]], y, ylim=(0.8, 1.0), train_sizes=np.linspace(.05, 0.2, 5))
從上圖上能夠看出,過擬合問題也獲得必定程度的緩解。不過咱們這是本身觀察後,手動選出11和14維特徵。那能不能自動進行特徵組合和選擇呢,其實咱們固然能夠遍歷特徵的組合樣式,而後再進行特徵選擇(前提依舊是這裏特徵的維度不高,若是高的話,遍歷全部的組合是一個很是很是很是耗時的過程!!):
from sklearn.pipeline import Pipelinefrom sklearn.feature_selection import SelectKBest, f_classif# SelectKBest(f_classif, k=2) 會根據Anova F-value選出 最好的k=2個特徵plot_learning_curve(Pipeline([("fs", SelectKBest(f_classif, k=2)), # select two features ("svc", LinearSVC(C=10.0))]), "SelectKBest(f_classif, k=2) + LinearSVC(C=10.0)", X, y, ylim=(0.8, 1.0), train_sizes=np.linspace(.05, 0.2, 5))
若是你本身跑一下程序,會發如今咱們本身手造的這份數據集上,這個特徵篩選的過程超級順利,但依舊像咱們以前提過的同樣,這是由於特徵的維度不過高。
從另一個角度看,咱們之因此作特徵選擇,是想下降模型的複雜度,而更不容易刻畫到噪聲數據的分佈。從這個角度出發,咱們還能夠有(1)多項式你和模型中下降多項式次數 (2)神經網絡中減小神經網絡的層數和每層的結點數 (c)SVM中增長RBF-kernel的bandwidth等方式來下降模型的複雜度。
話說回來,即便以上提到的辦法下降模型複雜度後,好像能在必定程度上緩解過擬合,可是咱們通常仍是不建議一遇到過擬合,就用這些方法處理,優先用下面的方法:
加強正則化做用(好比說這裏是減少LinearSVC中的C參數)
正則化是我認爲在不損失信息的狀況下,最有效的緩解過擬合現象的方法。
plot_learning_curve(LinearSVC(C=0.1), "LinearSVC(C=0.1)", X, y, ylim=(0.8, 1.0), train_sizes=np.linspace(.05, 0.2, 5))
調整正則化係數後,發現確實過擬合現象有必定程度的緩解,但依舊是那個問題,咱們如今的係數是本身敲定的,有沒有辦法能夠自動選擇最佳的這個參數呢?能夠。咱們能夠在交叉驗證集上作grid-search查找最好的正則化係數(對於大數據樣本,咱們依舊須要考慮時間問題,這個過程可能會比較慢):
from sklearn.grid_search import GridSearchCVestm = GridSearchCV(LinearSVC(), param_grid={"C": [0.001, 0.01, 0.1, 1.0, 10.0]})plot_learning_curve(estm, "LinearSVC(C=AUTO)", X, y, ylim=(0.8, 1.0), train_sizes=np.linspace(.05, 0.2, 5))print "Chosen parameter on 100 datapoints: %s" % estm.fit(X[:500], y[:500]).best_params_
在500個點獲得的結果是:{‘C’: 0.01}
使用新的C參數,咱們再看看學習曲線:
對於特徵選擇的部分,我打算多說幾句,咱們剛纔看過了用sklearn.feature_selection中的SelectKBest來選擇特徵的過程,也提到了在高維特徵的狀況下,這個過程可能會很是很是慢。那咱們有別的辦法能夠進行特徵選擇嗎?好比說,咱們的分類器本身可否甄別那些特徵是對最後的結果有益的?這裏有個實際工做中用到的小技巧。
咱們知道:
l2正則化,它對於最後的特徵權重的影響是,儘可能打散權重到每一個特徵維度上,不讓權重集中在某些維度上,出現權重特別高的特徵。
而l1正則化,它對於最後的特徵權重的影響是,讓特徵得到的權重稀疏化,也就是對結果影響不那麼大的特徵,乾脆就拿不着權重。
那基於這個理論,咱們能夠把SVC中的正則化替換成l1正則化,讓其自動甄別哪些特徵應該留下權重。
plot_learning_curve(LinearSVC(C=0.1, penalty='l1', dual=False), "LinearSVC(C=0.1, penalty='l1')", X, y, ylim=(0.8, 1.0), train_sizes=np.linspace(.05, 0.2, 5))
好了,咱們一塊兒來看看最後特徵得到的權重:
estm = LinearSVC(C=0.1, penalty='l1', dual=False)estm.fit(X[:450], y[:450]) # 用450個點來訓練print "Coefficients learned: %s" % est.coef_print "Non-zero coefficients: %s" % np.nonzero(estm.coef_)[1]
獲得結果:
Coefficients learned: [[ 0. 0. 0. 0. 0. 0.01857999 0. 0. 0. 0.004135 0. 1.05241369 0.01971419 0. 0. 0. 0. -0.05665314 0.14106505 0.]]Non-zero coefficients: [5 9 11 12 17 18]
你看,5 9 11 12 17 18這些維度的特徵得到了權重,而第11維權重最大,也說明了它影響程度最大。
3.2.2 欠擬合定位與解決咱們再隨機生成一份數據[1000*20]的數據(可是分佈和以前有變化),從新使用LinearSVC來作分類。
#構造一份環形數據from sklearn.datasets import make_circlesX, y = make_circles(n_samples=1000, random_state=2)#繪出學習曲線plot_learning_curve(LinearSVC(C=0.25),"LinearSVC(C=0.25)",X, y, ylim=(0.5, 1.0),train_sizes=np.linspace(.1, 1.0, 5))
簡直爛出翔了有木有,二分類問題,咱們作隨機猜想,準確率都有0.5,這比隨機猜想都高不了多少!!!怎麼辦?
不要盲目動手收集更多資料,或者調整正則化參數。咱們從學習曲線上其實能夠看出來,訓練集上的準確度和交叉驗證集上的準確度都很低,這其實就對應了咱們說的『欠擬合』狀態。別急,咱們回到咱們的數據,仍是可視化看看:
f = DataFrame(np.hstack((X, y[:, None])), columns = range(2) + ["class"])_ = sns.pairplot(df, vars=[0, 1], hue="class", size=3.5)
你發現什麼了,
數據根本就沒辦法線性分割!!!,因此你再找更多的數據,或者調整正則化參數,都是無濟於事的!!!
那咱們又怎麼解決欠擬合問題呢?一般有下面一些方法:
調整你的特徵(找更有效的特徵!!)
好比說咱們觀察完如今的數據分佈,而後咱們先對數據作個映射:
# 加入原始特徵的平方項做爲新特徵X_extra = np.hstack((X, X[:, [0]]**2 + X[:, [1]]**2))plot_learning_curve(LinearSVC(C=0.25), "LinearSVC(C=0.25) + distance feature", X_extra, y, ylim=(0.5, 1.0), train_sizes=np.linspace(.1, 1.0, 5))
臥槽,少年,這準確率,被嚇尿了有木有啊!!!因此你看,選用的特徵影響太大了,固然,咱們這裏是人工模擬出來的數據,分佈太明顯了,實際數據上,會比這個麻煩一些,可是在特徵上面下的功夫仍是頗有回報的。
使用更復雜一點的模型(好比說用非線性的核函數)
咱們對模型稍微調整了一下,用了一個複雜一些的非線性rbf kernel:
from sklearn.svm import SVC# note: we use the original X without the extra featureplot_learning_curve(SVC(C=2.5, kernel="rbf", gamma=1.0), "SVC(C=2.5, kernel='rbf', gamma=1.0)",X, y, ylim=(0.5, 1.0), train_sizes=np.linspace(.1, 1.0, 5))
你看,效果依舊很贊。
3.3 關於大數據樣本集和高維特徵空間咱們在小樣本的toy dataset上,怎麼搗鼓都有好的方法。可是當數據量和特徵樣本空間膨脹很是厲害時,不少東西就沒有那麼好使了,至少是一個很耗時的過程。舉個例子說,咱們如今從新生成一份數據集,可是此次,咱們生成更多的數據,更高的特徵維度,而分類的類別也提升到5。
3.3.1 大數據情形下的模型選擇與學習曲線在上面提到的那樣一份數據上,咱們用LinearSVC可能就會有點慢了,咱們注意到機器學習算法使用圖譜推薦咱們使用 SGDClassifier。其實本質上說,這個模型也是一個線性核函數的模型,不一樣的地方是,它使用了隨機梯度降低作訓練,因此每次並無使用所有的樣本,收斂速度會快不少。再多提一點, SGDClassifier對於特徵的幅度很是敏感,也就是說,咱們在把數據灌給它以前,應該先對特徵作幅度調整,固然,用sklearn的 StandardScaler能夠很方便地完成這一點。
StandardScaler每次只使用一部分(mini-batch)作訓練,在這種狀況下,咱們使用交叉驗證(cross-validation)並非很合適,咱們會使用相對應的progressive validation:簡單解釋一下,estimator每次只會拿下一個待訓練batch在本次作評估,而後訓練完以後,再在這個batch上作一次評估,看看是否有優化。
#生成大樣本,高緯度特徵數據X, y = make_classification(200000, n_features=200, n_informative=25, n_redundant=0, n_classes=10, class_sep=2, random_state=0)#用SGDClassifier作訓練,並畫出batch在訓練先後的得分差from sklearn.linear_model import SGDClassifierest = SGDClassifier(penalty="l2", alpha=0.001)progressive_validation_score = []train_score = []for datapoint in range(0, 199000, 1000): X_batch = X[datapoint:datapoint+1000] y_batch = y[datapoint:datapoint+1000] if datapoint > 0:progressive_validation_score.append(est.score(X_batch, y_batch)) est.partial_fit(X_batch, y_batch, classes=range(10)) if datapoint > 0:train_score.append(est.score(X_batch, y_batch))plt.plot(train_score, label="train score")plt.plot(progressive_validation_score, label="progressive validation score")plt.xlabel("Mini-batch")plt.ylabel("Score")plt.legend(loc='best') plt.show()
獲得以下的結果:
從這個圖上的得分,咱們能夠看出在50個mini-batch迭代以後,數據上的得分就已經變化不大了。可是好像得分都不過高,因此咱們猜想一下,這個時候咱們的數據,處於
欠擬合狀態。咱們剛纔在小樣本集合上提到了,若是欠擬合,咱們可使用更復雜的模型,好比把核函數設置爲非線性的,但遺憾的是像rbf核函數是沒有辦法和 SGDClassifier兼容的。所以咱們只能想別的辦法了,好比這裏,咱們能夠把 SGDClassifier整個替換掉了,用 多層感知神經網來完成這個任務,咱們之因此會想到 多層感知神經網,是由於它也是一個用隨機梯度降低訓練的算法,同時也是一個非線性的模型。固然根據機器學習算法使用圖譜,也可使用
核估計(kernel-approximation)來完成這個事情。
3.3.2 大數據量下的可視化大樣本數據的可視化是一個相對比較麻煩的事情,通常狀況下咱們都要用到
降維的方法先處理特徵。咱們找一個例子來看看,能夠怎麼作,好比咱們數據集取經典的『手寫數字集』,首先找個方法看一眼這個圖片數據集。
#直接從sklearn中load數據集from sklearn.datasets import load_digitsdigits = load_digits(n_class=6)X = digits.datay = digits.targetn_samples, n_features = X.shapeprint "Dataset consist of %d samples with %d features each" % (n_samples, n_features)# 繪製數字示意圖n_img_per_row = 20img = np.zeros((10 * n_img_per_row, 10 * n_img_per_row))for i in range(n_img_per_row): ix = 10 * i + 1 for j in range(n_img_per_row):iy = 10 * j + 1img[ix:ix + 8, iy:iy + 8] = X[i * n_img_per_row + j].reshape((8, 8))plt.imshow(img, cmap=plt.cm.binary)plt.xticks([])plt.yticks([])_ = plt.title('A selection from the 8*8=64-dimensional digits dataset')plt.show()
咱們總共有1083個訓練樣本,包含手寫數字(0,1,2,3,4,5),每一個樣本圖片中的像素點平鋪開都是64位,這個維度顯然是沒辦法直接可視化的。下面咱們基於scikit-learn的示例教程對特徵用各類方法作降維處理,再可視化。
隨機投射
咱們先看看,把數據隨機投射到兩個維度上的結果:
#import所需的packagefrom sklearn import (manifold, decomposition, random_projection)rp = random_projection.SparseRandomProjection(n_components=2, random_state=42)#定義繪圖函數from matplotlib import offsetboxdef plot_embedding(X, title=None): x_min, x_max = np.min(X, 0), np.max(X, 0) X = (X - x_min) / (x_max - x_min) plt.figure(figsize=(10, 10)) ax = plt.subplot(111) for i in range(X.shape[0]):plt.text(X[i, 0], X[i, 1], str(digits.target[i]), color=plt.cm.Set1(y[i] / 10.), fontdict={'weight': 'bold', 'size': 12}) if hasattr(offsetbox, 'AnnotationBbox'):# only print thumbnails with matplotlib > 1.0shown_images = np.array([[1., 1.]]) # just something bigfor i in range(digits.data.shape[0]): dist = np.sum((X[i] - shown_images) ** 2, 1) if np.min(dist) < 4e-3:# don't show points that are too closecontinue shown_images = np.r_[shown_images, [X[i]]] imagebox = offsetbox.AnnotationBbox(offsetbox.OffsetImage(digits.images[i], cmap=plt.cm.gray_r),X[i]) ax.add_artist(imagebox) plt.xticks([]), plt.yticks([]) if title is not None:plt.title(title)#記錄開始時間start_time = time.time()X_projected = rp.fit_transform(X)plot_embedding(X_projected, "Random Projection of the digits (time: %.3fs)" % (time.time() - start_time))
結果以下:
PCA降維
在維度約減/降維領域有一個很是強大的算法叫作PCA(Principal Component Analysis,主成分分析),它能將原始的絕大多數信息用維度遠低於原始維度的幾個主成分表示出來。PCA在咱們如今的數據集上效果還不錯,咱們來看看用PCA對原始特徵降維至2維後,原始樣本在空間的分佈情況:
from sklearn import (manifold, decomposition, random_projection)#TruncatedSVD 是 PCA的一種實現X_pca = decomposition.TruncatedSVD(n_components=2).fit_transform(X)#記錄時間start_time = time.time()plot_embedding(X_pca,"Principal Components projection of the digits (time: %.3fs)" % (time.time() - start_time))
獲得的結果以下:
咱們能夠看出,效果還不錯,不一樣的手寫數字在2維平面上,顯示出了區域集中性。即便它們之間有必定的重疊區域。
若是咱們用一些
非線性的變換來作降維操做,從原始的64維降到2維空間,效果更好,好比這裏咱們用到一個技術叫作t-SNE,sklearn的manifold對其進行了實現:
from sklearn import (manifold, decomposition, random_projection)#降維tsne = manifold.TSNE(n_components=2, init='pca', random_state=0)start_time = time.time()X_tsne = tsne.fit_transform(X)#繪圖plot_embedding(X_tsne, "t-SNE embedding of the digits (time: %.3fs)" % (time.time() - start_time))
咱們發現結果很是的驚人,彷佛這個非線性變換降維事後,僅僅2維的特徵,就能夠將原始數據的不一樣類別,在平面上很好地劃分開。不過t-SNE也有它的缺點,通常說來,相對於線性變換的降維,它須要更多的計算時間。也不太適合在大數據集上全集使用。
3.4 損失函數的選擇損失函數的選擇對於問題的解決和優化,很是重要。咱們先來看一眼各類不一樣的損失函數:
import numpy as npimport matplotlib.plot as plt# 改自http://scikit-learn.org/stable/auto_examples/linear_model/plot_sgd_loss_functions.htmlxmin, xmax = -4, 4xx = np.linspace(xmin, xmax, 100)plt.plot([xmin, 0, 0, xmax], [1, 1, 0, 0], 'k-', label="Zero-one loss")plt.plot(xx, np.where(xx < 1, 1 - xx, 0), 'g-', label="Hinge loss")plt.plot(xx, np.log2(1 + np.exp(-xx)), 'r-', label="Log loss")plt.plot(xx, np.exp(-xx), 'c-', label="Exponential loss")plt.plot(xx, -np.minimum(xx, 0), 'm-', label="Perceptron loss")plt.ylim((0, 8))plt.legend(loc="upper right")plt.xlabel(r"Decision function $f(x)$")plt.ylabel("$L(y, f(x))$")plt.show()
獲得結果圖像以下:
不一樣的損失函數有不一樣的優缺點:
0-1損失函數(zero-one loss)很是好理解,直接對應分類問題中判斷錯的個數。可是比較尷尬的是它是一個非凸函數,這意味着其實不是那麼實用。
hinge loss(SVM中使用到的)的健壯性相對較高(對於異常點/噪聲不敏感)。可是它沒有那麼好的機率解釋。
log損失函數(log-loss)的結果能很是好地表徵機率分佈。所以在不少場景,尤爲是多分類場景下,若是咱們須要知道結果屬於每一個類別的置信度,那這個損失函數很適合。缺點是它的健壯性沒有那麼強,相對hinge loss會對噪聲敏感一些。
多項式損失函數(exponential loss)(AdaBoost中用到的)對離羣點/噪聲很是很是敏感。可是它的形式對於boosting算法簡單而有效。
感知損失(perceptron loss)能夠看作是hinge loss的一個變種。hinge loss對於斷定邊界附近的點(正確端)懲罰力度很高。而perceptron loss,只要樣本的斷定類別結果是正確的,它就是滿意的,而無論其離斷定邊界的距離。優勢是比hinge loss簡單,缺點是由於不是max-margin boundary,因此獲得模型的泛化能力沒有hinge loss強。
4. 總結全文到此就結束了。先蜻蜓點水看了一遍機器學習的算法,而後給出了對應scikit-learn的『祕密武器』機器學習算法使用圖譜,緊接着從瞭解數據(可視化)、選擇機器學習算法、定位過/欠擬合及解決方法、大量極的數據可視化和損失函數優缺點與選擇等方面介紹了實際機器學習問題中的一些思路和方法。本文和文章機器學習系列(3)_邏輯迴歸應用之Kaggle泰坦尼克之災都說起了一些處理實際機器學習問題的思路和方法,有類似和互補之處,歡迎你們參照着看。