1. 程式人生 > >[譯]針對科學資料處理的統計學習教程(scikit-learn教程2)

[譯]針對科學資料處理的統計學習教程(scikit-learn教程2)

翻譯:Tacey Wong

統計學習
隨著科學實驗資料的迅速增長,機器學習成了一種越來越重要的技術。問題從構建一個預測函式將不同的觀察資料聯絡起來,到將觀測資料分類,或者從未標記資料中學習到一些結構。
本教程將探索機器學習中統計推理的統計學習的使用:將手中的資料做出結論
Scikit-learn 是一個緊密結合Python科學計算庫(Numpy、Scipy、matplotlib),整合經典機器學習演算法的Python模組。

一、統計學習:scikit-learn中的設定與評估函式物件

(1)資料集

scikit-learn 從二維陣列描述的資料中學習資訊。他們可以被理解成多維觀測資料的列表。如(n,m),n表示樣例軸,y表示特徵軸。

使用scikit-learn裝載一個簡單的樣例:iris資料集

>>from sklearn import datasets
>>iris = datasets.load_iris()
>>data = iris.data
>>data.shape
(150, 4)

它有150個iris觀測資料構成,每一個樣例被四個特徵所描述:他們的萼片、花瓣長度、花瓣寬度,具體的資訊可以通過iris》DESCR檢視。

當資料初始時不是(n樣例,n特徵)樣式時,需要將其預處理以被scikit-learn使用。

通過數字資料集講述資料變形
數字資料集由1797個8x8手寫數字圖片組成

>>>digits = datasets.load_digits()
>>>digits.images.shape
(1797, 8, 8)
>>> import pylab as pl 
>>>pl.imshow(digits.images[-1], cmap=pl.cm.gray_r) 
<matplotlib.image.AxesImage object at ...>

此處輸入圖片的描述
在scikit-learn中使用這個資料集,我們需要將其每一個8x8圖片轉換成長64的特徵向量

python
>>>data = digits.images.reshape((digits.images.shape[0],-1)) 

(2)估計函式物件

擬合數據:scikit-learn實現的主要API是估計函式。估計函式是用以從資料中學習的物件。它可能是分類、迴歸、聚類演算法,或者提取過濾資料特徵的轉換器。

一個估計函式帶有一個fit方法,以dataset作為引數(一般是個二維陣列)

>>>estimator.fit(data)

估計函式物件的引數:每一個估測器物件在例項化或者修改其相應的屬性,其引數都會被設定。

>>>estimator = Estimator(param1=1, param2=2)
>>>estimator.param1
1

估測後的引數

>>>estimator.estimated_param_

二、有監督學習:從高維觀察資料預測輸出變數

有監督學習解決的問題
有監督學習主要是學習將兩個資料集聯絡起來:觀察資料x和我們要嘗試預測的外接變數y,y通常也被稱作目標、標籤。多數情況下,y是一個和n個觀測樣例對應的一維陣列。
scikit-learn中實現的所有有監督學習評估物件,都有fit(X,Y)方法來擬合模型,predict(X)方法根據未加標籤的觀測資料X
返回預測的標籤y。

詞彙:分類和迴歸
如果預測任務是將觀測資料分類到一個有限的類別集中,換句話說,給觀測物件命名,那麼這個任務被稱作分類任務。另一方面,如果任務的目標是預測測目標是一個連續性變數,那麼這個任務成為迴歸任務。
用scikit-learn解決分類問題時,y是一個整數或字串組成的向量
注意:檢視[]快速瞭解用scikit-learn解決機器學習問題過程中的基礎詞彙。

(1)近鄰和高維災難

iris分類
iris分類是根據花瓣、萼片長度、萼片寬度來識別三種不同型別的iris的分類任務:

>> import numpy as np
>> from sklearn import datasets
>> iris = datasets.load_iris()
>> iris_X = iris.data
>> iris_y = iris.target
>> np.unique(iris_y)
array([0, 1, 2])

最近鄰分類器
近鄰也許是最簡的分類器:得到一個新的觀測資料X-test,從訓練集的觀測資料中尋找特徵最相近的向量。(【】)

訓練集和測試集
當嘗試任何學習演算法的時候,評估一個學習演算法 的預測精度是很重要的。所以在做機器學習相關的問題的時候,通常將資料集分成訓練集和測試集。

KNN(最近鄰)分類示例

