科學數據處理統計學習指南?

統計學習

機器學習是一項越來越重要的技術,因為實驗科學面臨的數據集規模正在迅速增長。 它所解決的問題包括建立鏈接不同觀察值的預測功能,對觀察值進行分類或學習未標記數據集中的結構。

本教程將探討統計學習,以及將機器學習技術用于統計推斷的目的:在手頭的數據上得出結論。

Scikit-learn是一個Python模塊,在緊密結合的科學Python程序包世界(NumPy,SciPy,matplotlib)中集成了經典的機器學習算法。

統計學習:scikit-learn中的設置和估計對象

數據集

Scikit-learn處理來自一個或多個以2D數組表示的數據集的學習信息。它們可以理解為多維觀測的列表。我們說這些數組的第一個軸是樣本軸,而第二個是特征軸。

scikit-learn附帶的一個簡單示例:iris數據集:

from sklearn import datasets
iris = datasets.load_iris()
data = iris.data
data.shape

輸出:

(150,4)

它由150個鳶尾花的觀察數據組成,每個觀察都由4個特征描述:它們的萼片和花瓣的長度和寬度,詳細信息請參見iris.DESCR。

當數據最初不是(n_samples,n_features)形狀時,需要對其進行預處理,以供scikit-learn使用。

重塑數據的一個例子是數字數據集:

數字數據集由1797個8x8手寫數字圖像組成,如圖所示:

digits = datasets.load_digits()
digits.images.shape

import matplotlib.pyplot as plt 
plt.imshow(digits.images[-1], cmap=plt.cm.gray_r) 

輸出:

(179788)

<matplotlib.image.AxesImage object at ...>

為了將此數據集與scikit-learn一起使用,我們將每個8x8圖像轉換為長度為64的特征向量:

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

估計對象

擬合數據:scikit-learn實現的主要API是估算器。估計器是從數據中學習的任何對象。它可以是分類,回歸或聚類算法,也可以是從原始數據中提取/過濾有用特征的轉換器。

所有估算器對象都公開一個帶數據集(通常為二維數組)的fit方法:

estimator.fit(data)

估算器參數:可以在實例化估計器或通過修改相應屬性來設置估計器的所有參數:

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

輸出:

1

估計出的參數:當數據裝有估計器時,參數是根據現有數據估計的。所有估計的參數都是估計對象的屬性,其下劃線結尾:

estimator.estimated_param_

有監督的學習:從高維觀測值預測輸出變量

監督學習中解決的問題

監督學習包括學習兩個數據集之間的鏈接:觀測數據X和我們試圖預測的外部變量y,通常稱為“目標”或“標簽”。 y通常是長度為n_samples的一維數組。

scikit-learn中所有受監督的估計器都執行fit(X,y)方法以擬合模型,并執行predict(X)方法,給定未標記的觀察值X,該方法返回預測的標記y。

詞匯:分類和回歸

如果預測任務是將觀察結果分類為一組有限標簽,換句話說就是“命名”觀察到的對象,則該任務稱為分類任務。另一方面,如果目標是預測連續目標變量,則稱其為回歸任務。

在scikit-learn中進行分類時,y是整數或字符串的向量。

注意:有關scikit-learn中使用的基本機器學習詞匯的快速指南,請參見scikit-learn機器學習簡介教程。

最近鄰和維度詛咒

分類鳶尾花數據集: 鳶尾花數據集是一項分類任務,包括從其花瓣和萼片的長度和寬度中識別出3種不同類型的鳶尾花(Setosa,Versicolour和Virginica):

import numpy as np
from sklearn import datasets
iris_X, iris_y = datasets.load_iris(return_X_y=True)
np.unique(iris_y)

輸出:

array([012])

k近鄰分類器

最簡單的分類器是最近鄰分類器:給定新的觀測值X_test,在訓練集中(即用于訓練估計器的數據)找到具有最近特征向量的觀測值。(有關這種類型的分類器的更多信息,請參見在線Scikit-learn文檔的Nearest Neighbors部分。)

