アヤメのサンプルデータを用いた機械学習体験

(1) ライブラリのインポートとデータのロード&中身確認

機械学習用ライブラリsklearnから必要なデータと関数をインポートします
Numpyもインポートしておきます

In [1]:
from sklearn import datasets, svm
import numpy as np

データ解析用ライブラリpandasを用いて、アヤメの学習用サンプルデータをロードします

In [2]:
import pandas as pd
dat=pd.read_csv("/content/iris0.csv") #, encoding="SHIFT-JIS")#"utf-8-sig")
dat
Out[2]:
がく片の長さ(cm) がく片の幅(cm) 花びらの長さ(cm) 花びらの幅(cm) アヤメの種類
0 5.1 3.5 1.4 0.2 0
1 4.9 3.0 1.4 0.2 0
2 4.7 3.2 1.3 0.2 0
3 4.6 3.1 1.5 0.2 0
4 5.0 3.6 1.4 0.2 0
... ... ... ... ... ...
145 6.7 3.0 5.2 2.3 2
146 6.3 2.5 5.0 1.9 2
147 6.5 3.0 5.2 2.0 2
148 6.2 3.4 5.4 2.3 2
149 5.9 3.0 5.1 1.8 2

150 rows × 5 columns

ロードしたアヤメのデータから,入力に対応するX(特徴量)と,出力に対応するy(クラスラベル)を取り出します.

まずXを取り出します.以下の3つの方法ではどれも同じ結果が得られます.

In [3]:
X=dat.iloc[:,[0,1,2,3]].values
#X(特徴量)として使う変量を取り出します.
#最後の"values"で,データを数値として扱えるようにします.
In [4]:
X=dat.iloc[:,:4].values
#X(特徴量)として使う変量を取り出します.
#最後の"values"で,データを数値として扱えるようにします.
In [5]:
X=dat.loc[:,['がく片の長さ(cm)', 'がく片の幅(cm)', '花びらの長さ(cm)', '花びらの幅(cm)']].values
#X(特徴量)として使う変量を取り出します.
#最後の"values"で,データを数値として扱えるようにします.

変数Xのデータのタイプを確認します

In [6]:
type(X)
Out[6]:
numpy.ndarray

Xのデータの形を確認します

In [7]:
X.shape
Out[7]:
(150, 4)

Xの0番データを見てみます→ 4つの数字のセット(=ベクトル)であることがわかります

In [8]:
X[0]
Out[8]:
array([5.1, 3.5, 1.4, 0.2])

Xの変量名を,「variables」という変数で保存します.

In [9]:
variables=dat.columns[:4]
print(variables)
Index(['がく片の長さ(cm)', 'がく片の幅(cm)', '花びらの長さ(cm)', '花びらの幅(cm)'], dtype='object')

Xの4つのデータはアヤメの[がく片の長さ(cm),がく片の幅(cm),花びらの長さ(cm),花びらの幅(cm)]です

次にターゲットyにあたるデータを取り出します.
yはアヤメの種類を表す数字で、アヤメの種類は0, 1, 2の数字で表されています。
各々の番号が下記のようなアヤメの種類に対応します.
0: 'セトーサ'
1: 'バーシーカラー'
2: 'バージニカ'

yの数字を取り出します。以下の2つの方法ではどれも同じ結果が得られます.

In [10]:
y=dat.iloc[:,4].values
In [11]:
y=dat.loc[:,"アヤメの種類"].values

yのデータの形を確認します.

In [12]:
y.shape
Out[12]:
(150,)

yのデータを見てみます

In [13]:
y
Out[13]:
array([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, 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, 2, 2])

yのクラスラベル名を,labelという変数名で保存します.

In [14]:
label=np.array(["セトーサ","バーシーカラー","バージニカ"])
print(label)
['セトーサ' 'バーシーカラー' 'バージニカ']

