[譯]使用scikit-learn進行機器學習(scikit-learn教程1)



原文地址:http://scikit-learn.org/stable/tutorial/basic/tutorial.html
翻譯:Tacey Wong


概要
該章節,我們將介紹貫穿scikit-learn使用中的“機器學習(Machine Learning)”這個詞匯,並給出一些簡單的學習示例。

前言

scikit-learn (Python機器學習庫)

  • 進行數據挖掘和數據分析的簡單而高效的工具
  • 任何人都可使用,可在多種場景/上下文復用
  • 基於NumPy,SciPy和matplotlib構建
  • 開放源代碼,可用於商業用途_BSD協議

分類


識別一個對象屬於那一種類別

應用:垃圾郵件檢測,圖像識別
算法:SVM(支持向量機),KNN(K近鄰),隨機森林

回歸


預測與某個對象相關聯的連續值屬性

應用:葯物反應,股票價格
算法:線性回歸,SVR(支持向量回歸),ridge regression(嶺回歸),LASSO回歸

聚類

將相似的對象自動聚集到不同的集合中

應用:顧客細分,分組試驗結果
算法:K-Means,譜聚類,mean-shift中值移動

降維

降低隨機變量的數目
可視化:可視化,提高效率
算法:PCA(主成分分析),特征選取,非負矩陣分解

模型選取


比較,驗證,參數和模型的選擇

目標:通過參數調整改進精度
模塊:網格搜索,交叉驗證,metrics(度量)

預處理

特征提取和正則化
應用: 轉換數據以便機器學習算法使用
模塊:預處理,特征提取

一、機器學習:問題設定

通常,一個學習問題是通過分析一些數據樣本來嘗試預測未知數據的屬性。如果每一個樣本不僅僅是一個單獨的數字,比如一個多維的實例(multivariate data),也就是說有着多個屬性特征.我們可以把學習問題分成如下的幾個大類:

  • (1)有監督學習
    數據帶有我們要預測的屬性。這種問題主要有如下幾種:

    • ①分類
      樣例屬於兩類或多類,我們想要從已經帶有標簽的數據學習以預測未帶標簽的數據。識別手寫數字就是一個分類問題,這個問題的主要目標就是把每一個輸出指派到一個有限的類別中的一類。另一種思路去思考分類問題,其實分類問題是有監督學習中的離散形式問題。每一個都有一個有限的分類。對於樣例提供的多個標簽,我們要做的就是把未知類別的數據划分到其中的一種。

    • ②回歸
      去過預期的輸出包含連續的變量,那么這樣的任務叫做回歸。根據三文魚的年紀和中聯預測其長度就是一個回歸樣例。

  • (2)無監督學習
    訓練數據包含不帶有目標值的輸入向量x。對於這些問題,目標就是根據數據發現樣本中相似的群組——聚類。或者在輸入空間中判定數據的分布——密度估計,或者把數據從高維空間轉換到低維空間以用於可視化

訓練集和測試集
機器學習是學習一些數據集的特征屬性並將其應用於新的數據。這就是為什么在機器學習用來評估算法時一般把手中的數據分成兩部分。一部分我們稱之為訓練集,用以學習數據的特征屬性。一部分我們稱之為測試集,用以檢驗學習到的特征屬性。

二、加載一個樣本數據集

scikit-learn本身帶有一些標准數據集。比如用來分類的iris(鳶尾花)數據集、digits(數字)數據集;用來回歸的boston house price(波士頓房屋價格) 數據集。

接下來,我們我們從shell開啟一個Python解釋器並加載iris和digits兩個數據集。【譯注:一些代碼慣例就不寫了,提示符>>>之類的學過Python的都懂】

$ python
>>>from sklearn import datasets  #從sklearn包中加載數據集模塊
>>>iris = datasets.load_iris()  #加載鳶尾花數據集
>>>digits = datasets.load_digits() #加載數字圖像數據集

一個數據集是一個包含數據所有元數據的類字典對象。這個數據存儲在 '.data'成員變量中,是一個\(n*n\)的數組,行表示樣例,列表示特征。在有監督學習問題中,一個或多個響應變量(Y)存儲在‘.target’成員變量中。不同數據集的更多細節可以在專屬章節中找到。

例如,對於digits數據集,digits.data可以訪問得到用來對數字進行分類的特征:

>>>print(digits.data)  
[[  0.   0.   5. ...,   0.   0.   0.]
 [  0.   0.   0. ...,  10.   0.   0.]
 [  0.   0.   0. ...,  16.   9.   0.]
 ...,
 [  0.   0.   1. ...,   6.   0.   0.]
 [  0.   0.   2. ...,  12.   0.   0.]
 [  0.   0.  10. ...,  12.   1.   0.]]

