1. 程式人生 > >用機器學習解決問題的思路

用機器學習解決問題的思路

當我們拿到一堆資料時,該如何去下手?
1. 首先要視覺化,瞭解資料
2. 選擇合適的機器學習演算法
3. 分析所得模型的狀態(過擬合、欠擬合)並解決
4. 大量級資料的特徵分析和視覺化
5. 各種損失函式的優缺點及選擇

1 資料視覺化

這裡寫圖片描述
然而當大量資料出現的時候,影象視覺化就可以讓我們直觀的理解資料的分佈和特性,比如 雜湊分佈圖和柱狀圖。 python中視覺化包: matplotlib 或者 Seaborn等。

安裝:

pip install 包名

這裡寫圖片描述
這裡寫圖片描述

從上圖可以看出:
第11維和第14維在一起可以很好的區分資料,類似的還有8和11、11和12等。而12和19則具有很強的負相關性。

下面計算各維度特徵之間(以及最後的類別)的相關性,來驗證上面的結論。
最新版的seaborn中取消了corrplot,代替為heatmap,官方示例:
Plotting a diagonal correlation matrix

這裡寫圖片描述
這裡寫圖片描述

可以看到第11維特徵和第14維特徵和類別有極強的相關性(顏色很淺),同時它們倆之間也有極高的相關性。而第12維特徵和第19維特徵卻呈現出極強的負相關性(顏色很深)。

強相關的特徵其實包含了一些冗餘的特徵,而除掉上圖中顏色較深的特徵,其餘特徵包含的資訊量就沒有這麼大了,它們和最後的類別相關度不高,甚至各自之間也沒什麼先慣性。

對於大量級資料處理,後面會介紹到。

2 機器學習演算法選擇

Ng說過做機器學習,先嚐試做出一個baseline然後再去嘗試改進。
根據機器學習圖譜:
這裡寫圖片描述

選擇使用LinearSVC(線性核SVM分類)。
原作者自己寫了一個函式,用來畫學習曲線,呼叫也很簡單。該函式可以畫出訓練集和測試集的精確度和方差情況。

#繪製學習曲線,以確定模型的狀況
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()

使用svc的結果:
這裡寫圖片描述
從圖中可以看出:隨著樣本數的增加訓練score下降,交叉驗證得分上升,並且兩者差距很大,訓練集上的識別率遠高於測試集,說明模型處於過擬合狀態

3 過擬合的解決

有幾種方法可以處理:
1 增加樣本量,(相當於給出更多的練習題目,不讓他們去死記硬背所有的答案)

2 減少特徵的量(簡化了模型,降低了方差,提高了偏差)
從另外一個角度看,我們之所以做特徵選擇,是想降低模型的複雜度,而更不容易刻畫到噪聲資料的分佈。從這個角度出發,我們還可以有
(1)多項式你和模型中降低多項式次數
(2)神經網路中減少神經網路的層數和每層的結點數
(3)SVM中增加RBF-kernel的bandwidth等方式來降低模型的複雜度。

3 增強正則化引數(最有效的辦法)
尋找最優的引數可以在在交叉驗證集上做grid-search查詢最好的正則化係數(對於大資料樣本,我們依舊需要考慮時間問題,這個過程可能會比較慢)。

在自動選擇特徵中有一個小技巧:
1: l2正則化,它對於最後的特徵權重的影響是,儘量打散權重到每個特徵維度上,不讓權重集中在某些維度上,出現權重特別高的特徵。
2: l1正則化,它對於最後的特徵權重的影響是,讓特徵獲得的權重稀疏化,也就是對結果影響不那麼大的特徵,乾脆就拿不著權重。

對於欠擬合解決:
1 調整你的特徵(找更有效的特徵!!, 高維特徵)
2 使用更復雜一點的模型(比如說用非線性的核函式)

4 關於大資料樣本集和高維特徵空間

對於大量的資料而言,我們用LinearSVC可能就會有點慢了,我們注意到機器學習演算法使用圖譜推薦我們使用SGDClassifier。

其實本質上說,這個模型也是一個線性核函式的模型,不同的地方是,它使用了隨機梯度下降做訓練,所以每次並沒有使用全部的樣本,收斂速度會快很多。再多提一點,SGDClassifier對於特徵的幅度非常敏感,也就是說,我們在把資料灌給它之前,應該先對特徵做幅度調整,當然,用sklearn的StandardScaler可以很方便地完成這一點。

SGDClassifier每次只使用一部分(mini-batch)做訓練,在這種情況下,我們使用交叉驗證(cross-validation)並不是很合適,我們會使用相對應的progressive validation:簡單解釋一下,estimator每次只會拿下一個待訓練batch在本次做評估,然後訓練完之後,再在這個batch上做一次評估,看看是否有優化

對於大資料下的視覺化

首先需要的是降維。具體的過程參考原文,原文已經介紹的幾種方法都非常有效

損失函式的對比

這裡寫圖片描述
不同的損失函式有不同的優缺點:

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強。