ここまで用意した変数まとめ:
特徴量X(入力)は各アヤメの[がく片の長さ(cm),がく片の幅(cm),花弁の長さ(cm),花弁の幅幅(cm)]の4つの数字(ベクトル)、
クラスy(出力)は対応するアヤメの名前['セトーサ' 'バーシーカラー' 'バージニカ']を表す数字[0,1,2]です

(2) 4つの全特徴量Xを用いて、3つのクラスyを分類する関数を機械学習で求めてみよう

sklearnの関数を用いて,Xからyを得る関数を機械学習で生成します

In [15]:
clf=svm.SVC(C=1.0,kernel='linear')
clf.fit(X,y)
Out[15]:
SVC(kernel='linear')

機械学習で得られた関数にXを代入して、学習結果を確認します.

In [16]:
result=clf.predict(X)
result #学習の結果得られた関数にXを入力した場合の出力(学習結果)です
Out[16]:
array([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, 2, 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, 2, 2])

答え合わせをしてみます

In [17]:
result==y
Out[17]:
array([ True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True, False,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True])

正解率を求めてみます

In [18]:
print('正解率')
success=sum(result==y)
print(100.0*success/len(y))#X,yの分割の仕方により結果は変わる
正解率
99.33333333333333

(3) 学習用のデータを視覚化してみよう

視覚化に必要なライブラリと日本語を扱うためのライブラリをインポートします.

In [19]:
import matplotlib.pyplot as plt
!pip install japanize-matplotlib
import japanize_matplotlib
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/
Collecting japanize-matplotlib
  Downloading japanize-matplotlib-1.1.3.tar.gz (4.1 MB)
     |████████████████████████████████| 4.1 MB 27.8 MB/s 
Requirement already satisfied: matplotlib in /usr/local/lib/python3.7/dist-packages (from japanize-matplotlib) (3.2.2)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.7/dist-packages (from matplotlib->japanize-matplotlib) (0.11.0)
Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->japanize-matplotlib) (1.4.4)
Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->japanize-matplotlib) (2.8.2)
Requirement already satisfied: numpy>=1.11 in /usr/local/lib/python3.7/dist-packages (from matplotlib->japanize-matplotlib) (1.21.6)
Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.7/dist-packages (from matplotlib->japanize-matplotlib) (3.0.9)
Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from kiwisolver>=1.0.1->matplotlib->japanize-matplotlib) (4.1.1)
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.7/dist-packages (from python-dateutil>=2.1->matplotlib->japanize-matplotlib) (1.15.0)
Building wheels for collected packages: japanize-matplotlib
  Building wheel for japanize-matplotlib (setup.py) ... done
  Created wheel for japanize-matplotlib: filename=japanize_matplotlib-1.1.3-py3-none-any.whl size=4120275 sha256=2d956c294ba94e78a6987ee574156f66cceaec3d57b4b80024af4af95e2f216e
  Stored in directory: /root/.cache/pip/wheels/83/97/6b/e9e0cde099cc40f972b8dd23367308f7705ae06cd6d4714658
Successfully built japanize-matplotlib
Installing collected packages: japanize-matplotlib
Successfully installed japanize-matplotlib-1.1.3

2変量のプロット(散布図)を描いてみます

In [20]:
####1変量目,2変量目の散布図
#青:セトーサ(0), オレンジ:バーシーカラー(1), 緑:バージニカ(2)
cmap = plt.get_cmap("tab10")#ここでカラーマップ(使用する色のパレットのようなもの)を指定
plt.scatter(X[:,0],X[:,1],c=cmap(y))#ラベルで色分け
plt.xlabel(variables[0])
plt.ylabel(variables[1])
Out[20]:
Text(0, 0.5, 'がく片の幅(cm)')
In [21]:
####3変量目,4変量目の散布図.1,2変量目よりはクラスが分かれている
plt.scatter(X[:,2],X[:,3],c=cmap(y))
plt.xlabel(variables[2])
plt.ylabel(variables[3])
Out[21]:
Text(0, 0.5, '花びらの幅(cm)')

