機械学習の練習問題"あやめの分類"をやってみたよ

# あやめの分類

機械学習の有名な練習問題である、あやめの分類について実施してみます。 これは、花弁や萼片のサイズに関するデータセットをもとに機械学習のモデルを作成し、あやめ(iris)の種類を判定するものです。 機械学習の練習問題として有名なあやめのデータセットはFisher[^1]が1936年に報告した論文に載っているデータを用いたもので、 三種類のあやめ(Iris-versicolor、Iris-setosa、Iris-virginica)の花それぞれ50個体ずつの花弁の長さと幅(PetalLengthCm, PetalWidthCm)、萼片の長さと幅(SepalLengthCm, SepalWidthCm)についてまとめたものとなっています。 今回用いるデータセットは、機械学習の分野で有名なコミュニティである[kaggl](https://www.kaggle.com/)の[Iris Species](https://www.kaggle.com/datasets/uciml/iris)からダウンロードしております。


[^1]:Fisher, R. A. (1936) The use of multiple measurements in taxonomic problems. Annals of Eugenics, 7(2), 179–188.

# データセットの取得

(1)kagglの[Iris Species](https://www.kaggle.com/datasets/uciml/iris)のページにアクセス
(2)kagglのアカウント作成してログイン
(3)"Download"でデータセットを取得

![Screen Shot 2024-02-20 at 0.47.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2804113/eb6b47d4-a04e-c61a-7e59-246d5dbef31d.png)

archive.zipというフォルダがダウンロードできたかと思います。これを解凍すると、database.sqlite、Iris.csvというファイルが入っています。sqliteというのもデータベースのようですが、今回使うのはIris.csvです。


# 機械学習
それでは機械学習を行います。実行はGoogle Colaboratoryにて実施します。

(1)モジュールのインポート

```Python
import numpy as np
import pandas as pd
    
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score

import matplotlib.pyplot as plt
import seaborn as sns
```
    
(2)データのインポート
```Python
iris_df = pd.read_csv("/{Iris.csvのディレクトリ}/Iris.csv")
iris_df.head()
```

![Screen Shot 2024-02-20 at 0.56.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2804113/b9ebd6ad-a5a5-6ed1-d4da-2daf84451bd9.png)

iris_df.head()で最初の4行のデータの可視化をおこなっています。

(3)データの可視化/解析
(3-1)欠損値の確認
```Python    
iris_df.isnull().sum()
```    

![Screen Shot 2024-02-20 at 1.04.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2804113/dddfa451-f3ea-ca14-29ac-997c1827e0db.png)

機械学習のアルゴリズムによっては、データセットの中にNanが含まれていると解析が行えないことがあります。ここでは、最初に欠損値の確認をおこなっています。結果、今回のデータセットには欠損値が含まれていないことがわかります。

(3-2)ヒストグラム
```Python    
f,ax=plt.subplots(2,2,figsize=(18,8))

sns.countplot(x="SepalLengthCm",hue='Species',data=iris_df,ax=ax[0][0])
ax[0][0].set_title('SepalLengthCm vs Species')

sns.countplot(x="SepalWidthCm",hue='Species',data=iris_df,ax=ax[1][0])
ax[1][0].set_title('SepalWidthCm vs Species')

sns.countplot(x="PetalLengthCm",hue='Species',data=iris_df,ax=ax[0][1])
ax[0][1].set_title('PetalLengthCm vs Species')

sns.countplot(x='PetalWidthCm',hue='Species',data=iris_df,ax=ax[1][1])
ax[1][1].set_title('PetalWidthCm vs Species')
plt.show()
```

![Screen Shot 2024-02-20 at 1.12.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2804113/e84aa7bb-0d2f-98c4-4462-9065c73db23d.png)

各あやめの種類に対してそれぞれの部位の大きさの分布がどのようになっているか確認するためヒストグラムを出図しました。このヒストグラムから、全体的にIris-virginicaが大きくてIris-versicolorが中間、Iris-setosaが小さい傾向にあることが見て取れます。さらに、あやめの種類に対して、萼片(Sepal)は明瞭にサイズが分かれておらず、花弁(Petal)は比較的はっきりとサイズが分かれていそうです。次は、これを定量的に比較するために相関関係係数のヒートマップを図示してみます。

(3-3)相関関係係数のヒートマップ

```Python
iris_df2 = iris_df
iris_df2['Speacies_label_encoded'] = iris_df2['Species'].astype('category').cat.codes
    
sns.heatmap(iris_df2.corr(),annot=True,cmap='bwr',linewidths=0.2)
fig=plt.gcf()
fig.set_size_inches(10,8)
plt.show()
```

![Screen Shot 2024-02-20 at 1.23.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2804113/9e1de95c-0381-6c66-13cb-d613b72b936e.png)


相関関係係数とは二つのデータの相関関係の強さを表す数値です。範囲は-1から1で、絶対値が大きいほど強い相関を示し、値が正であれば正の相関、値が負であれば負の相関関係にあることを示します。相関関係係数は数値のデータ同士に対して計算することができますがSpeaciesのように、各値が文字列の場合は計算することができません。Speaciesは三種類のあやめの種類に振り分けられており、このようなデータをカテゴリカルデータと呼びます。カテゴリカルデータについて解析を行いたいときによく用いられる手法として、エンコーディングがあります。これは、三種類のあやめの種類に対して0、1、2の整数値を割り振る手法です。今回Speaciesに対してエンコーディングを行い、Speacies_label_encodedという列を作成しています。Speacies_label_encodedに対してそれぞれの相関関係係数を確認すると、SepalLengthCmが0.78、SepalWidthCmが-0.42、PetalLengthCmが0.95、PetalWidthCmが0.96と花弁(Petal)が萼片(Sepal)に比べて強い相関関係を示していることがわかります。


(4)データの前処理
(4-1)特徴量とラベルの分割
```Python
X = iris_df.drop(["Id","Species"], axis=1)
y = iris_df['Species']
```    
    
(4-2)データの標準化
```Python
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
```
    
(4-3)データの分割
```Python
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.3, random_state=42)
```
    
データを訓練用のデータとテスト用のデータに分割します。

(5)学習
```Python
svm_model = SVC(kernel='linear', random_state=42)
	
svm_model.fit(X_train, y_train)

y_pred = svm_model.predict(X_test)
```

ここではサポートベクターマシン(SVC)というアルゴリズムを用いて学習を行います。

(6)評価
```Python    
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy:", accuracy)
```

![Screen Shot 2024-02-20 at 1.54.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2804113/d5fbadd7-3d6e-eb38-64e0-2704d8c372fc.png)


今回のモデルの正解率は97.8 %でした。かなり良いです。