訓練集和測試集

在嘗試使用任何學習算法進行實驗時,重要的是不要在用于擬合估算器的數據上測試估算器的預測,因為這不會評估新數據上估算器的性能。 這就是為什么數據集經常被分成訓練和測試數據的原因。

KNN(k個最近鄰)分類示例:

# 在訓練和測試數據中分割鳶尾花數據
# 隨機排列,隨機分割數據
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:]]

# 創建并擬合最近鄰分類器
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier()
knn.fit(iris_X_train, iris_y_train)

knn.predict(iris_X_test)

iris_y_test

輸出:

KNeighborsClassifier()

array([1210002120])

array([1110002120])

維度詛咒

為了使估算器有效,您需要相鄰點之間的距離小于某個值,這取決于問題。在一個維度上,這平均需要 點。在上述 -NN 示例的上下文中,如果僅通過一個值在0到1范圍內的特征和訓練觀察來描述數據,則新數據將比距離遠出。因此,與類間特征變化的規模相比,最近的鄰居決策規則將很快變得有效。

如果要素數量為,則現在需要 個點。假設我們在一個維度上需要10個點:現在,在維度的空間上則需要個點才能鋪平[0,1]空間。隨著變得越來越大,一個好的估計量所需的訓練點數呈指數增長。

例如,如果每個點僅是一個數字(8個字節),那么在大約的維度上有效的-NN估計量將需要比整個互聯網的當前估計大小(±1000艾字節左右)更多的訓練數據。

這稱為維數詛咒,是機器學習解決的核心問題。

線性模型:從回歸到稀疏

糖尿病數據集

糖尿病數據集包含442位患者的10個生理變量(年齡,性別,體重,血壓),并顯示一年后疾病進展的指標:

diabetes_X, diabetes_y = datasets.load_diabetes(return_X_y=True)
diabetes_X_train = diabetes_X[:-20]
diabetes_X_test  = diabetes_X[-20:]
diabetes_y_train = diabetes_y[:-20]
diabetes_y_test  = diabetes_y[-20:]

當前的任務是根據生理變量預測疾病的進展。

線性回歸

LinearRegression最簡單的形式是通過調整一組參數將線性模型擬合到數據集,以使模型的殘差平方和盡可能小。

線性模型:

  • :數據

  • :目標變量

  • :系數

  • :觀察噪聲

from sklearn import linear_model
regr = linear_model.LinearRegression()
regr.fit(diabetes_X_train, diabetes_y_train)

print(regr.coef_)  

# 均方誤差
np.mean((regr.predict(diabetes_X_test) - diabetes_y_test)**2)


# 解釋方差得分:1是完美預測,0表示X和y之間沒有線性關系。
regr.score(diabetes_X_test, diabetes_y_test)

輸出:

[   0.30349955 -237.63931533  510.53060544  327.73698041 -814.13170937
  492.81458798  102.84845219  184.60648906  743.51961675   76.09517222]

2004.56760268...

0.5850753022690...

緊縮

如果每個維度的數據點很少,則觀測值中的噪聲會引起高方差:

X = np.c_[ .51].T
y = [.51]
test = np.c_[ 02].T
regr = linear_model.LinearRegression()

import matplotlib.pyplot as plt 
plt.figure() 

np.random.seed(0)
for _ in range(6): 
    this_X = .1 * np.random.normal(size=(21)) + X
    regr.fit(this_X, y)
    plt.plot(test, regr.predict(test)) 
    plt.scatter(this_X, y, s=3)  

高維統計學習的一種解決方案是將回歸系數縮小為零:任意兩個隨機選擇的觀察值很可能是不相關的。 這稱為Ridge回歸:

regr = linear_model.Ridge(alpha=.1)

plt.figure() 

