■ はじめに
以下の関連記事で扱ったSchoo(スクー)
https://dk521123.hatenablog.com/entry/2020/02/29/003619
の講義で決定木 / ランダムフォレストを勉強する機会が あったのでメモ。 ちなみに、講師の方は以下のブログの方だと思うが 分かりやすかった
https://www.randpy.tokyo/entry/decision_tree_theory
https://www.randpy.tokyo/entry/python_random_forest
学べる事項(学んだこと)
1)Pythonライブラリ 1-1) scikit-learn 1-2) pydotplus 1-3) matplotlib 2)決定木 / ランダムフォレスト
目次
【1】用語整理 1) 決定木 (decision tree) 2)ランダムフォレスト (random forests) 【2】Hello World 【3】サンプル 例1)決定木 例2)ランダムフォレスト
【1】用語整理
以下の関連記事をより抜粋 (詳細や関連用語などは、関連記事を参照)
https://dk521123.hatenablog.com/entry/2013/12/16/225948
1) 決定木 (decision tree)
* 条件分岐を木構造のように繰り返しデータを分類する手法 ⇒ 言葉で説明するより、以下の図見たほうが理解は早い
https://www.randpy.tokyo/entry/decision_tree_theory
https://dev.classmethod.jp/articles/2017ad_20171211_dt-2/
2)ランダムフォレスト (random forests)
* 決定木をたくさん生成し、多数決する(または平均を取る)ような手法 ⇒ 決定"木を集めたから、ランダム"フォレスト(森)"。
【2】Hello World
Step1:データを用意 Step2:Step1データを使って、モデル (=決定木)を作成 Step3: 作成した決定木を使って、予想する
サンプル
# 決定木 from sklearn.tree import DecisionTreeClassifier # Step1:データを用意(今回は簡単なデータ) # 説明変数 x x_trains = [[140, 0], [130, 0], [150, 1], [170, 1]] # 目的変数 y (説明変数の2番目と一致) y_trains = [0, 0, 1, 1] # Step2:Step1データを使って、モデル (=決定木)を作成 # 決定木(Decision Tree) classifier = DecisionTreeClassifier() # 説明変数と目的変数の両方を与え、決定木を作成 classifier = classifier.fit(x_trains, y_trains) # Step3: 作成した決定木を使って、予想する x_tests = [[153, 1]] y_tests = classifier.predict(x_tests) print(y_tests)
出力結果
[1]
【3】サンプル
「決定木」「ランダムフォレスト」のサンプルを書いていく
使用するデータセット「Titanic」について
* 以下の関連記事ででてきた「Kaggle(カグル)」
https://dk521123.hatenablog.com/entry/2020/03/28/131839
の「Titanic: Machine Learning from Disaster」を使用する
https://www.kaggle.com/c/titanic/data
データ内容
PassengerId : ユニークID Survived : Survival (0 = 落命, 1 = 生存) << ★目的変数★ Pclass : 客席等級(1 = 1st, 2 = 2nd, 3 = 3rd) Name : 名前 Sex : 性別 Age : 年齢 SibSp : 同乗中の配偶者/兄弟の数 Parch : 同乗中の親/子供の数 Ticket : チケット番号 Fare : 料金 Cabin : 客室番号 Embarked : 出発港 (C = Cherbourg, Q = Queenstown, S = Southampton)
例1)決定木
import pandas as pd # 決定木 from sklearn.tree import DecisionTreeClassifier # 正解率を計算してくれる from sklearn.metrics import accuracy_score # 決定木のPDF化 import pydotplus from sklearn.tree import export_graphviz # データ入力 df_train = pd.read_csv("train.csv") # 欠損値処理 df_train['Fare'] = df_train['Fare'].fillna(df_train['Fare'].median()) df_train['Age'] = df_train['Age'].fillna(df_train['Age'].median()) df_train['Embarked'] = df_train['Embarked'].fillna('S') # カテゴリ変数の変換 df_train['Sex'] = df_train['Sex'].apply(lambda x: 1 if x == 'male' else 0) df_train['Embarked'] = df_train['Embarked'].map({'S': 0, 'C': 1, 'Q': 2}) df_train = df_train.drop(['Cabin', 'Name', 'PassengerId', 'Ticket'], axis=1) # 説明変数 x train_X = df_train.drop('Survived', axis=1) # 目的変数 y train_y = df_train.Survived # 決定木(Decision Tree) classifier = DecisionTreeClassifier(max_depth=3) classifier.fit(train_X, train_y) # モデル評価 df_test = pd.read_csv("test.csv") df_objection = pd.read_csv("gender_submission.csv") df_test = pd.merge(df_test, df_objection, on='PassengerId', how='inner') # 欠損値処理(削除) df_test = df_test.dropna(subset=['Fare']) df_test = df_test.dropna(subset=['Age']) df_test = df_test.dropna(subset=['Embarked']) # カテゴリ変数の変換 df_test['Sex'] = df_test['Sex'].apply(lambda x: 1 if x == 'male' else 0) df_test['Embarked'] = df_test['Embarked'].map({'S': 0, 'C': 1, 'Q': 2}) df_test = df_test.drop(['Cabin', 'Name', 'PassengerId', 'Ticket'], axis=1) # 説明変数 x test_X = df_test.drop('Survived', axis=1) # 目的変数 y test_y = df_test.Survived # 予想 predict_y = classifier.predict(test_X) # 評価 print(accuracy_score(test_y, predict_y)) # 決定木のPDF出力 dot_data = export_graphviz( classifier, feature_names='Titanic', filled=True, rounded=True, impurity=False) graph = pydotplus.graph_from_dot_data(dot_data) graph.write_pdf("viz_tree.pdf")
出力結果
0.9697885196374623 "viz_tree.pdf" もPDFで出力されている
例2)ランダムフォレスト
import pandas as pd # ランダムフォレスト from sklearn.ensemble import RandomForestClassifier # 正解率を計算してくれる from sklearn.metrics import accuracy_score # グラフ化 import numpy as np import matplotlib.pyplot as plt # データ入力 df_train = pd.read_csv("train.csv") # 欠損値処理 df_train['Fare'] = df_train['Fare'].fillna(df_train['Fare'].median()) df_train['Age'] = df_train['Age'].fillna(df_train['Age'].median()) df_train['Embarked'] = df_train['Embarked'].fillna('S') # カテゴリ変数の変換 df_train['Sex'] = df_train['Sex'].apply(lambda x: 1 if x == 'male' else 0) df_train['Embarked'] = df_train['Embarked'].map({'S': 0, 'C': 1, 'Q': 2}) df_train = df_train.drop(['Cabin', 'Name', 'PassengerId', 'Ticket'], axis=1) # 説明変数 x train_X = df_train.drop('Survived', axis=1) # 目的変数 y train_y = df_train.Survived # ランダムフォレスト(★ここが違う★) classifier = RandomForestClassifier(max_depth=7) classifier.fit(train_X, train_y) # モデル評価 df_test = pd.read_csv("test.csv") df_objection = pd.read_csv("gender_submission.csv") df_test = pd.merge(df_test, df_objection, on='PassengerId', how='inner') # 欠損値処理(削除) df_test = df_test.dropna(subset=['Fare']) df_test = df_test.dropna(subset=['Age']) df_test = df_test.dropna(subset=['Embarked']) # カテゴリ変数の変換 df_test['Sex'] = df_test['Sex'].apply(lambda x: 1 if x == 'male' else 0) df_test['Embarked'] = df_test['Embarked'].map({'S': 0, 'C': 1, 'Q': 2}) df_test = df_test.drop(['Cabin', 'Name', 'PassengerId', 'Ticket'], axis=1) # 説明変数 x test_X = df_test.drop('Survived', axis=1) # 目的変数 y test_y = df_test.Survived # 予想 predict_y = classifier.predict(test_X) # 評価 print(accuracy_score(test_y, predict_y)) # 変数の重要度 importances = classifier.feature_importances_ features = np.array(test_X.columns) # プロット indices = np.argsort(importances) plt.figure(figsize=(12, 12)) plt.barh(range(len(indices)), importances[indices], color='b', align='center') plt.yticks(range(len(indices)), features[indices]) plt.show()
出力結果
# 木の深さが5(max_depth=4)の場合 0.879154078549849 # max_depth=5の場合 0.8942598187311178 # max_depth=7の場合 0.8942598187311178 # グラフが表示
参考文献
https://www.randpy.tokyo/entry/decision_tree_theory
https://www.randpy.tokyo/entry/python_random_forest
https://future-chem.com/ames-decision-tree/
関連記事
scikit-learn ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2020/03/02/233902
scikit-learn ~ 基本編 ~
https://dk521123.hatenablog.com/entry/2020/03/08/113356
scikit-learn ~ 線形回帰 ~
https://dk521123.hatenablog.com/entry/2020/07/04/000000
scikit-learn ~ 重回帰/リッジ回帰 ~
https://dk521123.hatenablog.com/entry/2020/04/25/174503
パターン認識について
https://dk521123.hatenablog.com/entry/2013/12/16/225948
機械学習を勉強する際のデータセットについて
https://dk521123.hatenablog.com/entry/2020/03/28/131839