digits.target 就是數字數據集各樣例對應的真實數字值。也就是我們的程序要學習的。

>>>digits.target
array([0, 1, 2, ..., 8, 9, 8])

數據數組的形狀
盡管原始數據也許有不同的形狀,但實際使用的數據通常是一個二維數組(n個樣例,n個特征)。對於數字數據集,每一個原始的樣例是一張(8 x 8)的圖片,也能被使用:

>>>digits.images[0]
array([[  0.,   0.,   5.,  13.,   9.,   1.,   0.,   0.],
       [  0.,   0.,  13.,  15.,  10.,  15.,   5.,   0.],
       [  0.,   3.,  15.,   2.,   0.,  11.,   8.,   0.],
       [  0.,   4.,  12.,   0.,   0.,   8.,   8.,   0.],
       [  0.,   5.,   8.,   0.,   0.,   9.,   8.,   0.],
       [  0.,   4.,  11.,   0.,   1.,  12.,   7.,   0.],
       [  0.,   2.,  14.,   5.,  10.,  12.,   0.,   0.],
       [  0.,   0.,   6.,  13.,  10.,   0.,   0.,   0.]])

三、學習和預測

對於數字數據集(digits dataset),任務是預測一張圖片中的數字是什么。數字數據集提供了0-9每一個數字的可能樣例,可以用它們來對位置的數字圖片進行擬合分類。

在scikit-learn中,用以分類的擬合(評估)函數是一個Python對象,具體有fit(X,Y)predic(T)兩種成員方法。

其中一個擬合(評估)樣例是sklearn.svmSVC類,它實現了支持向量分類(SVC)。一個擬合(評估)函數的構造函數需要模型的參數,但是時間問題,我們將會把這個擬合(評估)函數作為一個黑箱:

>>>from sklearn import svm
>>>clf = svm.SVC(gamma=0.001, C=100.)

選擇模型參數
我們調用擬合(估測)實例clf作為我們的分類器。它現在必須要擬合模型,也就是說,他必須要學習模型。這可以通過把我們的訓練集傳遞給fit方法。作為訓練集,我們使用其中除最后一組的所有圖像。我們可以通過Python的分片語法[:-1]來選取訓練集,這個操作將產生一個新數組,這個數組包含digits.data中除最后一組數據的所有實例。

>>>clf.fit(digits.data[:-1], digits.target[:-1])  
SVC(C=100.0, cache_size=200, class_weight=None, coef0=0.0, degree=3,
gamma=0.001, kernel='rbf', max_iter=-1, probability=False,
random_state=None, shrinking=True, tol=0.001, verbose=False)

現在你就可以預測新的數值了。我們可以讓這個訓練器預測沒有作為訓練數據使用的最后一張圖像是什么數字。

>>>clf.predict(digits.data[-1])
array([8])

相應的圖片如下圖:
此處輸入圖片的描述

正如你所看到的,這是一個很有挑戰的任務:這張圖片的分辨率很低。你同意分類器給出的答案嗎?

這個分類問題的完整示例在這里識別手寫數字,你可以運行並使用它。[譯:看本文附錄]

四、模型持久化

可以使用Python的自帶模塊——pickle來保存scikit中的模型:

>>>from sklearn import svm
>>>from sklearn import datasets
>>>clf = svm.SVC()
>>>iris = datasets.load_iris()
>>>X, y = iris.data, iris.target
>>>clf.fit(X, y)  
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0, degree=3, gamma=0.0,
  kernel='rbf', max_iter=-1, probability=False, random_state=None,
  shrinking=True, tol=0.001, verbose=False)

>>>import pickle
>>>s = pickle.dumps(clf)
>>>clf2 = pickle.loads(s)
>>>clf2.predict(X[0])
array([0])
>>>y[0]
0

對於scikit,也許使用joblib的pickle替代——(joblib.dump&joblib.load)更有趣。因為它在處理帶數據時更高效。但是遺憾的是它只能把數據持久化到硬盤而不是一個字符串(譯注:搬到string字符串意味着數據在內存中):

>>>from sklearn.externals import joblib
>>>joblib.dump(clf, 'filename.pkl')

往后你就可以加載這個轉儲的模型(也能在另一個Python進程中使用),如下:

>>>clf = joblib.load('filename.pkl')

注意
joblib.dump返回一個文件名的列表,每一個numpy數組元素包含一個clf在文件系統上的名字,在用joblib.load加載的時候所有的文件需要在相同的文件夾下

注意pickle有一些安全和可維護方面的問題。請參考Model persistent 獲得在scikit-learn中模型持久化的細節。

五、慣例約定