# Split iris data in train and test data
# A random permutation, to split the data randomly
np.random.seed(0)
indices = np.random.permutation(len(iris_X))
iris_X_train = iris_X[indices[:-10]]
iris_y_train = iris_y[indices[:-10]]
iris_X_test  = iris_X[indices[-10:]]
iris_y_test  = iris_y[indices[-10:]]
# Create and fit a nearest-neighbor classifier
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier()
knn.fit(iris_X_train, iris_y_train) 
knn.predict(iris_X_test)
iris_y_test

高維災難
對於一個有效的學習演算法,你需要最近n個點之間的距離d(依賴於具體的問題)。在一維空間中,需要平局n1/d各點,在上文中提到的K-NN例子中,如果資料只是有一個0-1之間的特徵和n個訓練觀測資料所表述的畫,那麼新資料將不會超過1/n。因此,最近鄰決策規則非常高效,因為與類間特徵變化的範圍相比,1/n小的多。

如果特徵數是P,你就需要n 1/d^p個點。也就是說,如果我們在一維度情況下需要10個點,在P維度情況下需要10^p個點。當P變大的時候,為獲得一個好的預測函式需要的點數將急劇增長。

這被稱為高維災難(指數級增長),也是機器學習領域的一個核心問題。

(2)線性模型:從迴歸到稀疏性

Diabets資料集(糖尿病資料集)
糖尿病資料集包含442個患者的10個生理特徵(年齡,性別、體重、血壓)和一年以後疾病級數指標。

diabetes = datasets.load_diabetes()
diabetes_X_train = diabetes.data[:-20]
diabetes_X_test = diabetes.data[-20:]
diabetes_y_train = diabetes.target[:-20]
diabetes_y_test = diabetes.target[-20:]
手上的任務是從生理特徵預測疾病級數
線性迴歸:
【線性迴歸】的最簡單形式給資料集擬合一個線性模型,主要是通過調整一系列的參以使得模型的殘差平方和儘量小。

線性模型:y = βX+b
    X:資料
    y:目標變數
    β:迴歸係數
    b:觀測噪聲(bias,偏差)
from sklearn import linear_model
regr = linear_model.LinearRegression()
regr.fit(diabetes_X_train, diabetes_y_train)
print(regr.coef_)
# The mean square error
np.mean((regr.predict(diabetes_X_test)-diabetes_y_test)**2)
# Explained variance score: 1 is perfect prediction
# and 0 means that there is no linear relationship
# between X and Y.
regr.score(diabetes_X_test, diabetes_y_test) 

收縮(Shrinkage)
如果每一維的資料點很少,噪聲將會造成很大的偏差影響:

X = np.c_[ .5, 1].T
y = [.5, 1]
test = np.c_[ 0, 2].T
regr = linear_model.LinearRegression()
import pylab as pl 
pl.figure() 
np.random.seed(0)
for _ in range(6): 
   this_X = .1*np.random.normal(size=(2, 1)) + X
   regr.fit(this_X, y)
   pl.plot(test, regr.predict(test)) 
   pl.scatter(this_X, y, s=3)  

高維統計學習的一個解決方案是將回歸係數縮小到0:觀測資料中隨機選擇的兩個資料集近似不相關。這被稱為嶺迴歸(Ridge Regression):

regr = linear_model.Ridge(alpha=.1)
pl.figure() 
np.random.seed(0)
for _ in range(6): 
   this_X = .1*np.random.normal(size=(2, 1)) + X
   regr.fit(this_X, y)
   pl.plot(test, regr.predict(test)) 
   pl.scatter(this_X, y, s=3) 

這是一個偏差/方差(bias/variance)的權衡:嶺α引數越大,偏差(bias)越大,方差(variance)越小

我們可以選擇α以最小化排除錯誤,這裡使用糖尿病資料集而不是人為製造的資料:

alphas = np.logspace(-4, -1, 6)
from __future__ import print_function
print([regr.set_params(alpha=alpha
            ).fit(diabetes_X_train, diabetes_y_train,
            ).score(diabetes_X_test, diabetes_y_test) for alpha in alphas]) 

【注意】撲捉擬合引數的噪聲使得模型不能推廣到新的資料被稱為過擬合。嶺迴歸造成的偏差被稱為正則化(歸整化,regularization)

稀疏性
只擬合特徵1和特徵2:

【注意】整個糖尿病資料包含11維資料(10個特徵維,一個目標變數),很難對這樣的資料直觀地表現出來,但是記住那是一個很空的空間也許是有用的。

