第3章 あやめの分類
1 データの読み込み
本格的なデータを利用し、機械学習を行ってみます。 よく使われるデータは花のあやめ(Iris)のデータです。あやめには、さまざまな種類が有り、花びらの長さ・幅と花がくの長さ・幅に特徴があります。花びらの長さ・幅や花がくの長さ・幅によって、種類を予測する、というのが今回の目標です。
早速、データを読み込んでみましょう。 ファイル iris.ipynb に以下を記述します。
import pandas as pd
df = pd.read_csv("iris.csv")
df
このデータには以下の列があります。
- SepalLength 花がくの長さ
- SepalWidth 花がくの幅
- PetalLength 花びらの長さ
- PetalWidth 花びらの幅
- Name 種類
SepalLength、SepalWidth、PetalLength、PetalWidthが特徴量、Nameが正解ラベルになります。
種類には、どのようなものがあるのかも見ておきましょう。
df["Name"].unique()
Iris-setosa、Iris-versicolor、Iris-virginicaの3種類があることが分かります。
各種類毎に散布図行列を作成してみると種類毎に花がくや花びらのデータに特徴がありそうです。
import seaborn as sns
sns.set(font=["Meiryo"])
sns.pairplot(data=df, hue="Name")
これを学習し、未知のデータを予測します。 特徴量をx、正解ラベルをy に入れましょう。
x = df[["SepalLength", "SepalWidth", "PetalLength", "PetalWidth"]]
y = df["Name"]
2 モデルの構築と予測
今回もモデルは決定木を使用し、学習を行います。
from sklearn import tree
model = tree.DecisionTreeClassifier()
model.fit(x, y)
学習終了後に未知の値を入力し、予測を出してみましょう。
model.predict([[5.5, 3.8, 1.9, 1.2]])
3 テストデータの作成
これで予測は出来ましたが、果たして機械学習が上手くいっているのか、あやめの専門家でも無ければよく分かりません。そこでこのモデルが正しいかの評価を行ってみましょう。
これまでは、読み込んだデータを全て学習に使用していました。しかし、これを一部のデータだけを学習に使うことにして、残りは評価用のテストデータとして残しておきます。
あとでモデルが完成後、このテストデータを使って予測させ、正解を得られたかを確認するわけです。
学習用とテスト用のデータに分割を行うためには、DataFrameの機能を利用しても良いですが、scikit-learnに便利な分割関数 train_test_split があります。これは指定した割合でtrain(訓練用)とtest(テスト用)に分割をしてくれるものです。
戻り値は以下の4つになります。
- x_train 学習用の特徴量
- x_test テスト用の特徴量
- y_train 学習用の正解ラベル
- y_test テスト用の正解ラベル
20%をテストデータ、残り80%を学習用データに分けるには以下のようにします。
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2)
なお、どのように分けるかはランダムです。評価のためなどで分け方を固定にしたい場合、random_state=0 を付けます。
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, random_state=0)
4 評価の表示
作成した学習用データ、つまり、x_train と y_train を使って学習させます。
# 学習する
model.fit(x_train, y_train)
あとはこのモデルにテストデータを読み込ませて、どれぐらい正解したかを調べれば良いわけです。そのためには、predictにテストデータを指定します。
# テストデータの予測
model.predict(x_test)
しかし、これではどれが正解かがわかりません。どれが正解かをy_test と比較する必要があります。それをやってくれるのが、scoreというメソッドです。
これにテストデータを指定すると、そのデータで予測を行い、どれぐらいが正解しているかを返してくれます。
# 結果の検証
model.score(x_test, y_test)
0.9なら 90%が正解したということです。正解率は90%以上の結果が望ましいです。 なお、決定木は乱数を使って決定木を作ります。そのため、再実行すると違う数値になります。random_state=0 を引数に付けることで乱数が固定されます。
5 まとめ
ここまでの流れをまとめると以下のようになります。
# データの読み込み
import pandas as pd
df = pd.read_csv("iris.csv")
# 特徴量と正解ラベルに分割
x = df[["SepalLength", "SepalWidth", "PetalLength", "PetalWidth"]]
y = df["Name"]
# 学習用とテスト用の分割
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, random_state=0)
# モデルのインポート
from sklearn import tree
model = tree.DecisionTreeClassifier(random_state=0)
# 学習する
model.fit(x_train, y_train)
# 結果の検証
model.score(x_test, y_test)
その後、予測を行います。
# 未知のデータの予測
model.predict([[5.5, 3.8, 1.9, 1.2]])
6 決定木の表示
決定木のアルゴリズムでどのように判定を下しているかを確認してみましょう。
class_namesには決定結果ですので、y_trainのunique()で結果の値を取り出します。x_train.columnsで、特徴量の列名を指定します。
また、そのまま表示すると各判定が重なってしまいます。 図を大きくして重ならないようにmatplotlibのsubplotsでサイズ指定します。
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(font=["Meiryo", "Yu Gothic"])
plt.subplots(figsize=(16, 12))
tree.plot_tree(model,
class_names=y_train.unique(),
feature_names=x_train.columns,
filled=True)
plt.show()
7 特徴量の重要度
決定木を作る際にどの列がより重要な役割を果たしていたのかを知ることが出来ます。それがmodel.feature_importances_ で特徴量の重要度を示します。
model.feature_importances_
単に model.feature_importances_ を表示しても数値が表示されるだけで、何が何の値なのかがわかりにくいので、特徴量の列名と組み合わせてSeriesにして表示してみましょう。
pd.Series(model.feature_importances_, x_train.columns)
水平棒グラフで表示してみます。
plt.barh(x_train.columns, model.feature_importances_)
このように決定木モデルを作成することで何が影響を与えてその結果になっているかを分析することができます。