1 分類
分類是将事物按特性進行分類,例如将手寫數字圖檔分類為對應的數字。
1.1 MINIST數字圖檔集分類
MINST就是一個70000張規格較小的手寫數字圖檔,如何将他們分類為對應的數字?MINIST這個資料集是由矩陣數組結構,70000個矩陣,每個矩陣28*28=784,每個點代表一個像素值,取值範圍在0-256之間。

(1)擷取資料集
Scikit-Learn 提供了許多輔助函數,以便于下載下傳流行的資料集。
from sklearn.datasets import fetch_mldata
>>> mnist = fetch_mldata('MNIST original')#擷取數字資料集
>>> mnist {'COL_NAMES': ['label', 'data'], 'DESCR': 'mldata.org dataset: mnist-original', 'data': array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], ..., [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]], dtype=uint8), 'target': array([ 0., 0., 0., ..., 9., 9., 9.])}
data是資料集,target是目标數字,也就是每個圖檔矩陣代表的真實數字。
(2)擷取其中一個圖檔資料轉換後畫圖顯示
x, y = mnist["data"], mnist["target"] #擷取資料集中的資料
%matplotlib inline#聲明使用jupyter的後端渲染圖檔
import matplotlib import matplotlib.pyplot as plt #引入畫圖
some_digit = X[36000] #取第36000個資料,是一個784的長形數組
some_digit_image = some_digit.reshape(28, 28) #轉換為28*28的矩陣
plt.imshow(some_digit_image, cmap = matplotlib.cm.binary, interpolation="nearest") plt.axis("off") plt.show()#畫出矩陣圖檔顯示數字
(3)準備資料訓練
分成了一個訓練集(前 60000 張圖檔)和一個測試集(最後 10000 張圖檔),冒号在前表示取前60000之前的資料,冒号在後表示取60000之後的資料。
X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000],y[60000:]
打亂訓練集,洗牌,避免不均勻分布。
import numpy as np
shuffle_index = np.random.permutation(60000) X_train, y_train = X_train[shuffle_index], y_train[shuffle_index]
1.2 二分類器訓練
二分類器就是是和否的分類,比較簡單。
(1)首先擷取訓練集和測試集中的為5的資料子集
y_train_5 = (y_train == 5) # True for all 5s, False for all other
digits. y_test_5 = (y_test == 5)
(2)用Scikit-Learn 的 SGDClassifier分類器去訓練。這個分類器能夠高效地處理非常大的資料 集。可以一次隻處理一條資料,适合線上學習。
from sklearn.linear_model import SGDClassifier #引入
sgd_clf = SGDClassifier(random_state=42) #建立分類器對象
sgd_clf.fit(X_train, y_train_5)#訓練
sgd_clf.predict([some_digit]) #測試
array([ True], dtype=bool)#測試結果正确
1.3 性能評估
1.3.1 使用交叉驗證評估性能
讓我們使用 cross_val_score() 函數來評估 SGDClassifier 模型,同時使用K折交叉驗證,此 處讓 k=3 。即兩組訓練,一組測試,共測試三輪。
from sklearn.model_selection import cross_val_score
cross_val_score(sgd_clf, X_train, y_train_5, cv=3, scoring="accuracy")
array([ 0.9502 , 0.96565, 0.96495]
1.3.2 混淆矩陣
(1)混淆矩陣的定義
混淆矩陣是指列舉出判斷錯誤和判斷正确的次數的矩陣。例如上面的二分器,判斷為非5的正确的和錯誤,已經判斷為5的正确的和錯誤的。得到一個2*2的矩陣。為了計算混淆矩陣,首先你需要有一系列的預測值,這樣才能将預測值與真實值做比較。
(2)擷取預測值
from sklearn.model_selection import cross_val_predict y_train_pred = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3)
cross_val_predict() 也使用 K折交叉驗證。傳回基于每一個測試折做出的一個預測值。
(3)根據預測值和實際值生成混淆矩陣
在使用 confusion_matrix() 函數,你将會得到一個混淆矩陣。傳遞目标類(y_train_5)和預 測類( y_train_pred )給它。
>>> from sklearn.metrics import confusion_matrix
>>> confusion_matrix(y_train_5, y_train_pred)
array([[53272, 1307],
[ 1077, 4344]])
53272表示判斷為正确的非5(true negative),1307表示判斷為錯誤的非5(false negative)。1077表示判斷為錯誤的5(false positive),4344表示判斷為正确的5(true positive)。
(4)準确率和召回率定義
準确率(precision):true positive/( true positive+ false positive)=4344/(1077+4344)
召回率(recall):也叫做敏 感度(sensitivity)或者真正例率(true positive rate, TPR)
recall=ture positive/(true postive+false negative)=4344/(4344+1307)
(1) 準确率和召回率函數計算
Scikit-Learn 提供了一些函數去計算分類器的名額,包括準确率和召回率。
>>> from sklearn.metrics import precision_score, recall_score
>>> precision_score(y_train_5, y_pred) # == 4344 / (4344 + 1307) 0.76871350203503808
>>> recall_score(y_train_5, y_train_pred) # == 4344 / (4344 + 1077) 0.79136690647482011
(2) 調和平均值F1
常結合準确率和召回率來綜合的判斷算法的準确性。還需要綜合實際應用場景,綜合考慮采用哪種作為準确性的判斷的需要。當準确性和召回率都高的時候,調和平均值才會高。
1.3.3 準确性和召回率的折中
(1)準确性和召回率不能同時提升?
通常情況下提高準确性會降低召回率,反之亦然,即他們是互斥的。為什麼準确性和召回率不能同時提升?按照公式将false positive和false negative值都減小不就可以同時提高準确性和召回率,理想情況下,false positive和false negative都為0,準确性和召回率都為100%,為什麼不能同時提高呢?
precision=true positive/( true positive+ false positive)=4344/(1077+4344)
recall=ture positive/(true postive+false negative)=4344/(4344+1307)
(2)原因分析
如下圖所示, SGDClassifier分類器會對分析的資料進行評分,然後按照分數從小到大排列,設定一個門檻值,大于門檻值時判定為positive,小于門檻值判定為negative。門檻值越大準确性越高,但是同時有些是5的資料被判定到negative中,變成false negative,雖然準确性達到100%,但是false negative的數量也增加了,召回率變成50%。
(3)擷取單個資料評分值
Scikit-Learn 不讓你直接設定門檻值,但是它給你提供了擷取決策分數的方法decision_function()。這個方法傳回每一個樣例的分數值,你自己設定門檻值去預測。
>>>some_digit = X[36000]#取一個資料
>>> y_score = sgd_clf.decision_function([some_digit])#擷取這個資料的評分值
>>> y_scores #顯示評分值
array([ 161855.74572176])
>>> threshold = 0 #設定門檻值為0
>>> y_some_digit_pred=(y_scores>threshold) #布爾值指派顯示y_score大于0是以為true
array([ True], dtype=bool)
>>> threshold = 200000#重新設定門檻值200000
>>> y_some_digit_pred =(y_score >threshold) # y_score小于門檻值
>>> y_some_digit_pred array([False], dtype=bool)#得出false
(1) 擷取所有資料的評分值
用cross_val_predict()交叉預測方法,設定method="decision_function",得到的不是預測值,而是得到每一個樣例的分數值。
y_scores = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3, method="decision_function")
(5)根據評分調用函數precision_recall_curve計算準确率和召回率
現在有了這些分數值。對于任何可能的門檻值,使用 precision_recall_curve() ,你都可以計算 準确率和召回率:
from sklearn.metrics import precision_recall_curve
precisions, recalls, thresholds = precision_recall_curve(y_train_5, y_scores)
(6)定義畫圖函數畫出準确率和召回率相對于不同門檻值的曲線
def plot_precision_recall_vs_threshold(precisions, recalls, thresholds): plt.plot(thresholds, precisions[:-1], "b--", label="Precision") plt.plot(thresholds, recalls[:-1], "g-", label="Recall") plt.xlabel("Threshold")
plt.legend(loc="upper left")
plt.ylim([0, 1])
plot_precision_recall_vs_threshold(precisions, recalls, thresholds) plt.show()
你可以畫出準确率和召回率的曲線圖,在曲線圖上根據實際項目應用确定準确率和召回率。
1.3.4 ROC曲線
(1)定義
ROC(Receiver Operating Characteristic)曲線是橫坐标為假正率,縱坐标為真正率的曲線圖。假正率是指判為真的當中假的數量,站總的假的數量的比值。真正率是指判為真的當中真的數量占總的真的數量的比值,和召回率意義一樣。還用之前的例子,如下圖所示,共有12個數字,其中6個是真5,其他6個是假5。左一位置處,真正率為6/6=100%,假正率為2/6的33.33%。中間位置,真正率為4/6=66.66%,假正率為1/6=16.67%。右側位置處,真正率為3/6=50%,假正率為0/6=0%。
(2) 曲線下方面積比較分類器性能
roc曲線下面的面積越大,或roc曲線越靠左上角,性能越好,測量ROC曲線下的面積(AUC)評估分類器的好壞。Scikit-Learn 提供了一個函 數來計算 ROC AUC:
>>> from sklearn.metrics import roc_auc_score
>>> roc_auc_score(y_train_5, y_scores)
0.97061072797174941
(3)畫出曲線圖比較性能
也可以畫出兩個分類器的ROC曲線,看誰更接近左上角。
1)計算SGDClassifier分類器
為了畫出 ROC 曲線,你首先需要計算各種不同門檻值下的 TPR、FPR,使用 roc_curve() 函 數:
from sklearn.metrics import roc_curve
fpr, tpr, thresholds = roc_curve(y_train_5, y_scores)
2)計算RandomForestClassifier的TPR和FPR
RandomForestClassifier 不提供 decision_function() 方法。相反,它提供 predict_proba()方法,傳回一個數組,每一行代表一個數字記錄,每一列代表所屬于的類别,數組中數值含義是這一行這個數是這一列這個類的機率。例如數字判斷中,每一列是“是5”和“非5”,每一行是一個圖檔記錄,數組中的值是圖檔“是5”和“非5”的機率,把這個機率值作為評分值。
from sklearn.ensemble import RandomForestClassifier
forest_clf = RandomForestClassifier(random_state=42)
y_probas_forest = cross_val_predict(forest_clf, X_train, y_train_5, cv=3,method="predict_proba")
y_scores_forest = y_probas_forest[:, 1] # 是5的機率值作為評分
fpr_forest, tpr_forest, thresholds_forest = roc_curve(y_train_5,y_scores_forest)
3)畫出曲線圖
plt.plot(fpr, tpr, "b:", label="SGD") #SGD的ROC曲線圖
plot_roc_curve(fpr_forest, tpr_forest, "Random Forest") #随機森林的ROC
plt.legend(loc="bottom right")
plt.show()
如你所見, RandomForestClassifier 的 ROC 曲線比 SGDClassifier 的好得多:它更靠近左上 角。是以,它的 ROC AUC 也會更大。
>>> roc_auc_score(y_train_5, y_scores_forest)
0.99312433660038291
1.4 多分類器
1.4.1 定義
二分類器隻能區分兩個類,而多類分類器(也被叫做多項式分類器)可以區分多于兩個類。如随機森林分類器或者樸素貝葉斯分類器可以直接處理多類分類。(比如 SVM 分類器或者線性分類器)則是嚴格的二分類器。
一對所有(ONE VS ALL):例如訓練0~9共10個分類器,你想對某張 圖檔進行分類的時候,讓每一個分類器對這個圖檔進行分類,選出決策分數最高的那個分類 器。
一對1=一(ONE VS ONE)0,1之間,0,2之間……,共N(N-1)/2分類器,當你想對一張圖檔進行分類,你必須将這張圖檔跑在全部45個二分類器上。然後 看哪個類勝出。
1.4.2 SGDClassifier實作多分類
>>> sgd_clf.fit(X_train, y_train) # 訓練
>>> sgd_clf.predict([some_digit])#預測輸出是 array([ 5.])
>>> some_digit_scores = sgd_clf.decision_function([some_digit]) >>> some_digit_scores array([[-311402.62954431, -363517.28355739, -446449.5306454 , -183226.61023518, -414337.15339485, 161855.74572176, -452576.39616343, -471957.14962573, -518542.33997148, -536774.63961222]])#擷取評分
>>> np.argmax(some_digit_scores) #輸出評分最大的結果是5
1.4.3 OneVsOneClassifier 類 或者OneVsRestClassifier類
>>> from sklearn.multiclass import OneVsOneClassifier
>>> ovo_clf = OneVsOneClassifier(SGDClassifier(random_state=42)) >>> ovo_clf.fit(X_train, y_train)
>>> ovo_clf.predict([some_digit])
array([ 5.])
>>> len(ovo_clf.estimators_) 45
1.4.4 RandomForestClassifier多分類
随機森林分類器能夠直接将一個樣例 分到多個類别。你可以調用 predict_proba() ,得到樣例對應的類别的機率值的清單。
>>> forest_clf.fit(X_train, y_train)
>>> forest_clf.predict([some_digit])
array([ 5.])
>>> forest_clf.predict_proba([some_digit]) array([[ 0.1, 0. , 0. , 0.1, 0. , 0.8, 0. , 0. , 0. , 0. ]])
1.5 誤差分析
探索方案,嘗試多種模型,選擇最好的模型,用GridSearchCV調試超參數優化模型。要使用 cross_val_predict() 做出預測,然後調 用 confusion_matrix()函數。
>>> y_train_pred = cross_val_predict(sgd_clf, X_train_scaled, y_train, cv=3)
>>> conf_mx = confusion_matrix(y_train, y_train_pred) >>> conf_mx array([[5725, 3, 24, 9, 10, 49, 50, 10, 39, 4], [ 2, 6493, 43, 25, 7, 40, 5, 10, 109, 8], [ 51, 41, 5321, 104, 89, 26, 87, 60, 166, 13], [ 47, 46, 141, 5342, 1, 231, 40, 50, 141, 92], [ 19, 29, 41, 10, 5366, 9, 56, 37, 86, 189], [ 73, 45, 36, 193, 64, 4582, 111, 30, 193, 94], [ 29, 34, 44, 2, 42, 85, 5627, 10, 45, 0], [ 25, 24, 74, 32, 54, 12, 6, 5787, 15, 236], [ 52, 161, 73, 156, 10, 163, 61, 25, 5027, 123], [ 43, 35, 26, 92, 178, 28, 2, 223, 82, 5240]])
Matplotlib 的 matshow() 函數,将混淆矩陣以圖像的方式呈現,将會更 加友善。
plt.matshow(conf_mx, cmap=plt.cm.gray)
plt.show()
主對角線上意味着被分類 正确。數字 5 對應的格子看起來比其他數字要暗淡許多。資料集當中數字 5 的圖檔 比較少,又或者是分類器對于數字 5的表現不如其他數字那麼好。
将混淆矩陣的每一個值除以相應類别的 圖檔的總數目。這樣子,你可以比較錯誤率,而不是絕對的錯誤數(這對大的類别不公平)。用 0 來填充對角線正确的分類。最後得到的就是錯誤率的矩陣和圖像。
row_sums = conf_mx.sum(axis=1, keepdims=True)
norm_conf_mx = conf_mx / row_sums
np.fill_diagonal(norm_conf_mx, 0)
plt.matshow(norm_conf_mx, cmap=plt.cm.gray)
plt.show()
第 8、9 列相當亮,這告訴你許多圖檔被誤分成數字 8 或者數字 9,第一行很暗,這意味着大部分的數字 1 被正确分類。分析混淆矩陣通常可以給你提供深刻的見解去改善你的分類器。回顧這幅圖,看樣子你應該 努力改善分類器在數字 8 和數字 9 上的表現,和糾正 3/5 的混淆
1.6 多标簽分類KNeighborsClassifier
(1)分類實作
讓你的分類器給 一個樣例輸出多個類别。例如一個人臉識别分類器,這個分類 器被訓練成識别三個人臉,Alice,Bob,Charlie;然後當它被輸入一張含有 Alice 和 Bob 的 圖檔,它應該輸出 [1, 0, 1] 。(意思是:Alice 是,Bob 不是,Charlie 是)。這種輸出多個二 值标簽的分類系統被叫做多标簽分類系統。例如要對數字進行分類,兩個要求(1)大于等于7;(2)是奇數。
from sklearn.neighbors import KNeighborsClassifier #引入分類器
y_train_large = (y_train >= 7)#大于7的目标值
y_train_odd = (y_train % 2 == 1) #是奇數的目标值
y_multilabel = np.c_[y_train_large, y_train_odd] #組合兩種分類值
knn_clf = KNeighborsClassifier()#建立分類器對象
knn_clf.fit(X_train, y_multilabel)#進行分類訓練
>>> knn_clf.predict([some_digit]) #輸出5的預測值
array([[False, True]], dtype=bool)#結果為小于7,是奇數
(2)F1值評估分類器
y_train_knn_pred = cross_val_predict(knn_clf, X_train, y_train, cv=3)
>>> f1_score(y_train, y_train_knn_pred, average="macro") #平均
0.96845540180280221
,如果你的 Alice 的照片比 Bob 或者 Charlie 更多的時候,也許你想讓分類器在 Alice 的照片上具有更大的權重。設定 average="weighted" 。
1.7 多輸出分類
是多标簽分類的簡單泛化,在這裡每一個标簽可以是多類别的(比如說,它可以有多于兩個可能值)。例如去除噪音的系統,輸入是含有噪音的圖檔,輸出是一個幹淨的數字圖檔,由像素強度數組表示,一個像素是一個标簽,每個标簽的取值是 0~255。标簽的取值多範圍就是多輸出分類。
我們先給訓練資料加上噪音,然後再進行降噪處理。
noise = rnd.randint(0, 100, (len(X_train), 784)) #制造噪音
noise = rnd.randint(0, 100, (len(X_test), 784))
X_train_mod = X_train + noise #加上噪音
X_test_mod = X_test + noise
y_train_mod = X_train
y_test_mod = X_test
knn_clf.fit(X_train_mod, y_train_mod) #訓練KNeighborsClassifier分類器
clean_digit = knn_clf.predict([X_test_mod[some_index]]) #輸出降噪預測值
plot_digit(clean_digit)
自己開發了一個股票智能分析軟體,功能很強大,需要的點選下面的連結擷取:
https://www.cnblogs.com/bclshuai/p/11380657.html