我們可以看到,儘管特徵2在整個模型中佔據很大的係數,但是和特徵1相比,對結果y造成的影響很小。

為了提升問題的狀況(考慮到高維災難),只選擇資訊含量較大的(對結果y造成的影響較大的)的特徵,不選擇資訊含量較小的特徵會很有趣,如把特徵2的係數調到0.嶺迴歸將會減少資訊含量較小的係數的值,而不是把它們設定為0.另一種抑制措施——Lasso(最小絕對收縮和選擇運算元)可以使得一些引數為0.這些方法被稱作稀疏方法。係數操作可以看作是奧卡姆的剃刀:模型越簡單越好。

regr = linear_model.Lasso()
scores = [regr.set_params(alpha=alpha
            ).fit(diabetes_X_train, diabetes_y_train
            ).score(diabetes_X_test, diabetes_y_test)
       for alpha in alphas]
best_alpha = alphas[scores.index(max(scores))]
regr.alpha = best_alpha
regr.fit(diabetes_X_train, diabetes_y_train)
print(regr.coef_)

針對相同問題的不同演算法:
不同的演算法可以被用來解決相同的數學問題。例如scikit-learn中的Lasso物件使用coordinate decent方法解決lasso迴歸問題,在大資料集上是很有效的。然而,scikit-learn也使用LARS演算法提供了LassoLars物件,對於處理權重向量非常稀疏的資料非常有效(資料的觀測例項非常少)。

  • 分類:
    對於分類問題,比如iris標定任務,線性迴歸不是正確的方法。因為它會給資料得出大量遠離決策邊界的權重。一個線性方法是你和一個sigmoid函式或者logistic函式:
logistic = linear_model.LogisticRegression(C=1e5)
logistic.fit(iris_X_train, iris_y_train)

這就是有名的logistic迴歸

  • 多分類:
    如果你有多個類別需要預測,一個可行的方法是 “一對多”分類,接著根據投票決定最終的決策。

通過Logistic迴歸進行收縮和稀疏

在LogisticRegression物件中C引數控制著正則化的數量:C越大,正則化數目越少。penalty= "12" 提供收縮(非稀疏化係數),penalty="11"提供稀疏化。

練習
嘗試使用近鄰演算法和線性模型對數字資料集進行分類。留出最後的10%作為測試集用來測試預測的精確度。

from sklearn import datasets, neighbors, linear_model
digits = datasets.load_digits()
X_digits = digits.data
y_digits = digits.target

【完整程式碼】

from sklearn import datasets, neighbors, linear_model
digits = datasets.load_digits()
X_digits = digits.data
y_digits = digits.target
n_samples = len(X_digits)
X_train = X_digits[:.9 * n_samples]
y_train = y_digits[:.9 * n_samples]
X_test = X_digits[.9 * n_samples:]
y_test = y_digits[.9 * n_samples:]
knn = neighbors.KNeighborsClassifier()
logistic = linear_model.LogisticRegression()
print('KNN score: %f' % knn.fit(X_train, y_train).score(X_test, y_test))
print('LogisticRegression score: %f'
      % logistic.fit(X_train, y_train).score(X_test, y_test))

(3)支援向量機(SVMs)

線性SVNs
支援向量機屬於判別模型家族:它們嘗試尋找樣例的一個組合,構建一個兩類之間的最大邊緣平面。通過C引數進行正則化:一個較小的C意味著邊緣是通過分割線周圍的所有觀測樣例進行計算得到的(更規整化,正則化);一個較大的C意味著邊緣是通過鄰近分割線的觀測樣例計算得到的(更少的規整化,正則化):

  • 非正則化SVN:

  • 正則化 SVM(預設):

樣例:Plot different SVM分類器 iris資料集

SVMs能夠被用於迴歸——SVR(支援向量迴歸)—用於分類——SVC(支援向量分類)
from sklearn import svm
svc = svm.SVC(kernel='linear')
svc.fit(iris_X_train, iris_y_train)
【警告】:規格化資料
對於大多數的估測模型,包括SVMs,處理好單位標準偏差對於獲得一個好的預測是很重要的。

使用核函式:
在特徵空間中類別不經常是線性可分的。解決方案是構建一個非線性但能用多項式代替的決策函式。這要通過核技巧實現:使用核可以被看作通過設定核在觀測樣例上建立決策力量。

  • 線性核:

  • 多項式核:

  • 徑向基函式核(RBF,Radial Basis Function):

svc = svm.SVC(kernel='rbf')

