機械学習 で 株価分析 にチャレンジ Part4

machine-learning-part5

これまでの記事はこちら

machine-learning-part5
machine-learning-part5
machine-learning-part5

前回までで機械学習に使用する各指標を紹介し一番重要な目的変数とは何かを記事に書きました。今回は「特徴量選択」について書いていきます。

4.1 なぜ特徴量選択が重要なのか?

機械学習モデルを構築する際、「何を入力(特徴、feature)としてモデルに与えるか」が性能の鍵になります。特に金融データのように時系列・相関・ノイズが多い世界では、特徴量の数が多すぎたり、無関連なものが混ざっていたりすると以下のリスクがあります:

  • モデルが「ノイズ」を学習してしまい、過学習(training setでは高精度だが新規データでは低精度)に陥る
  • 入力変数のスケールや分布が異なり、学習が不安定・解釈が難しくなる
  • 計算量・モデルサイズが不要に大きくなり、実運用での速度・メモリの制約を圧迫
  • 「なぜこのモデルが動いているか」が見えにくく、運用・監査が難しくなる(説明性の低下)

そのため、特徴量選択(feature selection)は「多すぎる特徴量 → 本当に必要なものを絞る」という重要な工程です。ある意味で、モデルを使った運用における“捨てる技術”とも言えます。

ここから、この記事では「なぜTop-Kなのか」「どう重みづけ+重要度を取るのか」「実装上の流れ」「落とし穴と対策」などを丁寧に解説していきます。


4.2 特徴量選択の方法と分類

特徴量選択には、一般的に次の3つのアプローチがあります:

4.2.1 フィルター方式(Filter)

  • 特徴量と目的変数(ターゲット)との相関、分散、統計的検定などを使って事前に独立に選別する方式
  • 例:ピアソン相関係数で |r| > 0.3 の変数だけ残す、というような単純フィルタリング
  • メリット:モデルに依存せず高速・簡単
  • デメリット:相互作用(feature × feature)・モデルとの適合性を無視しがち

4.2.2 ラッパー方式(Wrapper)

  • 特徴量の組み合わせを変えながら、モデルの性能を基準に選択する方式(例:ステップワイズ選択、前進選択、後退選択)
  • メリット:モデルとの適合性が高く、精度を追いやすい
  • デメリット:計算量が非常に大きくなる(組み合わせ爆発)ため、実務で多数変数+時系列では難しい

4.2.3 埋め込み方式(Embedded)

  • モデル学習の中で特徴量の重要度(feature importance)を算出し、その重要度で選別する方式
  • 例:決定木系(RandomForest, LightGBM)ではfeature importanceが出せるので、その上位K個を選ぶことが自然
  • メリット:効率が高く、モデルとの整合性も取れるため実務でよく使われる
  • デメリット:モデルに特有の重要度であるため、モデルを変えると選ばれる特徴量も変わる

今回取り組む株価分析の設計では、Embedded方式を採用しており、具体的には「モデルの feature importance を出して、上位14個(TOP-K)を残す」流れです。次節以降では、この設計の意図・手順・実装を深掘りしていきます。

なお、今回使用している特徴量は下記の19個になります。このうち、上位14個の特徴量をピックアップしてきます。

名称定義意味・目的
ret_11日リターン(%変化率) $$\displaystyle ret_1 = \frac{Close_t – Close_{t-1}}{Close_{t-1}})$$短期の上昇・下落トレンドを捉える基本変化率。外れ値はクリップされている(上位2%、下位2%をカット)。
ret_1_lag1ret_1 の1日前の値1日前の変化方向を参照するラグ。トレンドの継続性を見る。
ret_1_lag5ret_1 の5日前の値5日前の変化方向を参照。短期反転を検出。
ret_hv過去20日のヒストリカルボラティリティ $$\displaystyle ret_hv = \sqrt{\frac{1}{20}\sum_{i=0}^{19}(ret_{t-i}-\bar{ret})^2}$$変動の大きさ。ボラが高いと予測リスクも上昇。