np.random.seed(0)
for _ in range(6): 
    this_X = .1 * np.random.normal(size=(21)) + X
    regr.fit(this_X, y)
    plt.plot(test, regr.predict(test)) 
    plt.scatter(this_X, y, s=3

這是偏差/方差折衷的一個示例:脊alpha參數越大,偏差越大,方差越小。

我們可以選擇α以最大程度地減少遺漏的錯誤,這次使用糖尿病數據集而不是我們的綜合數據:

alphas = np.logspace(-4-16)
print([regr.set_params(alpha=alpha)
           .fit(diabetes_X_train, diabetes_y_train)
           .score(diabetes_X_test, diabetes_y_test)
       for alpha in alphas])

輸出:

[0.5851110683883..., 0.5852073015444..., 0.5854677540698...,
 0.5855512036503..., 0.5830717085554..., 0.57058999437...]

注意:捕獲阻止模型泛化為新數據的擬合參數噪聲稱為過擬合。 脊回歸帶來的偏差稱為正則化。

稀疏性

注意:完整的糖尿病數據集的表示將涉及11個維度(10個特征維度和一個目標變量)。 很難就這種表示法建立一種直覺,但記住這將是一個相當空的空間,這可能會很有用。

我們可以看到,盡管特征2在整個模型中具有很強的系數,但是當與特征1一起考慮時,它傳達的y信息很少。

為了改善問題的狀況(即減輕維度詛咒),僅選擇信息性特征并將非信息性特征(例如特征2設置為0)會很有趣。Ridge回歸會減少其貢獻,但不會設置 他們為零。 另一種懲罰方法稱為Lasso(最小絕對收縮和選擇算子),可以將一些系數設置為零。 這種方法稱為稀疏方法,稀疏性可以看作是Occam剃刀的一種應用:更喜歡簡單的模型。

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_)

輸出:

Lasso(alpha=0.025118864315095794)

[   0.         -212.43764548  517.19478111  313.77959962 -160.8303982    -0.
 -187.19554705   69.38229038  508.66011217   71.84239008]

針對同一問題的不同算法

可以使用不同的算法來解決相同的數學問題。 例如,scikit-learn中的套索對象使用坐標下降法解決了套索回歸問題,該方法在大型數據集上非常有效。 但是,scikit-learn還使用LARS算法提供了LassoLars對象,對于估計的權重向量非常稀疏的問題(即觀察很少的問題)非常有效。

分類

對于分類,如在標記虹膜任務中一樣,線性回歸不是正確的方法,因為它將對遠離決策邊界的數據賦予過多的權重。 線性方法是擬合S型函數或邏輯函數:

輸入:

log = linear_model.LogisticRegression(C=1e5)
log.fit(iris_X_train, iris_y_train)

輸出:

LogisticRegression(C=100000.0)

這就是知名的邏輯回歸:

多標簽分類

如果您要預測多個類別,則經常使用的選擇是對所有分類器進行擬合,然后使用投票啟發法進行最終決策。

邏輯回歸的收縮率和稀疏性

C參數控制LogisticRegression對象中的正則化量:C的值較大會導致正則化程度降低。 懲罰=“ l2”給出收縮率(即非稀疏系數),而懲罰=“ l1”給出稀疏性。

練習

嘗試用最近的鄰居和線性模型對數字數據集進行分類。 忽略最后的10%,并根據這些觀察結果測試預測性能。

from sklearn import datasets, neighbors, linear_model

X_digits, y_digits = datasets.load_digits(return_X_y=True)
X_digits = X_digits / X_digits.max()

解決方案:https://scikit-learn.org/stable/_downloads/bfcebce45024b267e8546d6914acfedc/plot_digits_classification_exercise.py

支持向量機(SVM)

線性支持向量機

支持向量機屬于判別模型家族:它們試圖找到樣本的組合以構建一個平面,以最大化兩個類別之間的余量。 正則化是由C參數設置的:C的值較小意味著使用分隔線附近的許多或所有觀測值來計算裕度(更正則化); C的值較大,表示在接近分隔線的觀察值上計算裕度(較少的正則化)。

示例:

在鳶尾花數據集中繪制不同的SVM分類器