互動式樣例:
參照SVM GUI,下載svm_gui.py;通過滑鼠左右鍵設定兩類資料點,擬合模型並改變引數和資料。

練習:

嘗試使用SVMs根據iris資料集前兩個特徵將其分成兩類。留出每一類的10%作為測試樣例。
【警告】資料集中的資料是按照分類順序排列的,不要留出最後的10%作為測試樣例,要不然你只能測試一種類別。(獲取訓練集和測試集是注意要進行混淆)
提示:你可以在一個網格上使用decision_function方法獲得直觀的呈現。

iris = datasets.load_iris()
X = iris.data
y = iris.target
X = X[y != 0, :2]
y = y[y != 0]

完整程式碼:

"""
================================
SVM Exercise
================================
A tutorial exercise for using different SVM kernels.
This exercise is used in the :ref:`using_kernels_tut` part of the
:ref:`supervised_learning_tut` section of the :ref:`stat_learn_tut_index`.
"""
print(__doc__)
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets, svm
iris = datasets.load_iris()
X = iris.data
y = iris.target
X = X[y != 0, :2]
y = y[y != 0]
n_sample = len(X)
np.random.seed(0)
order = np.random.permutation(n_sample)
X = X[order]
y = y[order].astype(np.float)
X_train = X[:.9 * n_sample]
y_train = y[:.9 * n_sample]
X_test = X[.9 * n_sample:]
y_test = y[.9 * n_sample:]
# fit the model
for fig_num, kernel in enumerate(('linear', 'rbf', 'poly')):
    clf = svm.SVC(kernel=kernel, gamma=10)
    clf.fit(X_train, y_train)
    plt.figure(fig_num)
    plt.clf()
    plt.scatter(X[:, 0], X[:, 1], c=y, zorder=10, cmap=plt.cm.Paired)
    # Circle out the test data
    plt.scatter(X_test[:, 0], X_test[:, 1], s=80, facecolors='none', zorder=10)
    plt.axis('tight')
    x_min = X[:, 0].min()
    x_max = X[:, 0].max()
    y_min = X[:, 1].min()
    y_max = X[:, 1].max()
    XX, YY = np.mgrid[x_min:x_max:200j, y_min:y_max:200j]
    Z = clf.decision_function(np.c_[XX.ravel(), YY.ravel()])
    # Put the result into a color plot
    Z = Z.reshape(XX.shape)
    plt.pcolormesh(XX, YY, Z > 0, cmap=plt.cm.Paired)
    plt.contour(XX, YY, Z, colors=['k', 'k', 'k'], linestyles=['--', '-', '--'],
                levels=[-.5, 0, .5])
    plt.title(kernel)
plt.show()

三、模型選擇:選擇模型和他們的引數

(1)分數,和交叉驗證分數

眾所周知,每一個模型會得出一個score方法用於裁決模型在新的資料上擬合的質量。其值越大越好。

from sklearn import datasets, svm
digits = datasets.load_digits()
X_digits = digits.data
 y_digits = digits.target
svc = svm.SVC(C=1, kernel='linear')
svc.fit(X_digits[:-100], y_digits[:-100]).score(X_digits[-100:], y_digits[-100:])

為了獲得一個更好的預測精確度度量,我們可以把我們使用的資料摺疊交錯地分成訓練集和測試集:

import numpy as np
X_folds = np.array_split(X_digits, 3)
y_folds = np.array_split(y_digits, 3)
scores = list()
for k in range(3):
    # We use 'list' to copy, in order to 'pop' later on
    X_train = list(X_folds)
    X_test  = X_train.pop(k)
    X_train = np.concatenate(X_train)
    y_train = list(y_folds)
    y_test  = y_train.pop(k)
    y_train = np.concatenate(y_train)
    scores.append(svc.fit(X_train, y_train).score(X_test, y_test))
print(scores)

這被稱為KFold交叉驗證

(2)交叉驗證生成器

上面將資料劃分為訓練集和測試集的程式碼寫起來很是沉悶乏味。scikit-learn為此自帶了交叉驗證生成器以生成目錄列表:
from sklearn import cross_validation
k_fold = cross_validation.KFold(n=6, n_folds=3)
for train_indices, test_indices in k_fold:
     print('Train: %s | test: %s' % (train_indices, test_indices))

接著交叉驗證就可以很容易實現了:

kfold = cross_validation.KFold(len(X_digits), n_folds=3)
[svc.fit(X_digits[train], y_digits[train]).score(X_digits[test], y_digits[test])
         for train, test in kfold]

