本ページには広告・プロモーションが含まれています。
決定木とは 目的変数と説明変数の関係を木構造として表現したもの で機械学習の分野における予測モデルのひとつである。
意思決定の過程(要因)をツリー構造として分析する 手法を機械学習に応用したものなので決定木と呼ばれる。
目標(目的変数)にいたる決定の集合(説明変数)を分類するが、既知のルールから予測モデルを生成する ので、機械学習のなかでも『教師あり学習』に分類される。
すでに起こった出来事を教師データとして決定木のプログラムに与えてやると予測モデルを作ってくれる。
詳しい説明はこのページの下の方にある 参考文献 をご覧ください。
未来の抽せん数字を予想するために使うのですが、「何が」抽せん数字を決定しているのかというのがポイントです。
説明変数の組み合わせを色々試して自分なりの予測モデル(決定木)を構築しましょう。
次回の抽せん数字を予想する例として「前回の抽せん数字より大きい数字が出るのか、それとも小さい数字が出るのか」というのをやってみます。
前回よりも数字が大きいのか、小さいのかがわかるだけでも予想数字を絞り込むことができますよね。
第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='<U3')
ということで第6回の抽せん数字は第5回よりも大きいとの予測結果が出ました。 実際の第6回の抽せん数字は「792」でしたので予測は当たっています。
学習済みのデータで試してみましょう。
clf.predict(train_test)
# array(['yes', 'no', 'no', 'yes'], dtype='<U3')
clf.predict(train_test) == train_label
# array([ True, True, True, True])
当然ながら予測結果は当たっています。
教師データを多くするとどうでしょうか?
前準備 で用意した python のデータフレームを使って、第2000回まで学習させてみます。
## 教師データの作成
# 2000回分を学習させるために次回の回号も必要なので2001回までのデータを取得する
s_test = df.loc[1:2001, 'winning'].astype(np.int64)
# 変化率を計算して目的変数を生成
# 次回の抽せん数字のほうが大きい数字であれば変化率は 0 より小さくなる
s_label = s_test.pct_change(-1) < 0
# 2000回分のデータを配列で取得する
train_test = df.loc[1:2000, ['place100', 'place10', 'place1']].values
# 変化率から計算した目的変数はひとつ多いので削る
train_label = s_label[:-1]
## 決定木モデルの生成
clf = tree.DecisionTreeClassifier()
clf.fit(train_test, train_label)
# 予測 第2001回のデータで第2002回の数字が大きくなるのかを予測
clf.predict([3,2,5])
# 予測結果
# array([ True])
第2002回の抽せん数字は第2001回よりも大きいとの予測結果が出ました。 実際の第2002回の抽せん数字は「567」でしたので予測は当たっています。
機械学習では予測モデルを構築するのが目的ですので、予測の精度についても考慮します。
教師データにはモデルが適合するが、学習していない未知のデータに対して正しく予測できないモデルが出来上がってしまうこともあり、 こうした状態を「オーバーフィッティング (過剰適合/過学習)」と呼びます。
オーバーフィッティングを避けるために交差検証(Cross-Validation/クロスバリデーション)というのを行います。
交差検証とは解析のテストのことで、決定木で作った予測モデルが未知のデータに対して正しい分類ができるかを確かめることを指します。
ここでは sklearn を用いてK-分割交差検証をやります。 K-分割交差検証とはデータをK個に分割して、そのうちの1つをテストデータとして扱い、残る K - 1 個を教師データとする手法です。
下記のスクリプトで交差検証と精度の計算が可能です。データは第1回から第4000回のデータを使用しています。
from sklearn.model_selection import cross_val_score
# 4000回のデータを取得
winning = df.loc[1:4000, 'winning'].astype(np.int64)
# 目的変数を(前回の抽せん数字より大きいのか小さいのかを表す) bool 値で計算
# 4001回のデータは無いので4000回目の目的変数は dropna() で取り除く
label = winning.pct_change(-1).dropna() < 0
# 説明変数。行列 (3,999行 x 3列) に変換
data = df.loc[1:3999, ['place100', 'place10', 'place1']].values
# 決定木オブジェクトの生成
clf = tree.DecisionTreeClassifier()
# 交差検証の実行
# cv パラメータを 5 に設定している。
# データを5個に分割、そのうちの1個がテストデータで残りの4個が教師データとなる。
scores = cross_val_score(clf, data, label, cv=5)
# 平均制度
scores.mean()
# 結果: 0.691421151439299
精度は 69% のようです。「大きいまたは小さい」という確率を2分の1(50%)と考えれば、やや高い精度と言えそうです。
では3999回分のデータで予測モデルを作り予想してみましょう。
# 上記のスクリプトからの続き
clf.fit(data, label)
# 第4001回の抽せん数字が第4000回より大きくなるのか小さくなるのかを予測する
# 第4000回の抽せん数字: 404
# 第4001回の抽せん数字: 373
clf.predict([[4,0,4],])
# 予想結果
# array([ True])
True は「数字が大きくなる」ことを意味しますので予想結果ははずれています。
とりあえず今回はここまでとし、今後は精度を上げるための決定木のパラメータ調整について書く予定です。
最終更新日: 2020年01月21日(火)