3.6. scikit-learn: Python での機械学習

著者: Fabian Pedregosa, Gael Varoquaux

../../_images/scikit-learn-logo.png

事前準備

3.6.1. データセット例の読み込み

Photo of Iris Virginia

手始めにいくつかのデータを触ってみましょう。データとして Iris データセットとして知られす、とても単純な花のデータベースを使いましょう。

150 のアヤメの花の測定値があります: sepal length, sepal width, petal length そして petal width で Iris setosa Iris versicolor Iris virginica それぞれの品種毎に。

データセットを Python オブジェクトとして読み込みましょう:

>>> from sklearn import datasets
>>> iris = datasets.load_iris()

このデータは .data メンバーとして保管され (n_samples, n_features) の配列です。

>>> iris.data.shape
(150, 4)

各観測値のクラスはデータセットの .target 属性として保管されます。これは n_samples の長さを持つ整数の1次元配列です:

>>> iris.target.shape
(150,)
>>> import numpy as np
>>> np.unique(iris.target)
array([0, 1, 2])

データのリシェイプ例: digits dataset 手書き数字データセット

../../_images/digits_first_image.png

digits dataset は 1797 の画像からなります、それぞれが 8x8 のピクセルイメージで手書きの数字を表します:

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

このデータセットを scikit で使うために、それぞれの 8x8 の画像を長さ 64 のベクトルに変換します:

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

3.6.1.1. 学習と予測

いくつかのデータが得られました、これを元に学習と予測する方法について学んでみましょう。 scikit-learn では既存のデータから esitimator を作り fit(X, Y) メソッドを呼び出すことで学習できます。

>>> from sklearn import svm
>>> clf = svm.LinearSVC()
>>> clf.fit(iris.data, iris.target) # learn from the data
LinearSVC(...)

一旦データから学習ができれば、まだ見ぬデータに対してもっともらしい予測をするためにモデルを使うことができます:

>>> clf.predict([[ 5.0,  3.6,  1.3,  0.25]])
array([0])

注釈

アンダースコアで終わる属性を使うことで。モデルのパラメータにアクセスできます:

>>> clf.coef_   
array([[ 0...]])

3.6.2. 分類

3.6.2.1. k-近傍法による分類

最も単純な分類法は最近傍を使う方法です: 新しい観測値が得られたら n 次元空間の中の最も近いトレーニングサンプルでラベルづけします、ここで n は各サンプルの 特徴 の数です。

../../_images/iris_knn.png

k近傍法は内部的にはトレーニングするサンプルを表現するのに ball tree アルゴリズムを利用します。

KNN (k-nearest neighbors) による分類例:

>>> # Create and fit a nearest-neighbor classifier
>>> from sklearn import neighbors
>>> knn = neighbors.KNeighborsClassifier()
>>> knn.fit(iris.data, iris.target)
KNeighborsClassifier(...)
>>> knn.predict([[0.1, 0.2, 0.3, 0.4]])
array([0])

トレーニングデータセットとテスト用データセット

学習アルゴリズムを実験する際には、フィットに使ったデータを利用して予測結果をテストしないことが重要です。実際 kNN estimator を使うとトレーニングデータセットに対して完璧な予測が常に得られます。

>>> perm = np.random.permutation(iris.target.size)
>>> iris.data = iris.data[perm]
>>> iris.target = iris.target[perm]
>>> knn.fit(iris.data[:100], iris.target[:100])
KNeighborsClassifier(...)
>>> knn.score(iris.data[100:], iris.target[100:])
0.95999...

ボーナス問題: どうしてランダム順列を使わないのでしょうか?

3.6.2.2. サポートベクターマシン (SVMs) での分類

3.6.2.2.1. 線形サポートベクターマシン

SVM は2つのクラスの間のマージンを最大化するような超平面を構築します。SVM はサポートベクトルと呼ばれる入力インプットの部分集合を選び、これは超平面による分割に近い観測値です。

../../_images/svm_margin.png
>>> from sklearn import svm
>>> svc = svm.SVC(kernel='linear')
>>> svc.fit(iris.data, iris.target)
SVC(...)

scikit-learn にはいくつかのサポートベクトルマシンの実装があります。最もよく利用されるものは svm.SVC, svm.NuSVC そして svm.LinearSVC; “SVC” は Support Vector Classifier を意味します (回帰に SVMs を使う場合もあります、その場合は scikit-learn で “SVR” と呼ばれます)。