為了計算一個模型的score,scikit-learn自帶了一個幫助函式:

cross_validation.cross_val_score(svc, X_digits, y_digits, cv=kfold, n_jobs=-1)

n_jobs=-1意味著將計算任務分派個計算機的所有CPU.

交叉驗證生成器:
KFold(n,k) 交叉分割,K-1上進行訓練,生於資料樣例用於測試
StratifiedKFold(y,K) 儲存每一個fold的類比率/標籤分佈
leaveOneOut(n) 至預留一個觀測樣例
leaveOneLabelOut(labels) 採用一個標籤陣列把觀測樣例分組

練習:
使用digits資料集,繪製使用線性核的SVC進行交叉驗證的分數(使用對數座標軸,1——10)

import numpy as np
from sklearn import cross_validation, datasets, svm
digits = datasets.load_digits()
X = digits.data
y = digits.target
svc = svm.SVC(kernel='linear')
C_s = np.logspace(-10, 0, 10)

完整程式碼:

(3)網格搜尋和交叉驗證模型

網格搜尋:
scikit-learn提供一個物件,他得到資料可以在採用一個引數的模型擬合過程中選擇使得交叉驗證分數最高的引數。該物件的建構函式需要一個模型作為引數:

from sklearn.grid_search import GridSearchCV
Cs = np.logspace(-6, -1, 10)
clf = GridSearchCV(estimator=svc, param_grid=dict(C=Cs),
                   n_jobs=-1)
clf.fit(X_digits[:1000], y_digits[:1000])        
clf.best_score_                                  
clf.best_estimator_.C                            
# Prediction performance on test set is not as good as on train set
clf.score(X_digits[1000:], y_digits[1000:])      

預設情況下,GridSearchCV使用3-fold交叉驗證。然而,當他探測到是一個分類器而不是迴歸量,將會採用分層的3-fold
巢狀 交叉驗證

cross_validation.cross_val_score(clf, X_digits, y_digits)

兩個交叉驗證迴圈是並行執行的:一個GridSearchCV模型設定gamma,另一個使用cross_val_score 度量模型的預測表現。結果分數是在新資料預測分數的無偏差估測。

【警告】你不能在平行計算時巢狀物件(n_jobs不同於1)

交叉驗證估測:
在演算法by演算法的基礎上使用交叉驗證去設定引數更高效。這也是為什麼對於一個特定的模型/估測器引入Cross-validation:評估估測器表現模型去自動的通過交叉驗證設定引數。

from sklearn import linear_model, datasets
lasso = linear_model.LassoCV()
diabetes = datasets.load_diabetes()
X_diabetes = diabetes.data
y_diabetes = diabetes.target
lasso.fit(X_diabetes, y_diabetes)
# The estimator chose automatically its lambda:
lasso.alpha_ 

這些模型的稱呼和他們的對應模型很相似,只是在他們模型名字的後面加上了'CV'.

練習:
使用糖尿病資料集,尋找最佳的正則化引數α

  • 附加:你對選擇的α值信任度有多高?
from sklearn import cross_validation, datasets, linear_model
diabetes = datasets.load_diabetes()
X = diabetes.data[:150]
y = diabetes.target[:150]
lasso = linear_model.Lasso()
alphas = np.logspace(-4, -.5, 30)

完整程式碼:

四、無監督學習:尋找資料的代表

(1)聚類:將觀測樣例聚集到一起

聚類解決的問題:
比如對於iris資料集,如果我們知道我們知道有三種iris,但是我們沒有標籤標定他們:我們可以嘗試聚類任務:將觀測樣例分成分離的族群中,這些族群可以被稱為簇。

  • K-mean聚類(K均值聚類)
    注意存在很多不同的聚類標準和關聯演算法。最簡的聚類演算法是——K均值(K-means)
from sklearn import cluster, datasets
iris = datasets.load_iris()
X_iris = iris.data
y_iris = iris.target
k_means = cluster.KMeans(n_clusters=3)
k_means.fit(X_iris) 
print(k_means.labels_[::10])
print(y_iris[::10])

注意:沒有絕對的保證能夠恢復真實的分類。首先,儘管scikit-learn使用很多技巧來緩和問題的難度,但選擇簇的個數還是是很困難的,初始狀態下演算法是很敏感的,可能會陷入區域性最小。
不好的初始狀態:

8個簇:

真實情況:

不要“過解釋”聚類結果

