見出し画像

時系列予測での特徴量選択

質問箱にあったので。時系列予測での特徴量選択手法を紹介します。独自手法。教師なしです(目的変数を見ないで特徴量のみ見る)

方法

print('dfは特徴量が入ったDataFrame')
print('featuresは使う特徴量カラム名配列')

print('重要度表示。重要度が高いものは汎化性能に悪影響を与える可能性がある')
model = lgb.LGBMRegressor(n_jobs=-1, random_state=1)
model.fit(df[features], np.arange(df.shape[0]))
lgbm_adv_importance = model.feature_importances_
feature_imp = pd.DataFrame(sorted(zip(model.feature_importances_, features)), columns=['Value','Feature'])
plt.figure(figsize=(20, 40))
sns.barplot(x="Value", y="Feature", data=feature_imp.sort_values(by="Value", ascending=False))
plt.title('LightGBM Features adv val (avg over folds)')
plt.tight_layout()
plt.show()

print('スコア計算。スコアが高いと汎化性能が悪い可能性ある')
cv = KFold(n_splits=2, shuffle=True, random_state=0)
scores = cross_val_score(model, df[features], np.arange(df.shape[0]), scoring='r2', cv=cv)
print('scores', scores)
print('score mean, std', np.mean(scores), np.std(scores))

時系列予測の難しいところ

時系列予測は本番データと同じ分布になるような学習データを用意しづらいです。分布が異なっていたら汎化性能が出ません。

Adversarial Validation

Adversarial ValidationはKaggleのテクニックです。用意された学習データとテストデータの特徴量の分布が異なる場合に、テストデータに近い学習データのみを選んで学習すると性能上がるというものです。実際の問題であれば、学習データとテストデータの分布を近づけるのが良さそうですが、kaggleのテクニックとして。

これを、時系列予測の本番データと学習データの分布が異なってしまう問題に応用できないか考えました。

特徴量分布が時刻に依存しなければ良い

Adversarial Validationでは特徴量からtrainデータかtestデータかを識別できないことが重要でしたが、時系列予測では特徴量から時刻を識別できないことに置き換えてみました。時刻を識別できないということは、特徴量から過去のデータか未来のデータかがわからないということです。そうしておけば、未来のデータでも汎化性能出そうです。

整理すると以下の感じです。2, 3もあり得ると思います。

1. train/test + サンプル選択 <- Adversarial Validation

2. train/test + 特徴量選択

3. 時刻 + サンプル選択

4. 時刻 + 特徴量選択 <- 本手法

実装

コードを見てください。np.arange(df.shape[0])で時刻を予測して、r2で予測精度を評価しています。r2が大きいと特徴量分布が時刻に依存するので、汎化性能が悪化する可能性があります。NNなどlgbm以外のモデルを使っても良いと思います。

ライセンス

記事中のコードのライセンス: CC0

今後

kaggleの時系列予測系のコンペとかで使ってくれたら嬉しいです。まだこの手法についてよく理解できていないので。kaggle界隈で使われれば理解が進みそう。

ディープラーニングとかで時刻に依存しない特徴量を自動で作るみたいな方向性もありそう。