Python, scikit-learn

【scikit-learn】決定木によるクラス分類【DecisionTreeClassifier】


本記事では、機械学習ライブラリのscikit-learnを利用して、決定木のアルゴリズムに基づいてクラス分類を行う方法について書きます。

本記事における用語の説明

まずはいくつか用語の説明をします。

既に知っているという方は読み飛ばして下さい。

クラス分類とは

対象となるデータがいくつかのグループの内どれに属するのかを予測することです。

例としては、スパムメールの分類(受信メールがスパムか否かを予測)などが挙げられます。

決定木とは

AI関連技術である機械学習の代表的な手法の一つです。基本単位のノードがいくつも繋がった有向グラフのような構造をしています。

各ノードはそれぞれの位置、役割から以下のような分類となります。

  • 最上位のノード(根ノード):
    予測対象となるデータは最初にこのノードへ入力される
  • 最下位のノード(葉ノード):
    入力されたデータは最後にこのノードへ到達する
  • それ以外のノード:
    設定された条件式に従ってデータを次のノードへ遷移させる

決定木では、入力されたデータの値に基づいて根ノードから次々とノードを遷移していき、最終的にどの葉ノードに到達するかで出力の値を決定します。

ノードの数や条件式は、学習データに対する予測を行う上で最適なものが設定されるようになっています。

なお、決定木のメリット、デメリットはそれぞれ以下の通りです。

  • メリット:
    数値データ、カテゴリデータなど、複数種のデータが混在したデータセットも扱うことが可能
  • デメリット:
    性能が学習データにかなり依存するため頑健なモデルを構築しずらい

実際にプログラムを作成してみる

それでは、決定木のアルゴリズムに基づいてクラス分類を行うプログラムを作成してみます。

プログラム作成の手順

ここでは、以下の手順で処理を実装します。

  1. 実験用のデータセットを用意する
  2. データセットの一部を利用して学習(モデルの構築)を行う
  3. 構築したモデルを用いて残りのデータセットに対する予測を行う

今回に限らず、機械学習のモデルを構築する際には上記手順で実行することが多いです。

使用する実験用データセット

scikit-learnには、学習やテストで使用する実験用のデータセットが用意されているため、今回はその中の一つのアヤメの計測データ(load_iris)を使用します。

使用するデータセットの概要は以下の通りです。

花弁や萼片の長さなどの情報(4項目)を入力データとしてアヤメの種類を予測します。

モデル構築に使用するクラス

scikit-learnには、決定木のアルゴリズムに基づいてクラス分類の処理を行うDecisionTreeClassifierクラスが存在するため、今回はこれを利用します。

DecisionTreeClassifierの主なパラメータは以下の通りです。(一部省略)

  • criterion:{‘gini’, ‘entropy’}
    学習時、モデルの評価に使用する指標
  • splitter:{‘best’, ‘random’}
    各ノードの条件式の設定方法
  • max_depth:int型 or None
    決定木の深さの最大値(Noneの場合は、深さの制限無し)
  • random_state:int型
    乱数のシードを指定する

DecisionTreeClassifierはsklearn.treeパッケージからインポートします。

実装例

上記の手順に従ってプログラムを作成します。使用する言語はPythonです。

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier

import random

if __name__ == '__main__':

    # データセットを読み込む
    iris = load_iris()
    x = iris.data
    y = iris.target

    # 読み込んだデータセットをシャッフルする
    p = list(zip(x, y))
    random.shuffle(p)
    x, y = zip(*p)

    # 学習データの件数を指定する
    train_size = 100
    test_size = len(x) - train_size

    # データセットを学習データとテストデータに分割する
    train_x = x[:train_size]
    train_y = y[:train_size]
    test_x = x[train_size:]
    test_y = y[train_size:]

    # 決定木の学習を行う
    tree = DecisionTreeClassifier(criterion='gini', max_depth=None)
    tree.fit(train_x, train_y)

    # 学習させたモデルを使ってテストデータに対する予測を出力する
    count = 0
    pred = tree.predict(test_x)
    for i in range(test_size):
        print('[{0}] correct:{1}, predict:{2}'.format(i, test_y[i], pred[i]))
        if pred[i] == test_y[i]:
            count += 1

    # 予測結果から正答率を算出する
    score = float(count) / test_size
    print('{0} / {1} = {2}'.format(count, test_size, score))

このプログラムを実行すると以下の出力結果が得られます。

[0] correct:0, predict:0
[1] correct:0, predict:0
[2] correct:2, predict:2
...省略...
[47] correct:0, predict:0
[48] correct:1, predict:1
[49] correct:0, predict:0
50 / 50 = 1.0

テスト用データ50件に対する予測は正答率が1.0となりました。非常に高い分類精度が得られたことがわかります。