見出し画像

スギ花粉飛散量のデータ分析@機械学習編

それでは、実際に予測モデルを作成していきます。
復習として、前回作成したデータフレームを以下に記します。

ランダムフォレスト

ランダムフォレストは、精度の高くない弱学習器である決定木をたくさん作って、より精度の高い強学習器を作成するアンサンブル学習の一つです。材料開発の機械学習のマテリアルズインフォマティクスでよく使われます。

岩崎 悠真 著 マテリアルズインフォマティクス 参照 

以下のコードで予測しました。

import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score

# 説明変数1と目的変数1
X1 = merged_df9[["平均気温(℃)_t", "東京23区_lag1", "東京23区_rol3", "週番号", "東京23区_lag2", "東京23区_lag3"]]
y1 = merged_df9['東京23区']

# 説明変数2と目的変数2
X2 = merged_df9[["平均気温(℃)_t", "東京23区外_lag1", "東京23区外_rol3", "週番号", "東京23区外_lag2", "東京23区外_lag3"]]
y2 = merged_df9['東京23区外']

# 訓練データとテストデータに分割
X1_train, X1_test, y1_train, y1_test = train_test_split(X1, y1, test_size=0.2, random_state=42)
X2_train, X2_test, y2_train, y2_test = train_test_split(X2, y2, test_size=0.2, random_state=42)

# ランダムフォレスト回帰モデルのインスタンスを作成
regressor1 = RandomForestRegressor(n_estimators=100, random_state=42)
regressor2 = RandomForestRegressor(n_estimators=100, random_state=42)

# モデルの訓練
regressor1.fit(X1_train, y1_train)
regressor2.fit(X2_train, y2_train)

# 訓練データでの予測
y1_train_pred = regressor1.predict(X1_train)
y2_train_pred = regressor2.predict(X2_train)

# テストデータでの予測
y1_test_pred = regressor1.predict(X1_test)
y2_test_pred = regressor2.predict(X2_test)

# 評価
print("東京23区の予測モデル")
print("訓練データの平均二乗誤差(東京23区): ", mean_squared_error(y1_train, y1_train_pred))
print("テストデータの平均二乗誤差(東京23区): ", mean_squared_error(y1_test, y1_test_pred))
print("訓練データのR^2スコア(東京23区): ", r2_score(y1_train, y1_train_pred))
print("テストデータのR^2スコア(東京23区): ", r2_score(y1_test, y1_test_pred))
print()
print("東京23区外の予測モデル")
print("訓練データの平均二乗誤差(東京23区外): ", mean_squared_error(y2_train, y2_train_pred))
print("テストデータの平均二乗誤差(東京23区外): ", mean_squared_error(y2_test, y2_test_pred))
print("訓練データのR^2スコア(東京23区外): ", r2_score(y2_train, y2_train_pred))
print("テストデータのR^2スコア(東京23区外): ", r2_score(y2_test, y2_test_pred))

結果ですが

訓練データとテストデータの差が大きくなってしまいました。これは、モデルが過学習している可能性が高いらしいです。

ということで、モデルの複雑さを減らしてみました。

# ランダムフォレスト回帰モデルのインスタンスを作成
regressor1 = RandomForestRegressor(n_estimators=100, max_depth=3, random_state=42)
regressor2 = RandomForestRegressor(n_estimators=100, max_depth=3, random_state=42)

ランダムフォレストの木の深さを減らしてみました。

すると………

テストデータのR^2が少し上がり、訓練データとテストデータの差が少なくなっていることがわかります。
モデルの複雑さを減らすことで、過学習が抑えられていることが伺えます!

非線形SVMモデル

今回のデータは非線形ですので、非線形のSVM(サポートベクターマシン)を用います。

線形SVMがデータを線形の境界で分類するのに対して、非線形SVMは、より複雑な非線形の境界を使ってデータを分類します。
非線形SVMは、カーネルトリックと呼ばれる手法を用いて、元のデータを高次元の特徴空間にマッピングします。
この高次元空間で線形分類器を適用することで、元のデータ空間において非線形な境界を得ることができます。

と言っても何が何だかだと思いますので、習うより慣れろです(アイデミーさん、生徒失格でごめんなさいw)。
以下にコードを書きます。