SVM可用于回歸–SVR(支持向量回歸)–或分類–SVC(支持向量分類)。

from sklearn import svm
svc = svm.SVC(kernel='linear')
svc.fit(iris_X_train, iris_y_train)

輸出:

SVC(kernel='linear')

警告:歸一化數據

對于包括SVM在內的許多估算器而言,對于每個要素而言,擁有具有單位標準差的數據集對于獲得良好的預測至關重要。

使用核函數

在要素空間中,類并非總是線性可分離的。 解決方案是建立一個決策函數,該決策函數不是線性的,而是可以是多項式的。 這是使用內核技巧完成的,該技巧可以看作是通過將內核置于觀察值上來創建決策能量:

互動范例

參見SVM GUI以下載svm_gui.py;。 使用左右按鈕添加兩個類別的數據點,擬合模型并更改參數和數據。

練習

嘗試使用SVM對虹膜數據集中的第1類和第2類進行分類,并具有2個主要特征。 忽略每堂課的10%,并根據這些觀察結果測試預測性能。

警告:課程是有序的,請不要遺漏最后的10%,您只能在一個課程上進行測試。

提示:您可以在網格上使用Decision_function方法來獲取一些感覺。

輸入:

iris = datasets.load_iris()
X = iris.data
y = iris.target

X = X[y != 0, :2]
y = y[y != 0]

解決方案見:https://scikit-learn.org/stable/_downloads/91f0cd01beb5b964a5e1ece5bdd15499/plot_iris_exercise.py

模型選擇:選擇估計量及其參數

分數和交叉驗證的分數

如我們所見,每個估算器都公開一種計分方法,該方法可以判斷新數據的擬合(或預測)質量。 越大越好。

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

輸出:

0.98

為了更好地衡量預測準確性(我們可以將其用作模型擬合優度的代理),我們可以將數據依次分成折疊,用于訓練和測試:

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)

輸出:

[0.934..., 0.956..., 0.939...]

這被叫做K折交叉驗證。

交叉驗證生成器

Scikit-learn具有一組類,這些類可用于生成流行的交叉驗證策略的訓練/測試索引列表。

他們公開了一個拆分方法,該方法接受要拆分的輸入數據集,并為所選交叉驗證策略的每次迭代生成訓練/測試集索引。

本示例顯示了split方法的示例用法。

輸入:

from sklearn.model_selection import KFold, cross_val_score
X = ["a""a""a""b""b""c""c""c""c""c"]
k_fold = KFold(n_splits=5)
for train_indices, test_indices in k_fold.split(X):
     print('Train: %s | test: %s' % (train_indices, test_indices))

輸出:

Train: [2 3 4 5 6 7 8 9] | test: [0 1]
Train: [0 1 4 5 6 7 8 9] | test: [2 3]
Train: [0 1 2 3 6 7 8 9] | test: [4 5]
Train: [0 1 2 3 4 5 8 9] | test: [6 7]
Train: [0 1 2 3 4 5 6 7] | test: [8 9]

然后可以輕松執行交叉驗證:

[svc.fit(X_digits[train], y_digits[train]).score(X_digits[test], y_digits[test]) for train, test in k_fold.split(X_digits)]

輸出:

[0.963..., 0.922..., 0.963..., 0.963..., 0.930...]

可以使用cross_val_score幫助器直接計算交叉驗證得分。 給定一個估算器,交叉驗證對象和輸入數據集,cross_val_score將數據重復拆分為一個訓練和一個測試集,使用該訓練集訓練該估算器,并根據測試集計算交叉算子的每次迭代的得分 驗證。

默認情況下,估算器的得分方法用于計算各個得分。

請參閱指標模塊以了解有關可用評分方法的更多信息。

cross_val_score(svc, X_digits, y_digits, cv=k_fold, n_jobs=-1)

輸出:

array([0.963888890.922222220.9637883 , 0.9637883 , 0.93036212])

n_jobs = -1表示將在計算機的所有CPU上調度計算。