練習問題

svm.SVC で数字データセットのトレーニングをします。最後の 10% を除外して、それらの観測値に対する予測パフォーマンスを検証しましょう。

3.6.2.2.2. カーネルの利用

超平面で常にクラス毎に分けられないこともあります、そのため非線形で多項式や指数の決定関数が望ましいこともあります:

線形カーネル

多項式カーネル

RBF カーネル (Radial Basis Function)

svm_kernel_linear svm_kernel_poly svm_kernel_rbf
>>> svc = svm.SVC(kernel='linear')
>>> svc = svm.SVC(kernel='poly',
... degree=3)
>>> # degree: polynomial degree
>>> svc = svm.SVC(kernel='rbf')
>>> # gamma: inverse of size of
>>> # radial kernel

練習問題

上記カーネルの内どれが数字データセットに対してよい予測パフォーマンスがだせますか?

3.6.3. クラスタリング: 観測値をグループ分けする

Iris データベースが与えられたとき、3種類のアヤメがあると知っていますがラベルにはアクセスできないとします、このとき 教師なし学習 を試すことができます: いくつかの基準に従って観測値をいくつかのグループに クラスタリング します。

3.6.3.1. K平均クラスタリング

最も単純なクラスタリングアルゴリズムは k平均法です。この方法はデータセットを k のクラスタに分割します、各観測値をクラスタに割り当てて、クラスタ平均からの観測値の間の距離を (n 次元空間上で)最小化します; その後平均は再計算されます。この操作はクラスタが収束するか max_iter 回の最大に到達するまで反復的に実行されます。

(k平均法の別実装が SciPy の cluster パッケージで利用できます。 scikit-learn の実装はオブジェクト API と賢い初期化メソッドを含むいくつかの追加機能などの点で異なります。)

>>> from sklearn import cluster, datasets
>>> iris = datasets.load_iris()
>>> k_means = cluster.KMeans(n_clusters=3)
>>> k_means.fit(iris.data)
KMeans(...)
>>> print(k_means.labels_[::10])
[1 1 1 1 1 0 0 0 0 0 2 2 2 2 2]
>>> print(iris.target[::10])
[0 0 0 0 0 1 1 1 1 1 2 2 2 2 2]
cluster_iris_truth cluster_iris_kmeans k_means_iris_8

正解

K平均法 (3クラスタ)

K平均法 (8クラスタ)

画像圧縮への応用

クラスタリングは観測値から少数の情報を選びだす方法としても使うことができます (より小さい空間へ射影するように)。例えば画像のポスタリゼーションに利用できます (徐々にトーンが変化したものをトーンの少ないいくつかの領域への変換する):

>>> from scipy import misc
>>> face = misc.face(gray=True).astype(np.float32)
>>> X = face.reshape((-1, 1)) # We need an (n_sample, n_feature) array
>>> K = k_means = cluster.KMeans(n_clusters=5) # 5 clusters
>>> k_means.fit(X)
KMeans(...)
>>> values = k_means.cluster_centers_.squeeze()
>>> labels = k_means.labels_
>>> face_compressed = np.choose(labels, values)
>>> face_compressed.shape = face.shape
face face_compressed

元画像

K平均法による量子化 (K=5)

3.6.4. 主成分分析による次元削減

pca_3d_axis pca_3d_aligned

上の図では点群が観測値に一次元に平坦にまたがっています、そのため一つの特徴量を利用した方が他の2つを利用するより厳密な計算ができます。PCA はデータの 平坦 でない方向を探し、データのじげんを部分空間に射影することで次元を削減できます。

警告

scikit-learn のバージョンによって PCA は decomposition モジュールか pca モジュールのどちらかで使えます。

>>> from sklearn import decomposition
>>> pca = decomposition.PCA(n_components=2)
>>> pca.fit(iris.data)
PCA(copy=True, n_components=2, whiten=False)
>>> X = pca.transform(iris.data)

(変換した) iris データセットを可視化できます:

>>> import pylab as pl
>>> pl.scatter(X[:, 0], X[:, 1], c=iris.target)
<matplotlib.collections...Collection object at ...>
../../_images/pca_iris.png

PCA は高次元のデータセットの可視化に便利なだけではありません。前処理段階で利用することで、高次元で効率がよくない教師あり学習方法を高速化に利用できます。

