はじめに
本記事ではPythonでランダムフォレストの実装を行います。データはscikit-learnのサンプルで登録されているものを使用しています。
ランダムフォレストとは
ランダムフォレストは教師あり学習の1種です。複数の決定木を学習させて多数決をとる手法となっており、アンサンブル学習に含まれます。なお、分類・回帰の両方で使用することができます。
-
アンサンブル学習
複数のアルゴリズムを用いた学習 -
分類
データがどのグループに属するかを分類する手法 -
回帰
連続した数値を予測する手法
決定木とは
決定木とはデータを基に樹形図を作成し、予測を行うアルゴリズムです。
ランダムフォレストの流れ
ランダムフォレストは以下の流れで行います。
- 学習用データからn個のブートストラップデータを作成する(学習用データから重複を許してランダム抽出したデータをn個作成する)
- n個のブートストラップデータからn個の決定木を作成する
- n個の決定木からn個のモデルを作成する
- テストデータをn個のモデルに学習させて予測を行う
- n個の予測結果から、分類の場合は多数決、回帰の場合は平均値をとったものを最終結果とする
Python実行環境
python 3.10.4
Windows 11 Home
ランダムフォレスト(分類)の実装
乳がんのデータセット「load_breast_cancer」を使用してランダムフォレストの分類を行います。
使用するデータの構造
使用するデータの説明変数と目的変数は以下の通りとなっています。
-
説明変数
load_breast_cancer
のdataset.data
を使用します。
データの中身は以下で確認することができます。(乳房塊の微細針吸引物のデジタル画像に含まれる細胞核の特徴が入っている模様)説明変数に使うデータの確認import pandas as pd from sklearn.datasets import load_breast_cancer dataset = load_breast_cancer() # 1.データの行数、列数を確認する print(dataset.data.shape) # 2.データのカラムを確認する print(dataset.feature_names) # 3.データのサンプルを表示する sanple_df = pd.DataFrame(dataset.data, columns=dataset.feature_names) print(sanple_df.head(10))
実行結果「1.データの行数、列数を確認する」の実行結果(569行30列) (569, 30) 「2.データのカラムを確認する」の実行結果 ['mean radius' 'mean texture' 'mean perimeter' 'mean area' 'mean smoothness' 'mean compactness' 'mean concavity' 'mean concave points' 'mean symmetry' 'mean fractal dimension' 'radius error' 'texture error' 'perimeter error' 'area error' 'smoothness error' 'compactness error' 'concavity error' 'concave points error' 'symmetry error' 'fractal dimension error' 'worst radius' 'worst texture' 'worst perimeter' 'worst area' 'worst smoothness' 'worst compactness' 'worst concavity' 'worst concave points' 'worst symmetry' 'worst fractal dimension'] 「3.データのサンプルを表示する」の実行結果 mean radius mean texture ... worst symmetry worst fractal dimension 0 17.99 10.38 ... 0.4601 0.11890 1 20.57 17.77 ... 0.2750 0.08902 2 19.69 21.25 ... 0.3613 0.08758 3 11.42 20.38 ... 0.6638 0.17300 4 20.29 14.34 ... 0.2364 0.07678 5 12.45 15.70 ... 0.3985 0.12440 6 18.25 19.98 ... 0.3063 0.08368 7 13.71 20.83 ... 0.3196 0.11510 8 13.00 21.82 ... 0.4378 0.10720 9 12.46 24.04 ... 0.4366 0.20750
-
目的変数
load_breast_cancer
のdataset.target
を使用します。
データの中身は以下で確認することができます。(悪性か良性かの情報が入っている)目的変数に使うデータの確認import pandas as pd from sklearn.datasets import load_breast_cancer dataset = load_breast_cancer() # 1.データの行数、列数を確認する print(dataset.target.shape) # 2.データの対応を確認する print(dataset.target_names) # 3.データのサンプルを表示する(先頭10件は全て0だったため、末尾を表示) sanple_df = pd.DataFrame(dataset.target, columns=['乳がん診断結果']) print(sanple_df.tail(10))
実行結果「1.目的変数データの行数、列数を確認する」の実行結果(569行1列) (569,) 「2.目的変数データの対応を確認する」の実行結果(0が悪性、1が良性) ['malignant' 'benign'] 「3.目的変数データのサンプルを表示する」の実行結果 乳がん診断結果 559 1 560 1 561 1 562 0 563 0 564 0 565 0 566 0 567 0 568 1
作成プログラム
Pythonでランダムフォレストの分類を実装したプログラムは以下になります。
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import pandas as pd
def main():
dataset = load_breast_cancer() #乳がんのデータセットを読み込む
x_train, x_test, y_train, y_test = split_data_set(dataset)
calculate_accuracy(dataset, x_train, x_test, y_train, y_test)
#乳がんのデータを学習用とテスト用に分割する
def split_data_set(dataset):
x = dataset.data #説明変数
y = dataset.target #目的変数
#学習用データ(train)を8割、テストデータ(test)を2割に分ける
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, stratify = y)
return x_train, x_test, y_train, y_test
#ランダムフォレストを使用し、テストデータの正解率を算出する
def calculate_accuracy(dataset, x_train, x_test, y_train, y_test):
#ランダムフォレスト(分類)を実行しモデルを作る
model_rf = RandomForestClassifier(max_depth=3)
model_rf.fit(x_train, y_train)
#どの説明変数が重要だったかを出力する
output_feature_importances(model_rf, dataset)
#テストデータにモデルを適用し、悪性か良性かを予測する
pred = model_rf.predict(x_test)
#正解データと予測データを比較して正解率を算出する
score = accuracy_score(y_test, pred)
print("テストデータの正解率:" + str(score))
#どの説明変数が重要だったかを出力する
def output_feature_importances(model_rf, dataset):
df = pd.DataFrame({"説明変数":dataset.feature_names, "重要度":model_rf.feature_importances_})
df = df.sort_values("重要度", ascending=False)
print(df)
if __name__ == '__main__':
main()
実行結果
-
テストデータの正解率
テストデータの正解率:0.956140350877193
約96%は正解(悪性のデータを正しく悪性、良性のデータを正しく良性と算出)となりました。よって今回作成したモデルの精度は高いと言えます。
-
どの説明変数が重要だったかを出力した結果
説明変数 重要度 worst perimeter 0.194244 worst radius 0.123658 worst concave points 0.121415 mean concave points 0.100320 worst area 0.091693 以降説明変数が続く 以降重要度が続く worst perimeter
(細胞核の外周の長さの最悪値のようです)が悪性、良性の予測に最も影響していることが分かります。
※train_test_split
で作られる学習用データとテストデータは毎回変わるため、テストデータの正解率、説明変数の重要度も毎回変化します
ランダムフォレスト(回帰)の実装
カリフォルニア住宅価格のデータセット「fetch_california_housing」を使用してランダムフォレストの回帰を行います。
使用するデータの構造
使用するデータの説明変数と目的変数は以下の通りとなっています。
-
説明変数
fetch_california_housing
のdataset.data
を使用します。
データの中身は以下で確認することができます。(地域をブロックごとに分けて算出した情報が入っている)説明変数に使うデータの確認import pandas as pd from sklearn.datasets import fetch_california_housing dataset = fetch_california_housing() # 1.データの行数、列数を確認する print(dataset.data.shape) # 2.データのカラムを確認する print(dataset.feature_names) # 3.データのサンプルを表示する sanple_df = pd.DataFrame(dataset.data, columns=dataset.feature_names) print(sanple_df.head(10))
実行結果「1.データの行数、列数を確認する」の実行結果(20640行8列) (20640, 8) 「2.データのカラムを確認する」の実行結果 ['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population', 'AveOccup', 'Latitude', 'Longitude'] 「3.データのサンプルを表示する」の実行結果 MedInc HouseAge AveRooms AveBedrms Population AveOccup Latitude Longitude 0 8.3252 41.0 6.984127 1.023810 322.0 2.555556 37.88 -122.23 1 8.3014 21.0 6.238137 0.971880 2401.0 2.109842 37.86 -122.22 2 7.2574 52.0 8.288136 1.073446 496.0 2.802260 37.85 -122.24 3 5.6431 52.0 5.817352 1.073059 558.0 2.547945 37.85 -122.25 4 3.8462 52.0 6.281853 1.081081 565.0 2.181467 37.85 -122.25 5 4.0368 52.0 4.761658 1.103627 413.0 2.139896 37.85 -122.25 6 3.6591 52.0 4.931907 0.951362 1094.0 2.128405 37.84 -122.25 7 3.1200 52.0 4.797527 1.061824 1157.0 1.788253 37.84 -122.25 8 2.0804 42.0 4.294118 1.117647 1206.0 2.026891 37.84 -122.26 9 3.6912 52.0 4.970588 0.990196 1551.0 2.172269 37.84 -122.25
-
目的変数
fetch_california_housing
のdataset.target
を使用します。
データの中身は以下で確認することができます。(住宅価格の中央値が入っている)目的変数に使うデータの確認import pandas as pd from sklearn.datasets import fetch_california_housing dataset = fetch_california_housing() # 1.データの行数、列数を確認する print(dataset.target.shape) # 2.データの対応を確認する print(dataset.target_names) # 3.データのサンプルを表示する sanple_df = pd.DataFrame(dataset.target, columns=['住宅価格の中央値']) print(sanple_df.head(10))
実行結果「1.データの行数、列数を確認する」の実行結果(20640行1列) (20640,) 「2.データの対応を確認する」の実行結果 ['MedHouseVal'] 「3.データのサンプルを表示する」の実行結果 住宅価格の中央値 0 4.526 1 3.585 2 3.521 3 3.413 4 3.422 5 2.697 6 2.992 7 2.414 8 2.267 9 2.611
作成プログラム
Pythonでランダムフォレストの回帰を実装したプログラムは以下になります。
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error
import pandas as pd
def main():
dataset = fetch_california_housing() #カリフォルニア住宅価格のデータセットを読み込む
x_train, x_test, y_train, y_test = split_data_set(dataset)
check_model_accuracy(dataset, x_train, x_test, y_train, y_test)
#カリフォルニア住宅価格のデータを学習用とテスト用に分割する
def split_data_set(dataset):
x = dataset.data #説明変数
y = dataset.target #目的変数
#学習用データ(train)を8割、テストデータ(test)を2割に分ける
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)
return x_train, x_test, y_train, y_test
#ランダムフォレストで作成したモデルの精度を確認する
def check_model_accuracy(dataset, x_train, x_test, y_train, y_test):
#ランダムフォレストを実行しモデルを作る
model_rf = RandomForestRegressor(max_depth=8)
model_rf.fit(x_train, y_train)
#どの説明変数が重要だったかを出力する
output_feature_importances(model_rf, dataset)
#テストデータにモデルを適用し、住宅価格を予測する
pred = model_rf.predict(x_test)
#正解データと予測データを比較(平均絶対誤差)してモデルの精度を確認する
score = mean_absolute_error(y_test, pred)
print("平均絶対誤差:" + str(score))
#どの説明変数が重要だったかを出力する
def output_feature_importances(model_rf, dataset):
df = pd.DataFrame({"説明変数":dataset.feature_names, "重要度":model_rf.feature_importances_})
df = df.sort_values("重要度", ascending=False)
print(df)
if __name__ == '__main__':
main()
実行結果
-
平均絶対誤差
平均絶対誤差:0.3892159206320577
平均絶対誤差は約0.39となりました。 平均絶対誤差は0に近いほど正解データと予測データの誤差が小さくモデルの精度が高いと言えます。そのため今回作成したモデルの精度は高いと言えそうです。
-
どの説明変数が重要だったかを出力した結果
説明変数 重要度 MedInc 0.644024 AveOccup 0.138845 Latitude 0.065285 Longitude 0.061197 HouseAge 0.044450 以降説明変数が続く 以降重要度が続く MedInc
(ブロックの所得中央値)が住宅価格の予測に最も影響していることが分かります。
※train_test_split
で作られる学習用データとテストデータは毎回変わるため、平均絶対誤差、説明変数の重要度も毎回変化します
終わりに
Pythonでランダムフォレストを実装しました。
今回はパラメータの設定、評価指標の選択までは考慮しなかったため、別途勉強をし、モデルの精度を高めたいと思いました。
参考
この記事は以下の動画・記事を参考にして執筆しました。
・Pythonでランダムフォレストを作ってみよう【Python機械学習#8】
・Pythonによるあたらしいデータ分析の教科書(寺田 学,辻 真吾,鈴木 たかのり,福島 真太朗)
・ランダムフォレストとは?基本の仕組みから活用事例までまとめて解説