可替代地,可以提供計分參數以指定替代的計分方法。

cross_val_score(svc, X_digits, y_digits, cv=k_fold,
                scoring='precision_macro')

輸出:

array([0.965782890.927089220.966814760.963628970.93192644])

交叉驗證生成器

KFold (n_splits, shuffle, random_state) StratifiedKFold (n_splits, shuffle, random_state) GroupKFold (n_splits)
將其拆分為K折,在K-1上訓練,然后在左側進行測試。 與K折相同,但保留每個折內的類分布。 確保同一組不在測試和培訓集中
ShuffleSplit (n_splits, test_size, train_size, random_state) StratifiedShuffleSplit GroupShuffleSplit
根據隨機排列生成訓練/測試索引。 與shuffle split相同,但保留每次迭代內的類分布。 確保同一組不在測試和培訓集中。
LeaveOneGroupOut () LeavePGroupsOut (n_groups) LeaveOneOut ()
采用組數組對觀察進行分組。 忽略P組 忽略指定的一個觀察值。
LeavePOut (p) PredefinedSplit
忽略P個觀察值 根據預定義的拆分生成訓練/測試索引。

練習

在數字數據集上,繪制具有線性核的SVC估計量的交叉驗證得分作為參數C的函數(使用點的對數網格,范圍為1到10)。

import numpy as np
from sklearn.model_selection import cross_val_score
from sklearn import datasets, svm

X, y = datasets.load_digits(return_X_y=True)

svc = svm.SVC(kernel='linear')
C_s = np.logspace(-10010)

scores = list()

解決方案見鏈接:手寫數據集上的交叉驗證

網格搜索和交叉驗證的估計量

網格搜索

scikit-learn提供了一個對象,該對象在給定數據的情況下,在參數網格上的估計器擬合期間計算分數,并選擇參數以最大化交叉驗證分數。 該對象在構造期間接受一個估算器,并公開一個估算器API:

from sklearn.model_selection import GridSearchCV, cross_val_score
Cs = np.logspace(-6-110)
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                            


# 測試集的預測性能不如訓練集
clf.score(X_digits[1000:], y_digits[1000:])      

輸出:

GridSearchCV(cv=None,...)

0.925...

0.0077...

0.943...

默認情況下,GridSearchCV使用3倍交叉驗證。但是,如果檢測到通過了分類器而不是回歸器,則使用分層的3倍。默認值將在版本0.22中更改為5倍交叉驗證。

嵌套交叉驗證

cross_val_score(clf, X_digits, y_digits) 

輸出:

array([0.938..., 0.963..., 0.944...])
并行執行兩個交叉驗證循環:一個由GridSearchCV估計器設置gamma,另一個由cross_val_score來測量估計器的預測性能。所得分數是對新數據的預測分數的無偏估計。

警告:不能嵌套使用并行計算的對象(n_jobs不同于1)。

交叉驗證的估計量

可以在逐個算法的基礎上更高效地完成交叉驗證以設置參數。這就是為什么對于某些估計器,scikit-learn會顯示交叉驗證:評估通過交叉驗證自動設置其參數的估計器性能估計器:

from sklearn import linear_model, datasets
lasso = linear_model.LassoCV()
X_diabetes, y_diabetes = datasets.load_diabetes(return_X_y=True)
lasso.fit(X_diabetes, y_diabetes)

# 估算器自動選擇其lambda:
lasso.alpha_

輸出:

LassoCV()

0.00375...

這些估算器的名稱與對應估算器的名稱類似,后綴“ CV”。

練習

在糖尿病數據集上,找到最佳正則化參數alpha。

獎勵:您對選擇出的alpha有多少信心?

from sklearn import datasets
from sklearn.linear_model import LassoCV
from sklearn.linear_model import Lasso
from sklearn.model_selection import KFold
from sklearn.model_selection import GridSearchCV

X, y = datasets.load_diabetes(return_X_y=True)
X = X[:150]

解決方案:糖尿病數據集上的交叉驗證練習

