機器學習:問題設置
一般的,一個學習問題考慮一個n個樣本集合的數據,然后嘗試預測未知數據的屬性。如果每個樣本都超過一個數,比如是多維度條目。被叫做有多個特征或者屬性。
我們可以把學習問題分成幾個大類:
·監督學習,數據有我們要預測的額外的屬性。問題可以是:
·分類:樣本屬于兩個或更多的類別,我們要從已經標記過的數據學習如果預測未分類數據的類別。一個分類的例子是手寫數字識別,目標是給每個輸入向量分配一個分類的數字。
·回歸:如果期望的輸出包含一個或多個連續變量,任務就被叫做回歸,一個回歸的例子是根據鮭魚的年齡和重量預測它的長度。
·無監督學習,訓練數據不包括任何對應目標值得輸入向量x 的集合組成。這種問題的目標是發現數據里的相似數據的分組,這被叫做聚類。或者是在輸入空間里決定數據的分布,被叫做密度估計。或者從一個高緯度空間投射數據到2維或者3維空以顯示
訓練集合和測試集合
機器學習是關于學習數據集的一些屬性,并應用到其他數據上。這就是為什么機器學習里通常評估算法的方式是把手里的數據拆分成兩個集合,一個我們叫做訓練集,用來學習數據的屬性,另一個叫做測試集,我們用來測試這些屬性。
加載一個數據集
scikit-learn自帶一些標準數據集,比如iris和digits數據集用來做分類,boston house prices dataset用來做回歸。
下面我們啟動一個python解釋器,并加載iris和digits數據集。
$ python
>>> from sklearn import datasets
>>> iris = datasets.load_iris()
>>> digits = datasets.load_digits()
一個數據集是一個字典類的對象,里面有所有的數據還有關于數據的元數據。這些數據存在.data成員里,是n_samples,k n_features 數組,在監督學習問題里,一個或多個相應變量存在.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])
數據數字的形狀
數據都是2D數組,雖然原始數據可能有不同的形狀,在這個數字的例子里,每個原始樣本都是一個8x8的圖像,可以通過下面方式訪問:
>>> 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.]])
學習和預測
在數字數據集的例子里,任務是預測,給定一個圖像,它表示的數字是啥,我們給10個可能的類別(0到9)每個一些樣本來讓我們適配估計量,使之有能力預測未來的樣本的類別。
在scikit-learn里,分類的估計量是一個Python對象,實現了fit(X, y)和predict(T)方法。
估計量的一個例子是sklearn.svm.SVC。實現了支持向量分類。估計量構造函數把模型的參數作為參數
>>> from sklearn import svm
>>> clf = svm.SVC(gamma=0.001, C=100.)
選擇模型參數
我們手動設置gamma的值,如果用類似于grid search或者cross validation這樣的工具可以自動找到好的值。
我們把估計量實例叫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,decision_function_shape=None, 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來保存模型:
>>> 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,
decision_function_shape=None, degree=3, gamma='auto', 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:1])
array([0])
>>> y[0]
0
在scikit的特殊例子里,可以用joblib的替代pickle的工具(joblib.dump和joblib.load)。在大數據上更有效,但是只能保存到磁盤上,而不能到字符串。
>>> from sklearn.externals import joblib
>>> joblib.dump(clf, 'filename.pkl')
之后你可以把pickle了的模型加載回來。
>>>clf=joblib.load('filename.pkl')
注意:joblib.dump返回一個文件列表。clf對象里包含的每個單獨的numpy數組被串行化到文件系統的單獨文件里。當joblib.load加載模型的時候所有文件都需要在同一個目錄里。
慣例
scikit-learn 估計量遵循下屬原則以使其行為更可預測。
type casting
除非另外指明,否則輸入會被轉換到float64:
>>> import numpy as np
>>> from sklearn import random_projection
>>> rng = np.random.RandomState(0)
>>> X = rng.rand(10, 2000)
>>> X = np.array(X, dtype='float32')
>>> X.dtype
dtype('float32')
>>> transformer = random_projection.GaussianRandomProjection()
>>> X_new = transformer.fit_transform(X)
>>> X_new.dtype
dtype('float64')
在這個例子里,X是float32. 被fit_transform(X)轉換到float64
回歸目標被轉換到float64.分類目標保持不變:
>>> from sklearn import datasets
>>> from sklearn.svm import SVC
>>> iris = datasets.load_iris()
>>> clf = SVC()
>>> clf.fit(iris.data, iris.target)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> list(clf.predict(iris.data[:3]))
[0, 0, 0]
>>> clf.fit(iris.data, iris.target_names[iris.target])
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> list(clf.predict(iris.data[:3]))
['setosa', 'setosa', 'setosa']
這里,由于iris.target(整數數組)被fit使用,第一個predict()返回了整數數組,第二個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)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='linear',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> clf.predict(X_test)
array([1, 0, 1, 1, 0])
>>> clf.set_params(kernel='rbf').fit(X, y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> clf.predict(X_test)
array([0, 0, 0, 1, 0])
這里,默認核rbf在通過SVC()構造后被改變為linear,然后變回rbf來重新適應估計量。