import numpy as np
import pandas as pd
from sklearn.svm import SVR
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score

# 説明変数1と目的変数1
X1 = merged_df9[["平均気温(℃)_t", "東京23区_lag1", "東京23区_rol3", "週番号", "東京23区_lag2", "東京23区_lag3"]]
y1 = merged_df9['東京23区']

# 説明変数2と目的変数2
X2 = merged_df9[["平均気温(℃)_t", "東京23区外_lag1", "東京23区外_rol3", "週番号", "東京23区外_lag2", "東京23区外_lag3"]]
y2 = merged_df9['東京23区外']

# 訓練データとテストデータに分割
X1_train, X1_test, y1_train, y1_test = train_test_split(X1, y1, test_size=0.2, random_state=42)
X2_train, X2_test, y2_train, y2_test = train_test_split(X2, y2, test_size=0.2, random_state=42)

# SVM回帰モデルのインスタンスを作成
regressor1 = SVR(kernel='rbf', C=1, gamma='scale')
regressor2 = SVR(kernel='rbf', C=1, gamma='scale')

# モデルの訓練
regressor1.fit(X1_train, y1_train)
regressor2.fit(X2_train, y2_train)

# 訓練データでの予測
y1_train_pred = regressor1.predict(X1_train)
y2_train_pred = regressor2.predict(X2_train)

# テストデータでの予測
y1_test_pred = regressor1.predict(X1_test)
y2_test_pred = regressor2.predict(X2_test)

# 評価
print("東京23区の予測モデル")
print("訓練データの平均二乗誤差(東京23区): ", mean_squared_error(y1_train, y1_train_pred))
print("テストデータの平均二乗誤差(東京23区): ", mean_squared_error(y1_test, y1_test_pred))
print("訓練データのR^2スコア(東京23区): ", r2_score(y1_train, y1_train_pred))
print("テストデータのR^2スコア(東京23区): ", r2_score(y1_test, y1_test_pred))
print()
print("東京23区外の予測モデル")
print("訓練データの平均二乗誤差(東京23区外): ", mean_squared_error(y2_train, y2_train_pred))
print("テストデータの平均二乗誤差(東京23区外): ", mean_squared_error(y2_test, y2_test_pred))
print("訓練データのR^2スコア(東京23区外): ", r2_score(y2_train, y2_train_pred))
print("テストデータのR^2スコア(東京23区外): ", r2_score(y2_test, y2_test_pred))

結果ですが

いや、低いなおい!ww

ニューラルネットワーク

これはよく画像認識等で使われるモデルで、深層学習とも呼ばれます。
予測性能が高いので、使用してみました。
以下はtenserflowのklasを用いたシンプルなコードとなります。

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

# 説明変数1と目的変数1
X1 = merged_df9[["平均気温(℃)_t", "東京23区_lag1", "東京23区_rol3", "週番号", "東京23区_lag2", "東京23区_lag3"]]
y1 = merged_df9['東京23区']

# 説明変数2と目的変数2
X2 = merged_df9[["平均気温(℃)_t", "東京23区外_lag1", "東京23区外_rol3", "週番号", "東京23区外_lag2", "東京23区外_lag3"]]
y2 = merged_df9['東京23区外']

# 訓練データとテストデータに分割
X1_train, X1_test, y1_train, y1_test = train_test_split(X1, y1, test_size=0.2, random_state=42)
X2_train, X2_test, y2_train, y2_test = train_test_split(X2, y2, test_size=0.2, random_state=42)

# ニューラルネットワークモデルの作成
def create_nn_model(input_dim):
    model = Sequential()
    model.add(Dense(32, input_dim=input_dim, activation='relu'))
    model.add(Dense(16, activation='relu'))
    model.add(Dense(1, activation='linear'))
    model.compile(loss='mean_squared_error', optimizer='adam')
    return model

# モデルの訓練
nn_model1 = create_nn_model(X1_train.shape[1])
nn_model1.fit(X1_train, y1_train, epochs=50, batch_size=8, verbose=0)

nn_model2 = create_nn_model(X2_train.shape[1])
nn_model2.fit(X2_train, y2_train, epochs=50, batch_size=8, verbose=0)