無監督學習:尋求數據表示

聚類:將觀察分組在一起

聚類中解決的問題

在給定鳶尾花數據集的情況下,如果我們知道虹膜有3種類型,但沒有分類學家來標記它們的話:我們可以嘗試進行聚類任務:將觀察結果分成分離良好的一組,稱為聚類。

K均值聚類

請注意,存在許多不同的聚類標準和相關算法。 最簡單的聚類算法是K-means。

輸入:

from sklearn import cluster, datasets
X_iris, y_iris = datasets.load_iris(return_X_y=True)

k_means = cluster.KMeans(n_clusters=3)
k_means.fit(X_iris)

print(k_means.labels_[::10])

print(y_iris[::10])

輸出:

KMeans(n_clusters=3)

[1 1 1 1 1 0 0 0 0 0 2 2 2 2 2]

[0 0 0 0 0 1 1 1 1 1 2 2 2 2 2]

警告:聚類絕對不能保證恢復基本事實(譯者注:即找到真實標簽)。 首先,很難選擇正確數量的群集。 其次,盡管scikit-learn使用了幾種技巧來緩解此問題,但是該算法對初始化很敏感,并且可以陷入局部最小值。

不要過度解讀聚類結果。

應用示例:矢量量化

一般而言,尤其是KMeans,聚類可以看作是選擇少量樣本來壓縮信息的一種方式。 該問題有時稱為矢量量化。 例如,這可以用于后繼圖像:

import scipy as sp
try:
   face = sp.face(gray=True)
except AttributeError:
   from scipy import misc
   face = misc.face(gray=True)
X = face.reshape((-11)) # 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_
face_compressed = np.choose(labels, values)
face_compressed.shape = face.shape

輸出:

KMeans(n_clusters=5, n_init=1)

分層聚集聚類:Ward

層次聚類方法是一種聚類分析,旨在建立聚類的層次。通常,此技術的各種方法是:

  • 集聚-自下而上的方法:每個觀察都從其自己的簇開始,并且以最小化鏈接標準的方式迭代地合并簇。當感興趣的簇僅由少量觀察組成時,這種方法特別有趣。當簇數很大時,它的計算效率比k均值高得多。

  • 分裂-自上而下的方法:所有觀察都始于一個簇,當一個簇向下移動時,它將被迭代地拆分。對于估計大量聚類,此方法既緩慢(由于所有觀察都是從一個聚類開始,然后遞歸拆分),而且在統計上是不適定的。

連接受限的集群

通過聚集聚類,可以通過提供連通性圖來指定可以將哪些樣本聚在一起。 scikit-learn中的圖由它們的鄰接矩陣表示。通常,使用稀疏矩陣。例如,在對圖像進行聚類時,這對于檢索連接的區域(有時也稱為連接的組件)很有用。

from skimage.data import coins
from scipy.ndimage.filters import gaussian_filter
from skimage.transform import rescale
rescaled_coins = rescale(
    gaussian_filter(coins(), sigma=2),
    0.2, mode='reflect', anti_aliasing=False, multichannel=False
)
X = np.reshape(rescaled_coins, (-11))

我們需要圖像的矢量化版本。 'rescaled_coins'是硬幣圖像的縮小版本,以加快處理速度:

from sklearn.feature_extraction import grid_to_graph
connectivity = grid_to_graph(*rescaled_coins.shape)

定義數據的圖形結構。連接到鄰近的像素:

n_clusters = 27  #簇的數量

from sklearn.cluster import AgglomerativeClustering
ward = AgglomerativeClustering(n_clusters=n_clusters, linkage='ward',
                               connectivity=connectivity)
ward.fit(X)

label = np.reshape(ward.labels_, rescaled_coins.shape)

輸出:

AgglomerativeClustering(connectivity=..., n_clusters=27)

功能集聚

我們已經看到稀疏性可以用來減輕維數的詛咒,即與特征數量相比,觀測值不足。另一種方法是將相似的特征融合在一起:特征集聚。可以通過在特征方向上進行聚類(換句話說,對轉置后的數據進行聚類)來實現此方法。

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)

