前面章節嘗試了K均值聚類模型,准確率並不高。接下來我們嘗試一種新方法:支持向量機(SVM)。
支持向量機
支持向量機(support vector machine/SVM),通俗來講,它是一種二類分類模型,其基本模型定義為特征空間上的間隔最大的線性分類器,其學習策略便是間隔最大化,最終可轉化為一個凸二次規划問題的求解。本系列教程聚焦於SciKit-Learn 庫的使用介紹,關於支持向量機詳細原理,限於篇幅不再贅述,讀者可參考相關資料。
如前所訴,K均值聚類模型是一種無監督學習模型,與此不同,支持向量機是一種有監督學習模型,是很常用的一種機器學習模型。
創建模型
下面的代碼,創建了一個支持向量機模型。
import numpy as np from sklearn import datasets # 加載 `digits` 數據集 digits = datasets.load_digits() # 導入 `train_test_split` from sklearn.model_selection import train_test_split # 數據分成訓練集和測試集 # `test_size`:如果是浮點數,在0-1之間,表示測試子集占比;如果是整數的話就是測試子集的樣本數量,`random_state`:是隨機數的種子 X_train, X_test, y_train, y_test, images_train, images_test = train_test_split(digits.data, digits.target, digits.images, test_size=0.33, random_state=42) # 導入“svm”模型 from sklearn import svm # 創建SVC/Support Vector Classification/支持向量機分類器模型 svc_model = svm.SVC(gamma=0.001, C=100., kernel='linear') # 將數據擬合到SVC模型中,此處用到了標簽值y_train,是有監督學習 svc_model.fit(X_train, y_train)
可以看到,我們使用X_train
和y_train
數據來訓練SVC模型(Support Vector Classification/支持向量機分類器模型),此處用到了標簽值y_train
,是有監督學習。
另外,我們手動設置了gamma
的值,通過使用網格搜索和交叉驗證等工具,可以自動找到合適的參數值。
測試模型
接下來,我們使用測試數據測試模型。
# 預測“X_test”標簽 print(svc_model.predict(X_test)) # 打印' y_test '檢查結果 print(y_test)
輸出:
[6 9 3 7 2 1 5 2 5 2 1 4 4 0 4 2 3 7 8 8 4 3 9 7 5 6 3 5 6 3 4 9 1 4 4 6 9 4 7 6 6 9 1 3 6 1 3 0 6 5 5 1 9 5 6 0 9 0 0 1 0 4 5 2 4 5 7 0 7 5 9 5 5 4 7 0 4 5 5 9 9 0 2 3 8 0 6 4 4 9 1 2 8 3 5 2 9 0 4 4 4 3 5 3 1 3 5 9 4 2 7 7 4 4 1 9 2 7 8 7 2 6 9 4 0 7 2 7 5 8 7 5 7 9 0 6 6 4 2 8 0 9 4 6 9 9 6 9 0 5 5 6 6 0 6 4 3 9 3 9 7 2 9 0 4 5 3 6 5 9 9 8 4 2 1 3 7 7 2 2 3 9 8 0 3 2 2 5 6 9 9 4 1 5 4 2 3 6 4 8 5 9 5 7 8 9 4 8 1 5 4 4 9 6 1 8 6 0 4 5 2 7 4 6 4 5 6 0 3 2 3 6 7 1 5 1 4 7 6 5 8 5 5 1 6 2 8 8 9 9 7 6 2 2 2 3 4 8 8 3 6 0 9 7 7 0 1 0 4 5 1 5 3 6 0 4 1 0 0 3 6 5 9 7 3 5 5 9 9 8 5 3 3 2 0 5 8 3 4 0 2 4 6 4 3 4 5 0 5 2 1 3 1 4 1 1 7 0 1 5 2 1 2 8 7 0 6 4 8 8 5 1 8 4 5 8 7 9 8 5 0 6 2 0 7 9 8 9 5 2 7 7 1 8 7 4 3 8 3 5 6 0 0 3 0 5 0 0 4 1 2 3 4 5 9 6 3 1 8 8 4 2 3 8 9 8 8 5 0 6 3 3 7 1 6 4 1 2 1 1 6 4 7 4 8 3 4 0 5 1 9 4 5 7 6 3 7 0 5 9 7 5 9 7 4 2 1 9 0 7 5 8 3 6 3 9 6 9 5 0 1 5 5 8 3 3 6 2 6 5 7 2 0 8 7 3 7 0 2 2 3 5 8 7 3 6 5 9 9 2 9 6 3 0 7 1 1 9 6 1 8 0 0 2 9 3 9 9 3 7 7 1 3 5 4 6 1 2 1 1 8 7 6 9 2 0 4 4 8 8 7 1 3 1 7 1 8 5 1 7 0 0 2 2 6 9 4 1 9 0 6 7 7 9 5 4 7 0 7 6 8 7 1 4 6 2 8 7 5 9 0 3 9 6 6 1 9 1 2 9 8 9 7 4 8 5 5 9 7 7 6 8 1 3 5 7 9 5 5 2 4 1 2 2 4 8 7 5 8 8 9 4 9 0] [6 9 3 7 2 1 5 2 5 2 1 9 4 0 4 2 3 7 8 8 4 3 9 7 5 6 3 5 6 3 4 9 1 4 4 6 9 4 7 6 6 9 1 3 6 1 3 0 6 5 5 1 9 5 6 0 9 0 0 1 0 4 5 2 4 5 7 0 7 5 9 5 5 4 7 0 4 5 5 9 9 0 2 3 8 0 6 4 4 9 1 2 8 3 5 2 9 0 4 4 4 3 5 3 1 3 5 9 4 2 7 7 4 4 1 9 2 7 8 7 2 6 9 4 0 7 2 7 5 8 7 5 7 7 0 6 6 4 2 8 0 9 4 6 9 9 6 9 0 3 5 6 6 0 6 4 3 9 3 9 7 2 9 0 4 5 3 6 5 9 9 8 4 2 1 3 7 7 2 2 3 9 8 0 3 2 2 5 6 9 9 4 1 5 4 2 3 6 4 8 5 9 5 7 8 9 4 8 1 5 4 4 9 6 1 8 6 0 4 5 2 7 4 6 4 5 6 0 3 2 3 6 7 1 5 1 4 7 6 8 8 5 5 1 6 2 8 8 9 9 7 6 2 2 2 3 4 8 8 3 6 0 9 7 7 0 1 0 4 5 1 5 3 6 0 4 1 0 0 3 6 5 9 7 3 5 5 9 9 8 5 3 3 2 0 5 8 3 4 0 2 4 6 4 3 4 5 0 5 2 1 3 1 4 1 1 7 0 1 5 2 1 2 8 7 0 6 4 8 8 5 1 8 4 5 8 7 9 8 5 0 6 2 0 7 9 8 9 5 2 7 7 1 8 7 4 3 8 3 5 6 0 0 3 0 5 0 0 4 1 2 8 4 5 9 6 3 1 8 8 4 2 3 8 9 8 8 5 0 6 3 3 7 1 6 4 1 2 1 1 6 4 7 4 8 3 4 0 5 1 9 4 5 7 6 3 7 0 5 9 7 5 9 7 4 2 1 9 0 7 5 3 3 6 3 9 6 9 5 0 1 5 5 8 3 3 6 2 6 5 5 2 0 8 7 3 7 0 2 2 3 5 8 7 3 6 5 9 9 2 5 6 3 0 7 1 1 9 6 1 1 0 0 2 9 3 9 9 3 7 7 1 3 5 4 6 1 2 1 1 8 7 6 9 2 0 4 4 8 8 7 1 3 1 7 1 9 5 1 7 0 0 2 2 6 9 4 1 9 0 6 7 7 9 5 4 7 0 7 6 8 7 1 4 6 2 8 7 5 9 0 3 9 6 6 1 9 8 2 9 8 9 7 4 8 5 5 9 7 7 6 8 1 3 5 7 9 5 5 2 1 1 2 2 4 8 7 5 8 8 9 4 9 0]
我們也可以使用matplotlib可視化測試數據及其預測標簽:
# 導入 matplotlib import matplotlib.pyplot as plt # 將預測值賦給 `predicted` predicted = svc_model.predict(X_test) # 將images_test和images_prediction中的預測值壓縮在一起 images_and_predictions = list(zip(images_test, predicted)) # 對於images_and_prediction中的前四個元素 for index, (image, prediction) in enumerate(images_and_predictions[:4]): # 在坐標i+1處初始化一個1×4的網格中的子圖 plt.subplot(1, 4, index + 1) # 不顯示坐標軸 plt.axis('off') # 在網格中的所有子圖中顯示圖像 plt.imshow(image, cmap=plt.cm.gray_r, interpolation='nearest') # 添加標題 plt.title('Predicted: ' + str(prediction)) # 顯示圖形 plt.show()
顯示:
可以看到顯示的這幾張圖形,預測的標簽都是正確的。
評估模型
最后,我們來評估一下模型的性能,看看它准確率怎么樣。
# 導入 `metrics` from sklearn import metrics # 打印的分類報告 `y_test` 與 `predicted` print(metrics.classification_report(y_test, predicted)) # 打印“y_test”和“predicted”的混淆矩陣 print(metrics.confusion_matrix(y_test, predicted))
輸出:
precision recall f1-score support 0 1.00 1.00 1.00 55 1 0.98 0.96 0.97 55 2 1.00 1.00 1.00 52 3 0.98 0.96 0.97 56 4 0.97 1.00 0.98 64 5 0.97 0.97 0.97 73 6 1.00 1.00 1.00 57 7 0.98 0.98 0.98 62 8 0.94 0.94 0.94 52 9 0.97 0.97 0.97 68 accuracy 0.98 594 macro avg 0.98 0.98 0.98 594 weighted avg 0.98 0.98 0.98 594 [[55 0 0 0 0 0 0 0 0 0] [ 0 53 0 0 1 0 0 0 1 0] [ 0 0 52 0 0 0 0 0 0 0] [ 0 0 0 54 0 1 0 0 1 0] [ 0 0 0 0 64 0 0 0 0 0] [ 0 0 0 0 0 71 0 1 0 1] [ 0 0 0 0 0 0 57 0 0 0] [ 0 0 0 0 0 0 0 61 0 1] [ 0 1 0 1 0 1 0 0 49 0] [ 0 0 0 0 1 0 0 0 1 66]]
可以看到,這個模型比前面章節的K均值聚類模型,效果要好得多。
我們再看一下預測標簽與實際標簽的散點圖。
# 導入 `Isomap()` from sklearn.manifold import Isomap # 創建一個isomap,並將“digits”數據放入其中 X_iso = Isomap(n_neighbors=10).fit_transform(X_train) # 計算聚類中心並預測每個樣本的聚類指數 predicted = svc_model.predict(X_train) # 在1X2的網格中創建帶有子圖的圖 fig, ax = plt.subplots(1, 2, figsize=(8, 4)) # 調整布局 fig.subplots_adjust(top=0.85) # 將散點圖添加到子圖中 ax[0].scatter(X_iso[:, 0], X_iso[:, 1], c=predicted) ax[0].set_title('Predicted labels') ax[1].scatter(X_iso[:, 0], X_iso[:, 1], c=y_train) ax[1].set_title('Actual Labels') # 加標題 fig.suptitle('Predicted versus actual labels', fontsize=14, fontweight='bold') # 顯示圖形 plt.show()
顯示
從圖中可以看出,模型的預測結果與實際結果匹配度非常好,模型的准確率很高。
參數值
前面在創建模型時,手動設置了gamma
等參數的值,通過使用網格搜索和交叉驗證等工具,可以自動找到合適的參數值。
盡管這不是本篇教程的重點,本節內容演示如何使用網格搜索和交叉驗證等工具,自動找到合適的參數值。
import numpy as np from sklearn import datasets # 加載 `digits` 數據集 digits = datasets.load_digits() # 導入 `train_test_split` from sklearn.model_selection import train_test_split # 將 `digits` 數據分成兩個相等數量的集合 X_train, X_test, y_train, y_test = train_test_split(digits.data, digits.target, test_size=0.5, random_state=0) # 導入“svm”模型 from sklearn import svm # 導入 GridSearchCV from sklearn.model_selection import GridSearchCV # 設置參數候選項 parameter_candidates = [ {'C': [1, 10, 100, 1000], 'kernel': ['linear']}, {'C': [1, 10, 100, 1000], 'gamma': [0.001, 0.0001], 'kernel': ['rbf']}, ] # 使用參數候選項創建分類器 clf = GridSearchCV(estimator=svm.SVC(), param_grid=parameter_candidates, n_jobs=-1) # 根據訓練數據訓練分類器 clf.fit(X_train, y_train) # 打印結果 print('訓練數據的最佳得分:', clf.best_score_) print('最佳懲罰參數C:',clf.best_estimator_.C) print('最佳內核類型:',clf.best_estimator_.kernel) print('最佳gamma值:',clf.best_estimator_.gamma) # 將分類器應用到測試數據上,查看准確率得分 clf.score(X_test, y_test) # 用網格搜索參數訓練一個新的分類器,評估得分 score = svm.SVC(C=10, kernel='rbf', gamma=0.001).fit(X_train, y_train).score(X_test, y_test) print(score)
輸出
C:\Anaconda3\python.exe "C:\Program Files\JetBrains\PyCharm 2019.1.1\helpers\pydev\pydevconsole.py" --mode=client --port=64053
import sys; print('Python %s on %s' % (sys.version, sys.platform))
sys.path.extend(['C:\\app\\PycharmProjects', 'C:/app/PycharmProjects'])
Python 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.12.0 -- An enhanced Interactive Python. Type '?' for help.
PyDev console: using IPython 7.12.0
Python 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)] on win32
runfile('C:/app/PycharmProjects/ArtificialIntelligence/test.py', wdir='C:/app/PycharmProjects/ArtificialIntelligence')
訓練數據的最佳得分: 0.9866480446927375
最佳懲罰參數C: 10
最佳內核類型: rbf
最佳gamma值: 0.001
0.9911012235817576
可以看到,我們獲取到了合適的參數。