scikit-learn的各種擬合(評估)函數遵循一些確定的規則以使得他們的用法能夠被預想到(譯:使得各種學習方法的用法統一起來)

  • ①類型轉換

    除非特別指定,輸入將被轉換為float64

import numpy
from sklearn import random_projection
rng = np.random.RandomState(0)
X = rng.rand(10,2000)
X = np.array(X,dtype ='float32')
print x.dtype
transformer = random_projection.GaussianRandomProjection()
X_new = transformer.fit_transform(X)
print X_new.dtype

在這個例子中,X是float32,被fit_transform(X)轉換成float64,回歸被轉換成float64,分類目標維持不變.

from sklearn import datesets
from sklearn.svm import SVC
iris = datasets.load_iris()
clf =SVC()
clf.fit(iris.data,iris.target)
print list(clf.predict(iris.data[:3]))
clf.fit(iris.data,iris.target_names[iris.target])
print list(clf.predict(iris.data[:3]))

這里第一個predict()返回一個整數數組,是因為iris.target(一個整數數組)被用於擬合。第二個predict()返回一個字符串數組,因為iris.target_names被用於擬合。

  • ②重擬合和更新參數
    一個擬合(評估)函數的混合參數(超參數)能夠在通過sklearn.pipeline.Pipeline.set_params方法構造之后被更新。多次調用fit()能夠覆寫之前fit()學習的內容:
import numpy as np
from sklearn.svm import SVC
rng = np.random.RandomState(0);
X = rng.rand(100,10)
Y = rng.binomial(1,0.5,100)
X_test = rng.rand(5,10)
clf = SVC()
clf.set_params(kernel = 'linear').fit(X,Y)
clf.predict(X_test)
clf.set_params(kernel='rbf').fit(X,Y)
clf.predict(X_test) 

這里,用SVC()構造之后,開始擬合(評估)函數默認的'rbf'核被改編成'linear',后來又改回'rbf'去重擬合做第二次的預測。

附:

  • ①digits數據集:一個展示怎樣用scikit-learn識別手寫數字的樣例:繪制數字:
# 源代碼: Gaël Varoquaux
# 修改以進行文檔化:Jaques Grobler
# 協議: BSD 3 
from sklearn import datasets
import matplotlib.pyplot as plt
#加載數字數據集
digits = datasets.load_digits()
#展示第一個數字
plt.figure(1, figsize=(3, 3))
plt.imshow(digits.images[-1], cmap=plt.cm.gray_r, interpolation='nearest')
plt.show()

此處輸入圖片的描述

  • ②繪制數字分類 (plot_digits_classification.py)
# 作者: Gael Varoquaux <gael dot varoquaux at normalesup dot org>
# 協議: BSD 3 clause
# Python標准科學計算包導入
import matplotlib.pyplot as plt
# 導入數據集,分類器和評估度量
from sklearn import datasets, svm, metrics
# 數字數據集
digits = datasets.load_digits()
#數據是一個8x8的數字圖像,讓我們先看看開頭的三張圖像.圖像存儲在數據集
#的`images`屬性中,如果我們要加載圖像文件的話,可以使用pylab.imread.
#注意每一張圖像尺寸必須相等.這些圖像各自對應的數字是多少我們是知道的
#他們存儲在數據集的target屬性中.
images_and_labels = list(zip(digits.images, digits.target))
for index, (image, label) in enumerate(images_and_labels[:4]):
    plt.subplot(2, 4, index + 1)
    plt.axis('off')
    plt.imshow(image, cmap=plt.cm.gray_r, interpolation='nearest')
    plt.title('Training: %i' % label)
# 在數據上應用一個分類器, 我們需要鋪平圖像,
# 將數據轉換成二位矩陣:
n_samples = len(digits.images)
data = digits.images.reshape((n_samples, -1))
# 創建一個分類器: 一個支持向量分類器
classifier = svm.SVC(gamma=0.001)
# 我們在前半部分數據上進行學習
classifier.fit(data[:n_samples / 2], digits.target[:n_samples / 2])
# 現在預測后半部分的值:
expected = digits.target[n_samples / 2:]
predicted = classifier.predict(data[n_samples / 2:])
print("Classification report for classifier %s:\n%s\n"
      % (classifier, metrics.classification_report(expected, predicted)))
print("Confusion matrix:\n%s" % metrics.confusion_matrix(expected, predicted))
images_and_predictions = list(zip(digits.images[n_samples / 2:], predicted))
for index, (image, prediction) in enumerate(images_and_predictions[:4]):
    plt.subplot(2, 4, index + 5)
    plt.axis('off')
    plt.imshow(image, cmap=plt.cm.gray_r, interpolation='nearest')
    plt.title('Prediction: %i' % prediction)
plt.show()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM