今回は、多変量の入力データを主成分分析により解析して、変量の次元を減らし、機械学習する方法をご紹介いたします。主成分分析とは、相関のある多数の変数から相関のない少数で全体のばらつきを最もよく表す主成分と呼ばれる変数を合成する多変量解析の手法の1つです。データの次元を削減するために用いられます。主成分を与える変換は、第一主成分の分散を最大化し、続く主成分はそれまでに決定した主成分と直交するという拘束条件の下で分散を最大化するようにして選ばれます。主成分の分散を最大化することは、観測値の変化に対する説明能力を可能な限り主成分に持たせる目的で行われます。選ばれた主成分は互いに直交し、与えられた観測値のセットを線型結合として表すことができます。 | ![]() |
今回、使用するデータは、オープンソースであるUCI機械学習リポジトリから、「ワインデータ」を使用します。178のデータからなり、変数は、'Alcohol', 'Malic acid', 'Ash', 'Alcalinity of ash', 'Magnesium', 'Total phenols', 'Flavanoids', 'Nonflavanoid phenols', 'Proanthocyanins', 'Color intensity', 'Hue', 'OD280/OD315 of diluted wines', 'Proline'の化学特性による13の変量からなります。
https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data
各サンプルは、3つの異なるクラス(1または 2またh 3)に属します。それぞれ、イタリアの異なる地域で栽培された異なるぶどうのタイプを表しています。
13の変量がありますが、2次元の図にプロットする都合上、主成分分析により、2つの主成分を抽出し、Pythonを使用してワインの種類を予測する機械学習モデルを作成します。主成分分析とPythonを使用した機械学習の流れは、概ね以下になります。なお、Pythonのバージョンは3.5以上を想定しています。
- プロット出力用の関数を定義する。
- データを入力する。
- 入力データを、トレーニングデータとテストデータに分ける。
- トレーニングデータを使用してデータの標準偏差と平均値を求める。
- 標準偏差と平均値を使用して、トレーニングデータとテストデータを、それぞれ標準化する。
- 適切なモデル(Classifier)を選択する。
- 主成分分析により、入力データから上位2つの主成分を抽出する。
- 主成分分析により抽出されたトレーニングデータを使用して、モデルに機械学習させる。
- テストデータを使用して、ラベルの分類を行い、モデルを評価する。
- 学習結果を図にプロットする。
では、各ステップを詳しく見ていきましょう。
①プロット出力用の関数を定義する。
まず、対話形式ではなく、Pythonのスクリプトをファイルで用意します。Pythonスクリプトの先頭に以下の2行を添付しておくことをお勧めします。
#!/usr/bin/env python # -*- coding:utf-8 -*- |
ここでは、以下のように、「plot_decision_regions」という名前のプロット出力用の関数を定義します。
import numpy as np import matplotlib.pyplot as plt from matplotlib.colors import ListedColormap
def plot_decision_regions(X, y, classifier, resolution=0.02): # setup marker generator and color map markers = ('s', 'x', 'o', '^', 'v') colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan') cmap = ListedColormap(colors[:len(np.unique(y))]) # plot the decision surface x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1 x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1 xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution), np.arange(x2_min, x2_max, resolution)) Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T) Z = Z.reshape(xx1.shape) plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap) plt.xlim(xx1.min(), xx1.max()) plt.ylim(xx2.min(), xx2.max()) # plot class samples for idx, cl in enumerate(np.unique(y)): plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1], alpha=0.8, c=cmap(idx), marker=markers[idx], label=cl) |
②データを入力する。
今回は、冒頭でご紹介した「ワインデータ」を、オープンソースとして提供しているサイトのURLから、pandasライブラリーを使用して以下のようにデータを抽出します。変量Xの配列(178 x 13)に、ラベル(ワインの種類)を y(178x 1)という配列に178サンプル分のデータを格納します。
import pandas as pd X, y = df_wine.iloc[:, 1:].values, df_wine.iloc[:, 0].values |
③入力データを、トレーニングデータとテストデータに分ける。
scikit-learning.model_selectionライブラリーのtrain_test_split関数を使用して、
変量配列Xとラベル配列yについて、トレーニングデータとテストデータに分けます。変量配列Xを、それぞれ、X_train配列, X_test配列に分割し、ラベル配列yは、y_tarin配列, y_test配列へそれぞれ分割します。test_sizeのパラメータにより、テストデータの割合を指定できます。ここでは、0.3を指定することで、テストデータの割合を全体の30%と指定しています。全178サンプルの30%(= 53サンプル)がテストデータで、残りの125サンプルがトレーニングデータとなります。random_state=0を指定することにより、ランダムにトレーニングデータとテストデータを分割することができます。
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.3, random_state=0) |
④トレーニングデータを使用してデータの標準偏差と平均値を求める。
sklearn.preprocessingライブラリーのStandardScaler関数を用いて、変量配列X_trainとX_testを標準化します。まず、標準化のための標準偏差と平均値は、トレーニングデータのみを使用して計算しなければなりません。fitメソッドを使用して以下のように行います。
from sklearn.preprocessing import StandardScaler sc = StandardScaler() sc.fit(X_train) |
⑤標準偏差と平均値を使用して、トレーニングデータとテストデータを、それぞれ標準化する。
次に、変量配列のトレーニングデータとテストデータを、transformメソッドを用いて、それぞれ標準化します。標準化した変量配列をそれぞれ、X_train_std, X_test_stdに格納します。
X_train_std = sc.transform(X_train) X_test_std = sc.transform(X_test) |
⑥適切なモデル(Classifier)を選択する。
様々なClassifierがPythonライブラーの中でサポートされています。線形データとして分類できる場合は、Perceptron, Adaptive Linear Neuron(Adaline),Logistic regulation, Support Vector Machine(SVM),Decision tree, Random forests, K-nearest neighbors(KNN)などがあります。第5回の「アイリス花データ」では、Perceptronのモデルを選択しましたが、今回の「ワインデータ」では、Logistic regulationを選択することにいたします。sklearn.linear_modelライブラリーのLogisticRegression関数を使用して以下のように記述します。
from sklearn.linear_model import LogisticRegression lr = LogisticRegression() |
Logistic Regressionにご興味のある方は、以下の本の第3章を是非、読んでみてください。
「Python Machine Learning: Unlock Deeper Insights into Machine Learning With This Vital Guide to Cutting-edge Predictive Analytics」
Sebastian Raschka (著)
出版社: Packt Publishing (2015/9/23)
言語: 英語
ISBN-10: 1783555130
ISBN-13: 978-1783555130
⑦主成分分析により、入力データから上位2つの主成分を抽出する。
sklearn.decompositionライブラリーの中でサポートされているPCA関数を用いて、トレーニングデータについて主成分分析を行い、トレーニングデータ及びテストデータについて、2つの主成分を抽出します。
from sklearn.decomposition import PCA X_test_pca = pca.transform(X_test_std) |
⑧主成分分析により抽出されたトレーニングデータを使用して、モデルに機械学習させる。
トレーニングデータにfitメソッドを適用して、学習させます。
lr.fit(X_train_pca, y_train) |
⑨テストデータを使用して、ラベルの分類を行い、モデルを評価する。
テストデータを使用して、ラベルの分類を行い、sklearn.metricsライブラリーのaccuracy_score関数を用いて、モデルの精度を評価します。
from sklearn.metrics import accuracy_score y_pred = lr.predict(X_test_pca) print('Accuracy: %.2f' % accuracy_score(y_test,y_pred)) |
出力結果は、以下のように98%の精度と表示されます。
Accuracy: 0.98
⑩学習結果を図にプロットする。
①で定義したplot_decision_regions関数を用いて、トレーニングデータとテストデータについて、それぞれ、抽出した第1主成分を横軸に、第2主成分を縦軸にした2次元領域にプロットします。
まず、トレーニングデータについてプロットします。
plot_decision_regions(X_train_pca, y_train, classifier=lr) |
4サンプルほど、例外がありますが、トレーニングデータについて、概ね、直線で、分類されていることがわかります。次に、テストデータについてプロットします。
plot_decision_regions(X_test_pca, y_test, classifier=lr) |
テストデータについては、例外は1サンプルのみで、トレーニングデータよりも高い精度で、3つの領域に直線で分類できていることがわかります。
全体を通してのコードは以下のようになります。なお、本コードの稼働環境は、Python3.5以上を想定しています。
#!/usr/bin/env python
# -*- coding:utf-8 -*- import numpy as np import matplotlib.pyplot as plt from matplotlib.colors import ListedColormap def plot_decision_regions(X, y, classifier, resolution=0.02): # setup marker generator and color map
markers = ('s', 'x', 'o', '^', 'v') colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan') cmap = ListedColormap(colors[:len(np.unique(y))]) # plot the decision surface
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1 x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1 xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution), np.arange(x2_min, x2_max, resolution)) Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T) Z = Z.reshape(xx1.shape) plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap) plt.xlim(xx1.min(), xx1.max()) plt.ylim(xx2.min(), xx2.max()) # plot class samples for idx, cl in enumerate(np.unique(y)): plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1], alpha=0.8, c=cmap(idx), marker=markers[idx], label=cl) import pandas as pd df_wine = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data', header=None) X, y = df_wine.iloc[:, 1:].values, df_wine.iloc[:, 0].values from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.3, random_state=0) from sklearn.preprocessing import StandardScaler sc = StandardScaler() sc.fit(X_train) X_train_std = sc.transform(X_train) X_test_std = sc.transform(X_test) from sklearn.linear_model import LogisticRegression lr = LogisticRegression() from sklearn.decomposition import PCA pca = PCA(n_components=2) X_train_pca = pca.fit_transform(X_train_std) X_test_pca = pca.transform(X_test_std) lr.fit(X_train_pca, y_train) from sklearn.metrics import accuracy_score y_pred = lr.predict(X_test_pca) print('Accuracy: %.2f' % accuracy_score(y_test,y_pred)) plot_decision_regions(X_train_pca, y_train, classifier=lr) plt.xlabel('PC 1') plt.ylabel('PC 2') plt.legend(loc='lower left') plt.tight_layout() plt.show() plot_decision_regions(X_test_pca, y_test, classifier=lr) plt.xlabel('PC 1') plt.ylabel('PC 2') plt.legend(loc='lower left') plt.tight_layout() plt.show() |