scikit-learn官網:http://scikit-learn.org/stable/
通常情況下,一個學習問題會包含一組學習樣本數據,計算機通過對樣本數據的學習,嘗試對未知數據進行預測。
學習問題一般可以分為:
- 監督學習(supervised learning)
- 分類(classification)
- 回歸(regression)
- 非監督學習(unsupervised learning)
- 聚類(clustering)
監督學習和非監督學習的區別就是,監督學習中,樣本數據會包含要預測的標簽(label),例如給定一組貓和狗的圖片並對不同的照片給定對應的標簽(貓或狗),而非監督學習只會給定一組圖片,並不會給出標簽。
分類和回歸的區別是,分類的樣本數據中的標簽有大於等於2種,對於預測數據只需要判斷屬於其中哪個類即可,而回歸則是期望輸出由一個或多個連續的變量組成,例如根據魚的年齡和重量推斷魚的長度。
對於一個已知問題,如何判斷需要使用那種方法,scikit-learn給出了一個圖,可以根據這個圖來確定,鏈接:
http://scikit-learn.org/stable/tutorial/machine_learning_map/index.html
接下來的內容包括:
- 樣本數據的獲取和生成
- 分類器訓練和預測
- 持久化分類器
- 簡單交叉驗證
- 例子
① 樣本數據獲取和生成
scikit-learn中包含了很多供初學者學習的樣本數據,這些數據包含在sklearn.datasets包中,比較典型的數據是iris,這個數據集給出了iris花的花瓣和萼片的長度和寬度及對應花的種類:
讀取這個數據集的方法很簡單:
1 from sklearn import datasets 2 3 # 讀取iris數據集 4 iris = datasets.load_iris() 5 # 獲取數據集中的屬性值(花瓣和萼片長度寬度) 6 iris_X = iris.data 7 # 獲取數據集中的標簽,分別是哪種花 8 iris_y = iris.target 9 10 print(iris_X[::50]) 11 print(iris_y[::50])
因為數據集是有序的並且長度為150(每種花50個),所以打印的時候步長設置為50,我們可以看到結果如下所示:
下面的這個數組就是對應的分類,這里簡化為數字123了。
在學習中,也可以手動的創造自己想要的數據集,比如生成一組回歸數據:
1 X, y = datasets.make_regression(n_samples=200, n_features=1, n_targets=1, noise=10)
得到的數據集如圖所示:
構造的方法參考API文檔即可:http://scikit-learn.org/stable/modules/classes.html#samples-generator
② 訓練分類器和進行預測
接着我們將iris數據集分為兩部分,一部分用來訓練分類器,另一部分則是用來進行測試,看看預測的正確率如何。
1 from sklearn import datasets 2 from sklearn.model_selection import train_test_split 3 from sklearn.neighbors import KNeighborsClassifier 4 5 # 讀取iris數據集 6 iris = datasets.load_iris() 7 # 獲取數據集中的屬性值(花瓣和萼片長度寬度) 8 iris_X = iris.data 9 # 獲取數據集中的標簽,分別是哪種花 10 iris_y = iris.target 11 12 # 將數據分別訓練數據和測試數據,測試數據為20% 13 train_X, test_X, train_y, test_y = train_test_split(iris_X, iris_y, test_size=0.2) 14 15 # 創建K鄰近分類器 16 knn = KNeighborsClassifier() 17 # 輸入訓練數據 18 knn.fit(train_X, train_y) 19 # 得到預測標簽 20 predicts = knn.predict(test_X) 21 22 # 對比結果 23 print(predicts) 24 print(test_y) 25 26 # 計算准確率 27 print(knn.score(test_X, test_y))
這里首先將數據分成訓練和測試數據,接着創建了一個K臨近分類器,通過fit方法傳入訓練數據,predict方法對測試數據進行測試。
得到的結果如圖:
這里的准確率可能會不同,因為使用train_test_split方法分離數據會打亂數據集順序並且隨機選擇。
這里的K臨近分類器,是一個比較簡單的分類器,對於每個測試樣本,分類器會選取K個(默認是5個)附近的點進行比較,判斷哪個分類的點多,則判斷為對應的類。因為每個樣本有四個屬性,所以樣本屬性需要一個四維空間坐標系表示,但是距離計算公式是類似二維空間的。
當然,scikit-learn還有其他的分類器,可以參考API文檔和例子:
http://scikit-learn.org/stable/supervised_learning.html#supervised-learning
③ 持久化
對於一個訓練好的模型,可以進行持久化,也就是每次需要使用模型的時候,不需要重新訓練。
持久化的方法有多種,可以利用python提供的pickle,但是scikit-learn提供了效率更高的joblib:
1 from sklearn.externals import joblib 2 # 持久化knn分類器 3 joblib.dump(knn, 'save/knn.pk') 4 # 讀取knn分類器 5 knn2 = joblib.load('save/knn.pk') 6 print(knn2.score(test_X, test_y))
④ 交叉驗證
交叉驗證就是對訓練數據和測試數據進行多次分組測試模型的准確率,再計算平均值來表示當前模型的優劣。
一個模型中的不同參數,會不同程度的影響模型的准確率,如果模型架構配置不恰當,還會出現過度擬合(overfitting)或者擬合不足(underfitting):
交叉驗證,可以通過cross_val_score方法來計算認證的每個分組的分數:
1 from sklearn import datasets 2 from sklearn.model_selection import cross_val_score 3 from sklearn.neighbors import KNeighborsClassifier 4 5 iris = datasets.load_iris() 6 X = iris.data 7 y = iris.target 8 9 knn = KNeighborsClassifier() 10 11 # 交叉驗證分數,分為5組 12 scores = cross_val_score(knn, X, y, cv=5, scoring='accuracy') 13 # 輸出分組平均值 14 print(scores.mean()) 15 16 # 讓K鄰近分類器的k從1到30取值並計算認證分數 17 k_range = range(1, 31) 18 k_scores = [] 19 for r in k_range: 20 # 設置k,也就是n_neighbors參數 21 kn = KNeighborsClassifier(n_neighbors=r) 22 # 求平均值並加入k_scores中 23 k_scores.append(cross_val_score(kn, X, y, cv=10, scoring='accuracy').mean()) 24 25 print(k_scores)
打印得到的結果:
使用print打印結果雖然能顯示,但是不直觀,這里可以通過matplotlib這個庫來生成圖表,更加直觀的看出來對於每個k,哪個的分數更高:
1 import matplotlib.pyplot as plt 2 # 以k_range為x,k_scores為y,擬點並連線 3 plt.plot(k_range, k_scores) 4 # 設置x和y的標簽 5 plt.xlabel('n_neighbors') 6 plt.ylabel('score') 7 # 展示圖表 8 plt.show()
可以看到,k並非越大越好,我們得到這個圖表,就可以選擇一個得分高對應的k,例如上圖的13作為模型的n_neighbors參數。
⑤ 例子
這個例子也是datasets中包含的,手寫體數字分類。這里使用官方的一個例子:
http://scikit-learn.org/stable/auto_examples/classification/plot_digits_classification.html#sphx-glr-auto-examples-classification-plot-digits-classification-py
訓練完了之后,持久化模型,接着可以嘗試預測一下我們自己設計的數字(8*8像素灰度圖片,放大模糊了):
測試代碼:
1 from PIL import Image 2 import numpy as np 3 from sklearn.externals import joblib 4 5 # 使用pil獲取每個像素點的顏色信息(灰度圖為二維數組) 6 img = Image.open('four.jpg') 7 img = np.array(img) 8 for i in range(8): 9 for j in range(8): 10 # 根據datasets中的數據修改圖片數據信息 11 img[i][j] //= 16 12 img[i][j] = 15 - img[i][j] 13 14 clf = joblib.load('save/digit') 15 print('推斷圖片中的數字為:', clf.predict(img.reshape((1, -1))))
結果:
最后,關於回歸和聚類的demo,可以參考官方的Examples:
http://scikit-learn.org/stable/auto_examples/index.html
有誤,請指出,萬分感謝