應用例項:向量化
K-means和一般的聚類,可以看作是選擇少量的示例壓縮資訊的方式。這個問題被稱之為向量化。例如,這可以被用於分離一個影象:

import scipy as sp
try:
   lena = sp.lena()
except AttributeError:
   from scipy import misc
   lena = misc.lena()
X = lena.reshape((-1, 1)) # We need an (n_sample, n_feature) array
k_means = cluster.KMeans(n_clusters=5, n_init=1)
k_means.fit(X) 
values = k_means.cluster_centers_.squeeze()
labels = k_means.labels_
lena_compressed = np.choose(labels, values)
lena_compressed.shape = lena.shape

原始影象:

K-means向量化:

等段:(Equal bins)

影象直方圖:

  • 分層凝聚聚類:Ward
    分層聚類方法是一種針對構建一個簇的分層的簇分析。通常它的實現方式有以下兩種:
    • 凝聚:自下而上的方法:每一個觀測樣例開始於他自己的簇,以一種最小連線標準迭代合併。這種方法在觀測樣例較少的情況下非常有效(有趣)。當簇的數量變大時,計算效率比K-means高的多。
    • 分裂:自上而下的方法:所有的觀測樣例開始於同一個簇。迭代的進行分層。對於預計簇很多的情況,這種方法既慢(由於所有的觀測樣例作為一個簇開始的,是遞迴進行分離的)又有統計學行的病態。
  • 連同-驅使聚類(Conectivity-constrained clustering)
    使用凝聚聚類,通過一個連通圖可以指定某些樣例能被聚集在一起。scikit-learn中的圖通過鄰接矩陣來表示,且通常是一個稀疏矩陣。例如,在聚類一張圖片時檢索連通區域(有時也被稱作連同單元、部件):
from sklearn.feature_extraction.image import grid_to_graph
from sklearn.cluster import AgglomerativeClustering
###############################################################################
# Generate data
lena = sp.misc.lena()
# Downsample the image by a factor of 4
lena = lena[::2, ::2] + lena[1::2, ::2] + lena[::2, 1::2] + lena[1::2, 1::2]
X = np.reshape(lena, (-1, 1))
###############################################################################
# Define the structure A of the data. Pixels connected to their neighbors.
connectivity = grid_to_graph(*lena.shape)
###############################################################################
# Compute clustering
print("Compute structured hierarchical clustering...")
st = time.time()
n_clusters = 15  # number of regions
ward = AgglomerativeClustering(n_clusters=n_clusters,
        linkage='ward', connectivity=connectivity).fit(X)
label = np.reshape(ward.labels_, lena.shape)
print("Elapsed time: ", time.time() - st)
print("Number of pixels: ", label.size)
print("Number of clusters: ", np.unique(label).size)

特徵凝聚:
我們已經知道稀疏性可以緩和高維災難。i.e相對於特徵數量觀測樣例數量不足的情況。另一種方法是合併相似的特徵:特徵凝聚。這種方法通過在特徵方向上進行聚類實現。在特徵方向上聚類也可以理解為聚合轉置的資料。

digits = datasets.load_digits()
images = digits.images
X = np.reshape(images, (len(images), -1))
connectivity = grid_to_graph(*images[0].shape)
agglo = cluster.FeatureAgglomeration(connectivity=connectivity,
                                     n_clusters=32)
agglo.fit(X) 
X_reduced = agglo.transform(X)
X_approx = agglo.inverse_transform(X_reduced)
images_approx = np.reshape(X_approx, images.shape)

transeforminvers_transeform方法
有些模型帶有轉置方法。例如用來降低資料集的維度

(2)分解:從一個訊號到成分和載入

成分及其載入:
如果X是我們的多變數資料,那麼我們要要嘗試解決的問題就是在不同的觀測樣例上覆寫寫它:我們想要學習載入L和其它一系列的成分C,如X = LC。存在不同的標準和條件去選擇成分。

  • 主成分分析:PCA
    主成分分析(PCA)選擇在訊號上解釋極大方差的連續成分。

上面觀測樣例的點分佈在一個方向上是非常平坦的:三個特徵單變數的一個甚至可以有其他兩個準確的計算出來。PCA用來發現資料在哪個方向上是不平坦的。

當被用來轉換資料的時候,PCA可以通過投射到一個主子空間來降低資料的維度。:

# Create a signal with only 2 useful dimensions
x1 = np.random.normal(size=100)
x2 = np.random.normal(size=100)
x3 = x1 + x2
X = np.c_[x1, x2, x3]
from sklearn import decomposition
pca = decomposition.PCA()
pca.fit(X)
print(pca.explained_variance_)  
# As we can see, only the 2 first components are useful
pca.n_components = 2
X_reduced = pca.fit_transform(X)
X_reduced.shape
  • 獨立成分分析:ICA
    獨立成分分析(ICA)選擇合適的成分使得他們的分佈載有最大的獨立資訊量。可以恢復非高斯獨立訊號:
# Generate sample data
time = np.linspace(0, 10, 2000)
s1 = np.sin(2 * time)  # Signal 1 : sinusoidal signal
s2 = np.sign(np.sin(3 * time))  # Signal 2 : square signal
S = np.c_[s1, s2]
S += 0.2 * np.random.normal(size=S.shape)  # Add noise
S /= S.std(axis=0)  # Standardize data
# Mix data
A = np.array([[1, 1], [0.5, 2]])  # Mixing matrix
X = np.dot(S, A.T)  # Generate observations
# Compute ICA
ica = decomposition.FastICA()
S_ = ica.fit_transform(X)  # Get the estimated sources
A_ = ica.mixing_.T
np.allclose(X,  np.dot(S_, A_) + ica.mean_)

五、聯合起來

(1)管道(流水線)

我們已經知道了一些估測器(模型)能夠轉換資料,一些可以預測變數。我們也能夠將其結合到一起:

from sklearn import linear_model, decomposition, datasets
from sklearn.pipeline import Pipeline
from sklearn.grid_search import GridSearchCV
logistic = linear_model.LogisticRegression()
pca = decomposition.PCA()
pipe = Pipeline(steps=[('pca', pca), ('logistic', logistic)])
digits = datasets.load_digits()
X_digits = digits.data
y_digits = digits.target
###############################################################################
# Plot the PCA spectrum
pca.fit(X_digits)
plt.figure(1, figsize=(4, 3))
plt.clf()
plt.axes([.2, .2, .7, .7])
plt.plot(pca.explained_variance_, linewidth=2)
plt.axis('tight')
plt.xlabel('n_components')
plt.ylabel('explained_variance_')
###############################################################################
# Prediction
n_components = [20, 40, 64]
Cs = np.logspace(-4, 4, 3)
#Parameters of pipelines can be set using ‘__’ separated parameter names:
estimator = GridSearchCV(pipe,
                         dict(pca__n_components=n_components,
                              logistic__C=Cs))
estimator.fit(X_digits, y_digits)
plt.axvline(estimator.best_estimator_.named_steps['pca'].n_components,
            linestyle=':', label='n_components chosen')
plt.legend(prop=dict(size=12))

(2)使用特徵聯進行人臉識別

    該例項使用的資料集是從“Labeled Faces in the Wild”節選預處理得到的。更為熟知的名字是LFW。
"""
===================================================
Faces recognition example using eigenfaces and SVMs
===================================================
The dataset used in this example is a preprocessed excerpt of the
"Labeled Faces in the Wild", aka LFW_:
  http://vis-www.cs.umass.edu/lfw/lfw-funneled.tgz (233MB)
.. _LFW: http://vis-www.cs.umass.edu/lfw/
Expected results for the top 5 most represented people in the dataset::
                     precision    recall  f1-score   support
  Gerhard_Schroeder       0.91      0.75      0.82        28
    Donald_Rumsfeld       0.84      0.82      0.83        33
         Tony_Blair       0.65      0.82      0.73        34
       Colin_Powell       0.78      0.88      0.83        58
      George_W_Bush       0.93      0.86      0.90       129
        avg / total       0.86      0.84      0.85       282
"""
from __future__ import print_function
from time import time
import logging
import matplotlib.pyplot as plt
from sklearn.cross_validation import train_test_split
from sklearn.datasets import fetch_lfw_people
from sklearn.grid_search import GridSearchCV
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.decomposition import RandomizedPCA
from sklearn.svm import SVC
print(__doc__)
# Display progress logs on stdout
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')
###############################################################################
# Download the data, if not already on disk and load it as numpy arrays
lfw_people = fetch_lfw_people(min_faces_per_person=70, resize=0.4)
# introspect the images arrays to find the shapes (for plotting)
n_samples, h, w = lfw_people.images.shape
# for machine learning we use the 2 data directly (as relative pixel
# positions info is ignored by this model)
X = lfw_people.data
n_features = X.shape[1]
# the label to predict is the id of the person
y = lfw_people.target
target_names = lfw_people.target_names
n_classes = target_names.shape[0]
print("Total dataset size:")
print("n_samples: %d" % n_samples)
print("n_features: %d" % n_features)
print("n_classes: %d" % n_classes)
###############################################################################
# Split into a training set and a test set using a stratified k fold
# split into a training and testing set
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25)
###############################################################################
# Compute a PCA (eigenfaces) on the face dataset (treated as unlabeled
# dataset): unsupervised feature extraction / dimensionality reduction
n_components = 150
print("Extracting the top %d eigenfaces from %d faces"
      % (n_components, X_train.shape[0]))