(参考)可視化ライブラリseabornを用いると散布図行列を描くことができます.

散布図行列は,各変量のクラス毎の分布図, 変量の全ての組み合わせの散布図をまとめてplotすることができます.

In [22]:
import seaborn as sns
sns.pairplot(dat,hue="アヤメの種類",palette="tab10")#hueで,色分けするクラス情報のある変量を指定しています
Out[22]:
<seaborn.axisgrid.PairGrid at 0x7f882b153390>

(4) Xの2つの変量データから2つのクラスを分類する関数を機械学習で求めてみよう

イメージを掴むため,3,4番目の変量(花びらの長さ・幅)のみから'バーシーカラー'と'バージニカ'を判別する分類器を作成してみましょう.

In [23]:
print(label)
['セトーサ' 'バーシーカラー' 'バージニカ']
In [24]:
print(variables)
Index(['がく片の長さ(cm)', 'がく片の幅(cm)', '花びらの長さ(cm)', '花びらの幅(cm)'], dtype='object')

データの取り出し

y,Xからそれぞれyのクラスが1,2である(クラスがクラスが0以外である)アヤメの情報を取り出し、
かつXからは3,4番目の変量のみを取り出し,それぞれの結果をy2とX2として保存します.

In [25]:
##############3,4変量,versicolorとvirginicaのみ###########
y2=y[y!=0] #クラス番号が0(セトーサ)のy以外を取り出し,y2として保存
X2=X[y!=0] #Xからクラス番号が0(セトーサ)のX以外を取り出し,X2として保存
X2=X2[:,(2,3)] #さらにXから3,4変量目のみを取り出す
x_variable=variables[2]
y_variable=variables[3]
In [26]:
X2.shape #X2の大きさを確認
Out[26]:
(100, 2)
In [27]:
y2.shape #y2の大きさを確認
Out[27]:
(100,)

sklearnの関数を用いて,X2からy2を得る関数を機械学習で生成します

In [28]:
clf=svm.SVC(C=1.0,kernel='linear')
clf.fit(X2,y2)
Out[28]:
SVC(kernel='linear')

機械学習で得られた関数にテストデータのXを代入して、学習結果を確認します

In [29]:
result=clf.predict(X2)
print(result)
[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 2 1 1 1 1 1 2 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 2 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]

答え合わせをしてみます

In [30]:
result==y2
Out[30]:
array([ True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True, False,  True,  True,  True,  True,  True,  True,
       False,  True,  True,  True,  True,  True, False,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True, False,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True, False,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True])
In [31]:
print('正解率')
success=sum(result==y2)
print(100.0*success/len(y2))
正解率
95.0

パラメータwの推定結果(→境界線のパラメータ)を確認します

In [32]:
print(clf.coef_)#w1,w2に対応
print(clf.intercept_)#w0に対応
[[2.1829247  2.25365588]]
[-14.41486828]

推定した境界線を,散布図と共に図示してみましょう

In [33]:
######結果
plt.scatter(X2[:,0],X2[:,1],c=cmap(y2))#まず散布図表示
plt.xlabel(x_variable)
plt.ylabel(y_variable)
##境界線をplotするため,境界線の横軸(x1),縦軸(x2)に対応する座標を計算
x1 = np.arange(np.min(X2[:,0]),np.max(X2[:,0]),(np.max(X2[:,0]) - np.min(X2[:,0]))/10)#境界線をplotするx1軸の範囲指定
x2 = -(x1*clf.coef_[0][0]+clf.intercept_)/clf.coef_[0][1]#x1に対応するx2の座標
plt.plot(x1,x2,"r-")#(x1,x2)の座標点を表示し,線で繋ぐ
Out[33]:
[<matplotlib.lines.Line2D at 0x7f88278eeb50>]