用機器學習解決問題的思路
當我們拿到一堆資料時,該如何去下手?
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強。