t0 = time()
pca = RandomizedPCA(n_components=n_components, whiten=True).fit(X_train)
print("done in %0.3fs" % (time() - t0))
eigenfaces = pca.components_.reshape((n_components, h, w))
print("Projecting the input data on the eigenfaces orthonormal basis")
t0 = time()
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)
print("done in %0.3fs" % (time() - t0))
###############################################################################
# Train a SVM classification model
print("Fitting the classifier to the training set")
t0 = time()
param_grid = {'C': [1e3, 5e3, 1e4, 5e4, 1e5],
              'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1], }
clf = GridSearchCV(SVC(kernel='rbf', class_weight='auto'), param_grid)
clf = clf.fit(X_train_pca, y_train)
print("done in %0.3fs" % (time() - t0))
print("Best estimator found by grid search:")
print(clf.best_estimator_)
###############################################################################
# Quantitative evaluation of the model quality on the test set
print("Predicting people's names on the test set")
t0 = time()
y_pred = clf.predict(X_test_pca)
print("done in %0.3fs" % (time() - t0))
print(classification_report(y_test, y_pred, target_names=target_names))
print(confusion_matrix(y_test, y_pred, labels=range(n_classes)))
###############################################################################
# Qualitative evaluation of the predictions using matplotlib
def plot_gallery(images, titles, h, w, n_row=3, n_col=4):
    """Helper function to plot a gallery of portraits"""
    plt.figure(figsize=(1.8 * n_col, 2.4 * n_row))
    plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)
    for i in range(n_row * n_col):
        plt.subplot(n_row, n_col, i + 1)
        plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray)
        plt.title(titles[i], size=12)
        plt.xticks(())
        plt.yticks(())
# plot the result of the prediction on a portion of the test set
def title(y_pred, y_test, target_names, i):
    pred_name = target_names[y_pred[i]].rsplit(' ', 1)[-1]
    true_name = target_names[y_test[i]].rsplit(' ', 1)[-1]
    return 'predicted: %s\ntrue:      %s' % (pred_name, true_name)
prediction_titles = [title(y_pred, y_test, target_names, i)
                     for i in range(y_pred.shape[0])]
plot_gallery(X_test, prediction_titles, h, w)
# plot the gallery of the most significative eigenfaces
eigenface_titles = ["eigenface %d" % i for i in range(eigenfaces.shape[0])]
plot_gallery(eigenfaces, eigenface_titles, h, w)
plt.show()
    預測:

特徵臉:

資料集中最有代表性的五個人臉的期望結果:

precision recall f1-score support

Gerhard_Schroeder 0.91 0.75 0.82 28
Donald_Rumsfeld 0.84 0.82 0.83 33
Tony_Blair 0.65 0.82 0.73 34
Colin_Powell 0.78 0.88 0.83 58
George_W_Bush 0.93 0.86 0.90 129

  avg / total       0.86      0.84      0.85       282

(3)開放性問題:股票市場結構

我們是否可以根據給定的時間幀預測股票的價格變化。
[學習一個圖結構]

六、尋求幫助

###(1)專案郵件列表
如果你碰到scikit-learn的BUG或者文件中需要澄清宣告的部分,請放心大膽的在郵件列表裡詢問[maillist]

(2)問答(Q&A)機器學習從業者參與的社群

  • Metaoptimize/QA:
    一個 機器學習、自然語言處理和其他資料分析方面討論的論壇(類似針對開發者的Stackoverflow):http://metaoptimize.com/qa

                 一個比較容易開始參與的討論:good freely available textbooks on machine learning(機器學習方面優秀的免費電子書)
  •                 瀏覽一下最佳問題的部分,例如:What are some good resources for learning about machine learning(關於機器學習的優秀資源有哪些)
  • ---斯坦福的 Andrew Ng教授 教授的 關於機器學習的優秀線上免費課程
    {網易公開課有,搜一下機器學習就可以了}