名称定義説明
close_sma_ratio_5 $$Close_t / SMA_5$$ 5日単純移動平均との比率。短期過熱感を表す。
close_sma_ratio_20$$Close_t / SMA_{20}$$20日平均との比率。中期トレンドの相対位置。
close_ema_ratio_5$$Close_t / EMA_5$$指数移動平均との比率。より即時的なトレンド把握。
bb_z$$\displaystyle BB_Z = \frac{Close_t – MA_{20}}{SD_{20}}$$ボリンジャーバンドのZスコア。±2σを超えると過熱/売られすぎ。
名称定義説明
rsi相対力指数(RSI, 14期間) $$\displaystyle RSI = 100 – \frac{100}{1 + \frac{avg(gain)}{avg(loss)}}$$買われすぎ・売られすぎの度合い。70以上=買われすぎ、30以下=売られすぎ。
atr_norm正規化ATR(14期間) $$\displaystyle ATR_norm = \frac{ATR_{14}}{Close_t}$$変動レンジ(高値-安値など)を終値で正規化。価格スケールの違いを吸収。
名称定義説明
vol_chg出来高の前日比変化率 $$\displaystyle vol_chg = \frac{Volume_t – Volume_{t-1}}{Volume_{t-1}}$$売買活動の勢いを示す。上昇局面での出来高増加=強気。
Volume_lag_11日前の出来高出来高の短期推移。
Volume_lag_55日前の出来高週単位の流動性傾向。
名称定義説明
dow_sin$$\displaystyle \sin\left(\frac{2\pi \times dayofweek}{5}\right)$$曜日周期(週5営業日)を円周上にマッピング。月曜と金曜の関係を連続的に表現。
dow_cos$$\displaystyle \cos\left(\frac{2\pi \times dayofweek}{5}\right)$$sinと組で曜日の位相を2次元的に表現。
名称定義意味・用途
Close_lag_1$$Close_{t-1}$$前日の終値。最も基本的な自己相関。
Close_lag_2$$Close_{t-2}$$2日前の終値。トレンド継続確認。
Close_lag_3$$Close_{t-3}$$3日前の終値。短期の反転傾向。
Close_lag_5$$Close_{t-5}$$5営業日前の終値。週単位の周期変動。

4.3 なぜ「Top-K」に絞るか? — 多変量かつ時系列特有の観点から

4.3.1 Kを固定する意図

「TOP-K」の“K”を固定(例:14)するという設計には、以下のような理由があります:

  • モデルの過剰な複雑化を防ぐ:変数が100個もあると、決定木系でも枝が深くなり「偶然のパターン」を拾いやすくなる
  • 運用維持のしやすさ:変数が多すぎると、データの欠損・仕様変更・特徴量計算コストが増える
  • 解釈性の確保:14個程度なら「この14個が効いてるんだな」とモデルの傾向を把握しやすい
  • 再現性・比較可能性:毎回変数数が変わると、モデルを再現・改善するたびに仕様が不安定になる
  • シグナルの安定性:多数変数を入れると“バラつきのある効き方”を拾いやすく、短期的なノイズに過剰反応してしまう

4.3.2 時系列データならではの注意点

  • 自己相関・ラグ構造が多いため、似たような説明変数(例:Close_lag_1Close_lag_2Close_lag_3)が強く相関してしまう。
    → “似た変数を複数入れる”とモデルが冗長になり、学習が不安定化。
  • 時間変化(レジームチェンジ)があるため、ある期間で有効だった特徴量が、別期間で使えない可能性がある。
    → 変数数を絞ると“普遍的に効きやすい変数”にフォーカスしやすい。
  • 過去データと最新データの重みづけを入れている設計なので、変数の重要度にも「時間の古さ」が反影響する可能性あり。
    → 重要度で古い構造(例:長期ホールド系)ばかり残ると「現在の相場感」に合わない。

このような観点から、「厳選+Top-K選択」は実務的には非常にバランスの良い設計と言えます。


4.4 実装:重要度Top-K選択の流れとコード対応

今回書いたコードにおける特徴量選択は以下のステップになっています。
select_topk_features関数を用いてtop_featsというリストに上位K個の特徴量を入れて返します。

# 重要度Top-K選択(H=MAIN_Hで一度だけ)
def select_topk_features(df, base_feature_cols, H, models, TOPK):
    df_tmp = df.copy()
    df_tmp['Target'] = make_target(df_tmp, H)
    df_train = df_tmp.dropna(subset=base_feature_cols + ['Target']).reset_index(drop=True)
    
    X = df_train[base_feature_cols].values
    y = df_train['Target'].values
    w, _ = make_weights(df_train)
    
    feats = base_feature_cols.copy()
    importances = None

    if models['lgbm_ok']:
        …(LightGBMでfeature_importance取得)…
    else:
        …(RandomForestでfeature_importances_取得)…

    imp_df = pd.DataFrame({'feature': feats, 'importance': importances})
    imp_df = imp_df.sort_values('importance', ascending=False)
    top_feats = imp_df['feature'].head(TOPK).tolist()
    return top_feats