輸出:

FeatureAgglomeration(connectivity=..., n_clusters=32)

轉換和逆轉換(inverse_transform)方法

一些估計器會公開一種轉換方法,例如以減少數據集的維數。

分解:從信號到分量和負載

組件(成分/特征)和負載

如果X是我們的多元數據,那么我們要解決的問題是在不同的觀察基礎上重寫它:我們想學習載荷L和一組分量C,使得X = LC。存在選擇的不同標準組件

主成分分析:PCA

主成分分析(PCA)選擇解釋信號中最大方差的連續成分。

上面觀察到的點云在一個方向上非常平坦:三個單變量特征之一幾乎可以使用另外兩個來精確計算。 PCA尋找數據不一致的方向。

當用于轉換數據時,PCA可以通過投影在主要子空間上來降低數據的維數。

#創建一個僅2個有用維度的信號

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_) 

輸出:

[  2.18565811e+00   1.19346747e+00   8.43026679e-32]

如我們所見,只有前兩個組件是有用的。

pca.n_components = 2
X_reduced = pca.fit_transform(X)
X_reduced.shape

輸出:

(100, 2)

獨立成分分析:ICA

獨立組件分析(ICA)選擇組件,以便它們的載荷分布具有最大數量的獨立信息。 它能夠恢復非高斯獨立信號:

# 獲取樣本數據
import numpy as np
from scipy import signal
time = np.linspace(0102000)
s1 = np.sin(2 * time)  # 信號1 : 正弦信號
s2 = np.sign(np.sin(3 * time))  # 信號2:方波信號
s3 = signal.sawtooth(2 * np.pi * time)  # 信號3: 鋸齒信號
S = np.c_[s1, s2, s3]
S += 0.2 * np.random.normal(size=S.shape)  # 增加噪音
S /= S.std(axis=0)  # 標準化數據
# 混合數據
A = np.array([[111], [0.521], [1.512]])  # 混和矩陣
X = np.dot(S, A.T)  # 獲取觀測值

# 計算ICA
ica = decomposition.FastICA()
S_ = ica.fit_transform(X)  # 得到預測結果
A_ = ica.mixing_.T
np.allclose(X,  np.dot(S_, A_) + ica.mean_)

輸出:

True

全部放在一起

管道

我們已經看到,一些估計器可以轉換數據,并且一些估計器可以預測變量。 我們還可以創建組合的估計量:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd

from sklearn import datasets
from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV


# 定義管道以搜索PCA截斷和分類器正則化的最佳組合。
pca = PCA()
# 將公差設置為較大的值可以使示例更快
logistic = LogisticRegression(max_iter=10000, tol=0.1)
pipe = Pipeline(steps=[('pca', pca), ('logistic', logistic)])

X_digits, y_digits = datasets.load_digits(return_X_y=True)

# 可以使用__分隔的參數名稱來設置管道的參數:
param_grid = {
    'pca__n_components': [515304564],
    'logistic__C': np.logspace(-444),
}
search = GridSearchCV(pipe, param_grid, n_jobs=-1)
search.fit(X_digits, y_digits)
print("Best parameter (CV score=%0.3f):" % search.best_score_)
print(search.best_params_)

# 繪制PCA色譜
pca.fit(X_digits)

fig, (ax0, ax1) = plt.subplots(nrows=2, sharex=True, figsize=(66))
ax0.plot(np.arange(1, pca.n_components_ + 1),
         pca.explained_variance_ratio_, '+', linewidth=2)
ax0.set_ylabel('PCA explained variance ratio')

ax0.axvline(search.best_estimator_.named_steps['pca'].n_components,
            linestyle=':', label='n_components chosen')
ax0.legend(prop=dict(size=12))

特征臉的人臉識別

本示例中使用的數據集是“未經處理的、有標簽的人臉”(也稱為LFW)的預處理摘錄:

