解析環境セットアップ

ライブラリーおよび関数の準備

このノート全体にわたって、共通して使用するパッケージ、関数やデータなどをここで呼び出して、すぐに使える状態にする。

In [1]:
%matplotlib inline

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
In [2]:
import matplotlib.colors

def plot_decision_region(X, y, clf, resolution=0.02):
  """
  決定領域を可視化するための関数
  
  1 番目の特徴量を横軸座標、2 番目の特徴量を縦軸座標として、決定領域を可視化する。なお、特徴量
  が 3 つ以上存在しても、可視化に使用するのは 1 番目および 2 番目の特徴量だけである。

  入力
    X: 特徴量
    y: 教師ラベル
    clf: 分類器
    resolution: メッシュ化間隔

  出力
    なし(図が表示される)
  """

  # 教師ラベルの色(最大で 6 クラスまで異なる色で対応可能)
  c = ('#bc3c29', '#0072b5', '#20854e', '#7876b1', '#6f99ad', '#e18727')
  cmap = matplotlib.colors.ListedColormap(c[:len(np.unique(y))])

  # 横軸および縦軸の範囲を特徴量から計算する
  x1_min = X[:, 0].min() - 1
  x1_max = X[:, 0].max() + 1
  x2_min = X[:, 1].min() - 1
  x2_max = X[:, 1].max() + 1
  
  # 横軸および縦軸を resolution=0.02 間隔でメッシュ化し、メッシュの交点座標を計算する
  xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
                         np.arange(x2_min, x2_max, resolution))
  
  # メッシュの各交点座標で予測を行う
  # ただし、xx1 および xx2 は 2 次元配列となっているので、ここで両者を ravel メソッドで
  # 列ベクトルに変換してから予測を行う
  z = clf.predict(np.array([xx1.ravel(), xx2.ravel()]).T)

  # 予測結果 z を xx1 と同じ構造の 2 次元配列に変更する
  z = z.reshape(xx1.shape)

  # xx1 を横軸、xx2 を縦軸、予測結果 z を色として、等高図をプロットする
  plt.contourf(xx1, xx2, z, alpha=0.3, cmap=cmap)
  plt.xlim(xx1.min(), xx1.max())
  plt.ylim(xx2.min(), xx2.max())

  # 入力されたデータ(X と y)に点をプロットする
  for idx, cl in enumerate(np.unique(y)):
    plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1], alpha=0.8, c=c[idx], label=cl)
  

  # グラフを調整し表示する
  plt.xlabel('X1')
  plt.ylabel('X2')
  plt.tight_layout()
  plt.show()

データセットの準備

このノートでは scikit-learn パッケージに保存されているワインのデータセットを使用する。このデータセットは、3 種類のワインに対して、アルコール、リンゴ酸などの 13 化学物質を定量した結果が記述されている。このノートで、13 種類の化学物質の定量結果を特徴量とし、ワインの名前(種類)を教師ラベルとして、分類器を作成する。ワインデータセットを取得するには、scikit-learn の datasets.load_wine() 関数を使用する。

In [3]:
import sklearn.datasets
wine = sklearn.datasets.load_wine()

print(wine.DESCR)
.. _wine_dataset:

Wine recognition dataset
------------------------

**Data Set Characteristics:**

    :Number of Instances: 178 (50 in each of three classes)
    :Number of Attributes: 13 numeric, predictive attributes and the class
    :Attribute Information:
 		- Alcohol
 		- Malic acid
 		- Ash
		- Alcalinity of ash  
 		- Magnesium
		- Total phenols
 		- Flavanoids
 		- Nonflavanoid phenols
 		- Proanthocyanins
		- Color intensity
 		- Hue
 		- OD280/OD315 of diluted wines
 		- Proline

    - class:
            - class_0
            - class_1
            - class_2
		
    :Summary Statistics:
    
    ============================= ==== ===== ======= =====
                                   Min   Max   Mean     SD
    ============================= ==== ===== ======= =====
    Alcohol:                      11.0  14.8    13.0   0.8
    Malic Acid:                   0.74  5.80    2.34  1.12
    Ash:                          1.36  3.23    2.36  0.27
    Alcalinity of Ash:            10.6  30.0    19.5   3.3
    Magnesium:                    70.0 162.0    99.7  14.3
    Total Phenols:                0.98  3.88    2.29  0.63
    Flavanoids:                   0.34  5.08    2.03  1.00
    Nonflavanoid Phenols:         0.13  0.66    0.36  0.12
    Proanthocyanins:              0.41  3.58    1.59  0.57
    Colour Intensity:              1.3  13.0     5.1   2.3
    Hue:                          0.48  1.71    0.96  0.23
    OD280/OD315 of diluted wines: 1.27  4.00    2.61  0.71
    Proline:                       278  1680     746   315
    ============================= ==== ===== ======= =====

    :Missing Attribute Values: None
    :Class Distribution: class_0 (59), class_1 (71), class_2 (48)
    :Creator: R.A. Fisher
    :Donor: Michael Marshall (MARSHALL%PLU@io.arc.nasa.gov)
    :Date: July, 1988

This is a copy of UCI ML Wine recognition datasets.
https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data

The data is the results of a chemical analysis of wines grown in the same
region in Italy by three different cultivators. There are thirteen different
measurements taken for different constituents found in the three types of
wine.

Original Owners: 

Forina, M. et al, PARVUS - 
An Extendible Package for Data Exploration, Classification and Correlation. 
Institute of Pharmaceutical and Food Analysis and Technologies,
Via Brigata Salerno, 16147 Genoa, Italy.

Citation:

