決定木とは 目的変数と説明変数の関係を木構造として表現したもの で機械学習の分野における予測モデルのひとつである。
意思決定 の過程(要因)を ツリー構造 として分析する手法を機械学習に応用したものなので決定木と呼ばれる。(たぶん)
目標(目的変数)にいたる決定の集合(説明変数)を分類するが、既知のルールから予測モデルを生成する ので、機械学習のなかでも『教師あり学習』に分類される。
すでに起こった出来事を教師データとして決定木のプログラムに与えてやると予測モデルを作ってくれる。
詳しい説明はこのページの下の方にある 参考文献 をご覧ください。
未来の抽せん数字を予想するために使うのですが、「何が」抽せん数字を決定しているのかというのがポイントです。
説明変数の組み合わせを色々試して自分なりの予測モデル(決定木)を構築しましょう。
次回の抽せん数字を予想する例として「前回の抽せん数字より大きい数字が出るのか、それとも小さい数字が出るのか」というのをやってみます。
前回よりも数字が大きいのか、小さいのかがわかるだけでも予想数字を絞り込むことができますよね。
第1回から第4回の抽せん数字で決定木のモデルを作って、第6回の数字が第5回よりも大きくなるのか小さくなるのかを予想してみます。
次回の抽せん数字のほうが大きい数字か? を意思決定したいので、教師データは以下のように作成しました。
| 抽せん数字 | 次回の抽せん数字のほうが大きい数字か? | |
|---|---|---|
| 回号 | ||
| 1 | 191 | yes |
| 2 | 988 | no |
| 3 | 194 | no |
| 4 | 105 | yes |
| 5 | 592 | (ここを予測する) |
scikit-learn という機械学習のライブラリを使って決定木からの予測をやります。 決定木のモジュールは Decision Trees です。
教師データの数値の配列と結果の配列を学習させ、テストデータの数値の配列を与えると予測結果が返ってきます。
説明変数は位ごとの数字にします。つまり「100の位」「10の位」「1の位」の3つが説明変数になります。 目的変数は「次回の抽せん数字のほうが大きい数字か」を yes または no で示します。
from sklearn import tree
train_test = np.array([[1,9,1], [9,8,8], [1,9,4], [1,0,5]]) # 説明変数
train_label = np.array(['yes', 'no', 'no', 'yes']) # 目的変数
clf = tree.DecisionTreeClassifier()
clf.fit(train_test, train_label)
# 予測
clf.predict([5,9,2])
# 予測結果
# array(['yes'],
# dtype='|S3')
ということで第6回の抽せん数字は第5回よりも大きいとの予測結果が出ました。 実際の第6回の抽せん数字は「792」でしたので予測は当たっています。
学習済みのデータで試してみましょう。
clf.predict(train_test)
# array(['yes', 'no', 'no', 'yes'],
# dtype='|S3')
clf.predict(train_test) == train_label
array([ True, True, True, True], dtype=bool)
当然ながら予測結果は当たっています。
教師データを多くするとどうでしょうか?第2000回まで学習させてみます。
df_numbers は 前準備のページ で作成した pandas の DaraFrame です。
## 教師データの作成
# 2000回分を学習させるために次回の回号も必要なので2001回までのデータを取得する
s_test = df_numbers.loc[1:2001, 'winning'].astype(np.int64)
# 変化率を計算して目的変数を生成
# 次回の抽せん数字のほうが大きい数字であれば変化率は 0 より小さくなる
s_label = s_test.pct_change(-1) < 0
# 2000回分のデータを配列で取得する
train_test = df_numbers.loc[1:2000].as_matrix(columns=['place100', 'place10', 'place1'])
# 変化率から計算した目的変数はひとつ多いので削る
train_label = s_label[:-1]
## 決定木モデルの生成
clf = tree.DecisionTreeClassifier()
clf.fit(train_test, train_label)
# 予測 第2001回のデータで第2002回の数字が大きくなるのかを予測
clf.predict([3,2,5])
# 予測結果
# array([ True], dtype=bool)
第2002回の抽せん数字は第2001回よりも大きいとの予測結果が出ました。 実際の第2002回の抽せん数字は「567」でしたので予測は当たっています。
機械学習では予測モデルを構築するのが目的ですので、予測の精度についても考慮します。
「 前回の抽せん数字より数字が大きくなるのか小さくなるのかを予想 」したときの教師データ(第1回から第2000回のデータ)を用います。
精度を計算するテストデータは学習されていない第2001回から第4000回のデータを使用しました。
下記のようなスクリプトで精度を計算します。
import pandas as pd
import numpy as np
from sklearn import tree
def make_test_data(start_idx, end_idx):
"""
回号ごとの抽せん数字と次回の抽せん数字のほうが大きい数字か
:param start_idx: int. 回号の開始位置
:param end_idx: int. 回号の終了位置
:return tuple: ([sample], [target])
"""
last_idx = end_idx + 1
df_numbers = pd.read_table('numbers3-utf8.txt', index_col=0, encoding='utf_8', dtype={'winning': np.int64})
df_numbers = df_numbers.loc[start_idx:last_idx]
df_numbers['greater'] = df_numbers.winning.pct_change(-1) < 0
train_test = df_numbers.loc[start_idx:end_idx].as_matrix(columns=['place100', 'place10', 'place1'])
train_label = df_numbers.loc[start_idx:end_idx, 'greater']
return (train_test, train_label)
# 学習のための教師データ
train_sample, train_label = make_test_data(1, 2000)
# 精度をテストするためのデータ
test_sample, test_label = make_test_data(2001, 4000)
clf = tree.DecisionTreeClassifier()
clf.fit(train_sample, train_label)
# 平均精度の出力
print(clf.score(test_sample, test_label))
# clf.score() の結果
# 0.671
精度は 67% のようです。「大きいまたは小さい」という確率を2分の1と考えれば高い精度と言えそうです。
目的変数に曜日を加えたり sklearn.tree.DecisionTreeClassifier のパラメータを調整すると精度を変化させることができますので色々試してみましょう。
最終更新日: 2015年09月06日(日)