# 訓練データでの予測
y1_train_pred = nn_model1.predict(X1_train)
y2_train_pred = nn_model2.predict(X2_train)

# テストデータでの予測
y1_test_pred = nn_model1.predict(X1_test)
y2_test_pred = nn_model2.predict(X2_test)

# 評価
print("東京23区の予測モデル")
print("訓練データの平均二乗誤差(東京23区): ", mean_squared_error(y1_train, y1_train_pred))
print("テストデータの平均二乗誤差(東京23区): ", mean_squared_error(y1_test, y1_test_pred))
print("訓練データのR^2スコア(東京23区): ", r2_score(y1_train, y1_train_pred))
print("テストデータのR^2スコア(東京23区): ", r2_score(y1_test, y1_test_pred))
print()
print("東京23区外の予測モデル")
print("訓練データの平均二乗誤差(東京23区外): ", mean_squared_error(y2_train, y2_train_pred))
print("テストデータの平均二乗誤差(東京23区外): ", mean_squared_error(y2_test, y2_test_pred))
print("訓練データのR^2スコア(東京23区外): ", r2_score(y2_train, y2_train_pred))
print("テストデータのR^2スコア(東京23区外): ", r2_score(y2_test, y2_test_pred))

おぉ!やはり精度が高い!が、まだランダムフォレストと変わらん。。。。

ってことで、データの標準化エポック数などを変更し、以下のコードで再度試みました!

from keras.models import Sequential
from keras.layers import Dense
from keras.wrappers.scikit_learn import KerasRegressor
from sklearn.preprocessing import StandardScaler

def create_nn_model():
    model = Sequential()
    model.add(Dense(50, input_dim=6, activation='relu'))  # 変更: ノード数を50に設定
    model.add(Dense(30, activation='relu'))  # 変更: 隠れ層を追加し、ノード数を30に設定
    model.add(Dense(1, activation='linear'))
    model.compile(loss='mean_squared_error', optimizer='adam')
    return model

# データの標準化
scaler1 = StandardScaler()
scaler2 = StandardScaler()
X1_train_scaled = scaler1.fit_transform(X1_train)
X1_test_scaled = scaler1.transform(X1_test)
X2_train_scaled = scaler2.fit_transform(X2_train)
X2_test_scaled = scaler2.transform(X2_test)

# ニューラルネットワークモデルのインスタンスを作成
nn_regressor1 = KerasRegressor(build_fn=create_nn_model, epochs=100, batch_size=10, verbose=0)
nn_regressor2 = KerasRegressor(build_fn=create_nn_model, epochs=100, batch_size=10, verbose=0)

# モデルの訓練
nn_regressor1.fit(X1_train_scaled, y1_train)
nn_regressor2.fit(X2_train_scaled, y2_train)

# 訓練データでの予測
y1_train_pred = nn_regressor1.predict(X1_train_scaled)
y2_train_pred = nn_regressor2.predict(X2_train_scaled)

# テストデータでの予測
y1_test_pred = nn_regressor1.predict(X1_test_scaled)
y2_test_pred = nn_regressor2.predict(X2_test_scaled)


# 評価
print("東京23区の予測モデル")
print("訓練データの平均二乗誤差(東京23区): ", mean_squared_error(y1_train, y1_train_pred))
print("テストデータの平均二乗誤差(東京23区): ", mean_squared_error(y1_test, y1_test_pred))
print("訓練データのR^2スコア(東京23区): ", r2_score(y1_train, y1_train_pred))
print("テストデータのR^2スコア(東京23区): ", r2_score(y1_test, y1_test_pred))
print()
print("東京23区外の予測モデル")
print("訓練データの平均二乗誤差(東京23区外): ", mean_squared_error(y2_train, y2_train_pred))
print("テストデータの平均二乗誤差(東京23区外): ", mean_squared_error(y2_test, y2_test_pred))
print("訓練データのR^2スコア(東京23区外): ", r2_score(y2_train, y2_train_pred))
print("テストデータのR^2スコア(東京23区外): ", r2_score(y2_test, y2_test_pred))

これが今までのベスト数値です。
これ以上上げるとなるとさらなる特徴量エンジニアリングが必要ですね。

ってことで、次回はさらに特徴量を追加して試みます!

この記事が気に入ったらサポートをしてみませんか?