Lichman, M. (2013). UCI Machine Learning Repository
[https://archive.ics.uci.edu/ml]. Irvine, CA: University of California,
School of Information and Computer Science. 

.. topic:: References

  (1) S. Aeberhard, D. Coomans and O. de Vel, 
  Comparison of Classifiers in High Dimensional Settings, 
  Tech. Rep. no. 92-02, (1992), Dept. of Computer Science and Dept. of  
  Mathematics and Statistics, James Cook University of North Queensland. 
  (Also submitted to Technometrics). 

  The data was used with many others for comparing various 
  classifiers. The classes are separable, though only RDA 
  has achieved 100% correct classification. 
  (RDA : 100%, QDA 99.4%, LDA 98.9%, 1NN 96.1% (z-transformed data)) 
  (All results using the leave-one-out technique) 

  (2) S. Aeberhard, D. Coomans and O. de Vel, 
  "THE CLASSIFICATION PERFORMANCE OF RDA" 
  Tech. Rep. no. 92-01, (1992), Dept. of Computer Science and Dept. of 
  Mathematics and Statistics, James Cook University of North Queensland. 
  (Also submitted to Journal of Chemometrics).

ワインの名前、すなわち教師ラベルは wine.target で取得できる。ワインの名前を実際に取得して表示させると、以下のようにゼロからの整数値のリストとして表示されていることがわかる。scikit-learn を含むほとんどの機械学習パッケージは文字からなるラベル名をそのまま受け付けないので、そのようなラベル名を整数値に変換する必要がある。そのため、独自のデータセットを使用する際に、解析者自身で教師ラベルを整数値に変換する必要がある。

In [4]:
print(wine.target)
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2]

また、特徴量は wine.data で取得できる。特徴量は、NumPy の 2 次元配列として保存されている。独自のデータセットを使用する際に、特徴量をこのように 2 次元配列に変換する必要がある。

In [5]:
print(wine.data.shape)
print(wine.data)
(178, 13)
[[1.423e+01 1.710e+00 2.430e+00 ... 1.040e+00 3.920e+00 1.065e+03]
 [1.320e+01 1.780e+00 2.140e+00 ... 1.050e+00 3.400e+00 1.050e+03]
 [1.316e+01 2.360e+00 2.670e+00 ... 1.030e+00 3.170e+00 1.185e+03]
 ...
 [1.327e+01 4.280e+00 2.260e+00 ... 5.900e-01 1.560e+00 8.350e+02]
 [1.317e+01 2.590e+00 2.370e+00 ... 6.000e-01 1.620e+00 8.400e+02]
 [1.413e+01 4.100e+00 2.740e+00 ... 6.100e-01 1.600e+00 5.600e+02]]

scikit-learn で提供されているデータセットの構造を確認できたので、あとで使いやすいように、特徴量を X、教師ラベルを y に代入する。

In [6]:
X = wine.data
y = wine.target

データセットの分布を可視化して一通り傾向を見てみる。Seaborn の pairplot 関数を使用するには、データをデータフレームとして与える必要があるので、ここで Xy を一つのデータフレームにまとめて可視化を行なう。

In [7]:
wine_df = pd.DataFrame(np.concatenate([y.reshape(y.shape[0], 1), X], axis=1),
                       columns=['y' if i == 0 else 'X' + str(i) for i in range(X.shape[1] + 1)])
print(wine_df)
sns.pairplot(wine_df, hue='y')
       y     X1    X2    X3    X4     X5    X6    X7    X8    X9    X10   X11  \
0    0.0  14.23  1.71  2.43  15.6  127.0  2.80  3.06  0.28  2.29   5.64  1.04   
1    0.0  13.20  1.78  2.14  11.2  100.0  2.65  2.76  0.26  1.28   4.38  1.05   
2    0.0  13.16  2.36  2.67  18.6  101.0  2.80  3.24  0.30  2.81   5.68  1.03   
3    0.0  14.37  1.95  2.50  16.8  113.0  3.85  3.49  0.24  2.18   7.80  0.86   
4    0.0  13.24  2.59  2.87  21.0  118.0  2.80  2.69  0.39  1.82   4.32  1.04   
..   ...    ...   ...   ...   ...    ...   ...   ...   ...   ...    ...   ...   
173  2.0  13.71  5.65  2.45  20.5   95.0  1.68  0.61  0.52  1.06   7.70  0.64   
174  2.0  13.40  3.91  2.48  23.0  102.0  1.80  0.75  0.43  1.41   7.30  0.70   
175  2.0  13.27  4.28  2.26  20.0  120.0  1.59  0.69  0.43  1.35  10.20  0.59   
176  2.0  13.17  2.59  2.37  20.0  120.0  1.65  0.68  0.53  1.46   9.30  0.60   
177  2.0  14.13  4.10  2.74  24.5   96.0  2.05  0.76  0.56  1.35   9.20  0.61   

      X12     X13  
0    3.92  1065.0  
1    3.40  1050.0  
2    3.17  1185.0  
3    3.45  1480.0  
4    2.93   735.0  
..    ...     ...  
173  1.74   740.0  
174  1.56   750.0  
175  1.56   835.0  
176  1.62   840.0  
177  1.60   560.0  

[178 rows x 14 columns]
/opt/anaconda3/lib/python3.7/site-packages/statsmodels/nonparametric/kde.py:487: RuntimeWarning: invalid value encountered in true_divide
  binned = fast_linbin(X, a, b, gridsize) / (delta * nobs)
/opt/anaconda3/lib/python3.7/site-packages/statsmodels/nonparametric/kdetools.py:34: RuntimeWarning: invalid value encountered in double_scalars
  FAC1 = 2*(np.pi*bw/RANGE)**2
Out[7]:
<seaborn.axisgrid.PairGrid at 0x1a25c85950>