http://vis-www.cs.umass.edu/lfw/lfw-funneled.tgz(233MB)

"""
===================================================
使用特征臉和SVM的臉部識別示例
===================================================

本示例中使用的數據集是“貼有標簽的未經處理的面孔”,又名LFW_:

   http://vis-www.cs.umass.edu/lfw/lfw-funneled.tgz(233MB)

.._ LFW:http://vis-www.cs.umass.edu/lfw/

數據集中排名前5名的人員的預期結果:

================================================== =

================== ============ ======= ========== =======
                   precision    recall  f1-score   support
================== ============ ======= ========== =======
     Ariel Sharon       0.67      0.92      0.77        13
     Colin Powell       0.75      0.78      0.76        60
  Donald Rumsfeld       0.78      0.67      0.72        27
    George W Bush       0.86      0.86      0.86       146
Gerhard Schroeder       0.76      0.76      0.76        25
      Hugo Chavez       0.67      0.67      0.67        15
       Tony Blair       0.81      0.69      0.75        36

      avg / total       0.80      0.80      0.80       322
================== ============ ======= ========== =======

"""

from time import time
import logging
import matplotlib.pyplot as plt

from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import fetch_lfw_people
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.decomposition import PCA
from sklearn.svm import SVC


print(__doc__)

# 在標準輸出上顯示進度日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')


# #############################################################################
# 下載數據(如果尚未存儲在磁盤上)并將其作為numpy數組加載

lfw_people = fetch_lfw_people(min_faces_per_person=70, resize=0.4)

# 內省圖像數組以找到形狀(用于繪制)
n_samples, h, w = lfw_people.images.shape

# 對于機器學習,我們直接使用這2個數據(因為相對像素位置信息被該模型忽略)
X = lfw_people.data
n_features = X.shape[1]

# 要預測的標簽是該人的身份證
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)


# #############################################################################
# 使用分層k折分為訓練集和測試集

# 分割需練級與測試集
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=42)


# #############################################################################
# 在人臉數據集(視為未標記數據集)上計算PCA(特征臉):無監督特征提取/降維
n_components = 150

print("Extracting the top %d eigenfaces from %d faces"
      % (n_components, X_train.shape[0]))
t0 = time()
pca = PCA(n_components=n_components, svd_solver='randomized',
          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))


# #############################################################################
# 訓練SVM分類模型

print("Fitting the classifier to the training set")
t0 = time()
param_grid = {'C': [1e35e31e45e41e5],
              'gamma': [0.00010.00050.0010.0050.010.1], }
clf = GridSearchCV(
    SVC(kernel='rbf', class_weight='balanced'), 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_)


# #############################################################################
# 對測試集中的模型質量進行定量評估

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)))


# #############################################################################
# 使用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(())


# 在測試集的一部分上繪制預測結果

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)

# 繪制最有意義的特征臉圖庫

eigenface_titles = ["eigenface %d" % i for i in range(eigenfaces.shape[0])]
plot_gallery(eigenfaces, eigenface_titles, h, w)

plt.show()

輸出:

數據集中排名前5名的人員的預期結果:

                   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

未解決的問題:股票市場結構

我們可以預測給定時間內Google的股價變化嗎?

股市結構可視化

尋求幫助

項目郵件清單

如果您遇到scikit-learn的錯誤,或者需要在文檔字符串或在線文檔中進行說明,請隨時在郵件列表中詢問。

機器學習從業者問答社區

網站 說明
Quora.com Quora有一個與機器學習相關的問題的主題,其中還包含一些有趣的討論:https://www.quora.com/topic/Machine-Learning
Stack Exchange Stack Exchange系列站點托管用于機器學習問題的多個子域。

– _“斯坦福大學的吳安德教授教授的一本優秀的免費在線機器學習課程”:https://www.coursera.org/learn/machine-learning

– _“另一種出色的免費在線課程,采用了更通用的人工智能方法”:https://www.udacity.com/course/intro-to-artificial-intelligence–cs271