3.6.5. まとめて: 顔認識

主成分解析による次元削減とサポートベクトルマシンによる分類を使った顔認識の例を扱います。

../../_images/faces1.png

face recognition example 最低限のバージョンです:

import numpy as np
import pylab as pl
from sklearn import cross_val, datasets, decomposition, svm
# ..
# .. load data ..
lfw_people = datasets.fetch_lfw_people(min_faces_per_person=70, resize=0.4)
perm = np.random.permutation(lfw_people.target.size)
lfw_people.data = lfw_people.data[perm]
lfw_people.target = lfw_people.target[perm]
faces = np.reshape(lfw_people.data, (lfw_people.target.shape[0], -1))
train, test = iter(cross_val.StratifiedKFold(lfw_people.target, k=4)).next()
X_train, X_test = faces[train], faces[test]
y_train, y_test = lfw_people.target[train], lfw_people.target[test]
# ..
# .. dimension reduction ..
pca = decomposition.RandomizedPCA(n_components=150, whiten=True)
pca.fit(X_train)
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)
# ..
# .. classification ..
clf = svm.SVC(C=5., gamma=0.001)
clf.fit(X_train_pca, y_train)
# ..
# .. predict on new images ..
for i in range(10):
print(lfw_people.target_names[clf.predict(X_test_pca[i])[0]])
_ = pl.imshow(X_test[i].reshape(50, 37), cmap=pl.cm.gray)
_ = raw_input()

Full code: faces.py

3.6.6. Linear model: from regression to sparsity

糖尿病データセット

糖尿病データセットは 442 の患者に対する 10 の生理学変数 (年齢、性別、体重、血圧) の測定値から構成され、さらに 1年後の病状の進行を示す指標を含んでいます:

>>> 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:]

やる作業は生理学変数から病気の予測です。

3.6.6.1. スパースモデル

問題の条件を改善するために (重要でない変数、次元の呪いの軽減、前特徴洗濯の前処理、など)、重要な特徴のみを選びだし、重要でない特徴を 0 に設定します。いくつかの係数を 0 に設定する減点アプローチは Lasso と呼ばれています。このような方法は スパース法 と呼ばれており、スパース性は Occam の剃刀の応用とみることもできます: 単純なモデルが複雑なものより好ましい。

>>> from sklearn import linear_model
>>> regr = linear_model.Lasso(alpha=.3)
>>> regr.fit(diabetes_X_train, diabetes_y_train)
Lasso(...)
>>> regr.coef_ # very sparse coefficients
array([ 0. , -0. , 497.34075682, 199.17441034,
-0. , -0. , -118.89291545, 0. ,
430.9379595 , 0. ])
>>> regr.score(diabetes_X_test, diabetes_y_test)
0.5510835453...

スコアは線形回帰(最小自乗)ととてもよく似ています:

>>> lin = linear_model.LinearRegression()
>>> lin.fit(diabetes_X_train, diabetes_y_train)
LinearRegression(...)
>>> lin.score(diabetes_X_test, diabetes_y_test)
0.5850753022...

同じ問題に対する異なるアルゴリズム

数学的に同じ問題を異なるアルゴリズムで解くことができます。例えば sklearnLasso オブジェクトは coordinate descent 法を利用して lasso 回帰を解きます、この方法は大きなデータセットに対して効率的です。しかし sklearn は同様に LassoLARS オブジェクトを提供しており、これは LARS を使います、重みベクトルがスパースな問題に対してとても効率的で、つまり、観測値が少ないときに有効です。

3.6.7. モデル選択: estimator とパラメータの選択

3.6.7.1. グリッドサーチと交差検証 estimator

3.6.7.1.2. 交差検証 estimator

交差検証でパラメータを設定するのは、アルゴリズムの対応を利用して効率的に実施されます。特定の estimator に対して scikit-learn は “CV” estimator としてアクセスできるようにして、交差検証で自動的にパラメータを設定されるからです。

>>> 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)
LassoCV(alphas=None, ...)
>>> # The estimator chose automatically its lambda:
>>> lasso.alpha_
0.012...

これらの estimator は対応するものに ‘CV’ を加えた名前で呼びだされます。

練習問題

糖尿病のデータセットに対して、最適な正則化パラメータ alpha を見つけましょう。