4.4.1 各ステップの意味

  1. 対象地平 H=MAIN_H(例:H=5)で“ターゲット付きの学習データ”を準備
    → 期間ずれや欠損を除外して、モデル学習可能な形に整形
  2. 特徴量行列 X と目的変数 y を取り出し、重み w を生成(直近重視設計)
    → モデルは「最新に近いサンプルを重視」して学習
  3. モデル(LightGBM or RandomForest)を一度だけ学習して、feature importance を取得
  4. importance 順にソートして、上位 TOPK(例:14個)を「本採用特徴量」としてリスト化
  5. 以降、モデル本番学習・予測時にはこの「top_feats」だけを使う

4.4.2 数式表現

特徴量選択を数学的に書くと

$$\text{importance}_j= \text{FI}(X_{\cdot j}, y, w)\quad (j = 1,2,\dots,m)$$

$$\text{TopK\_set} = \{\, j \;\big|\; \text{importance}_j \text{ が上位 K 件} }$$
$$\text{Selected\_features} = \{ X_{\cdot j} \mid j \in \text{TopK\_set} }$$

ここで

  • $X_{j}$:特徴量 j の列ベクトル
  • FeatureImportance:モデルから得られる“その特徴量の貢献度”
  • w:サンプルごとの重み(直近22営業日×2+指数減衰)
  • “上位 K 件” は、$importancejimportance_{j}$​ を降順ソートして上から K 件取る操作

4.4.3 なぜ “H=MAIN_Hで一度だけ” 行うのか?

  • 複数地平(H∈{3,5,10})それぞれに特徴量選択すると、変数数や精度差が出て運用が煩雑になる
  • H=5(標準)を基準に選べば「中期の予測」を中心とした特徴量設計が可能
  • H変動の影響を抑え、共通化された特徴量セットを持つことで運用・モデル切り替えが容易

4.5 注意すべき落とし穴と対策


特徴量選択を行う際に、初心者が陥りやすいミスや注意点があります。以下に代表的なものと対策を整理します。

4.5.1 過学習リスク:特徴量だけで目的変数を説明し尽くしてしまう

  • 多数のラグ変数・出来高変数を無差別に入れると、「過去値の延長」になりやすく、未来の構造変化には弱くなる
  • 対策:特徴量選択後、検証(CV:Cross Validation)やフォワードテストを必ず行う。変数数を抑えておく(例:K=14)ことで過剰化を防ぐ。本題からそれてしまうため、検証部分は省かせてください。

4.5.2 相関重複:似た特徴量を複数含めてしまう

  • 例:ret_1_lag1ret_1_lag2ret_1_lag3などが強く相関していると、モデルが冗長になる
  • 対策:まず相関マトリクスを確認、似ている変数をまとめる orなるべく共線性を抑える。

4.5.3 時系列リーク:未来情報が混ざることに注意

  • 特徴量生成時に「今日から見た過去ラグ」以外の未来値を入れてはいけない
  • 選択された特徴量が、未来にしか計算できない値(例:翌日の出来高予測など)になっていないかをチェック。

4.5.4 時間変化(レジーム)への弱さ

  • 選ばれた特徴量が「過去のレジームでは効いたが今のレジームでは効かない」というケースがある
  • 対策:定期的な特徴量入れ替え・再選択を検討する。モデル更新のスケジュールを持つ。

4.5.5 “Kの選び方” が恣意的にならないように

  • Kを極端に小さくすると必要な情報を捨ててしまう。逆に大きくすると変数が多すぎて意味が薄くなる。
  • 対策:Kを変えて検証し、「特徴量数と精度のトレードオフ」を見る。たとえばK=10,14,20で比べてみる。

4.7 まとめ(この章の総括)

  • 特徴量選択は、入力変数を「使えるものだけに絞る」非常に重要なステップです。
  • 今回のモデル設計では、「Embedded方式 → feature importance による Top-K(14個)選択」を採用しており、時系列+トレンド+運用観点に非常に適した手法です。
  • 選択の意図(K固定、H=5基準など)、実装手順(モデル学習→重要度抽出→上位K選定)、落とし穴(相関、過学習、リーク、レジーム変化)を理解しておくことが、モデルの安定運用・精度維持に繋がります。
  • 次章では 第5章:RandomForestの直感とハイパーパラメータ に進み、モデルそのものの解説に入ります。
shota_py

メーカー勤務のエンジニアです。 自分の趣味である、「電気回路」、「ガジェット」「株式投資」、「Python」に関する記事をつらつらと書いています

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


ABOUT US
shota_py
メーカー勤務のエンジニアです。 自分の趣味である、「電気回路」、「ガジェット」「株式投資」、「Python」に関する記事をつらつらと書いています