ファイナンス機械学習:ファイナンスにおける交差検証法 オーバーフィッティングとなる理由

 機械学習のモデルの評価においては、訓練データとは交わらないデータでテストすることが重要である。交差検証法は訓練データセットを訓練データを検証データに分け、検証データ結果からパラメータを調整し、最後に未知のテストデータでの評価を可能にする方法である。
 k-fold交差検証法(k-fold CV )は、訓練データセットをk個に分割し、データセット$${i}$$を検証データとして、残りの$${k-1}$$データセットを訓練データとする。
 しかし、観測データがIIDに従わないファイナンスではこのk-foldCVは、うまく機能せず、時系列データからなるテストデータで同じデータが複数回現れることで、バイアスが高くなる。
 これを避けるには、訓練データセットの結果$${Y_i}$$と$${Y_j}$$が決定される観測値/訓練データ$${X}$$がダブっている場合、どちらかを除外するか、もしくは観測値が$${Y_j}$$と重複する$${Y_i}$$を除外する(独自性)、冗長なサンプリングを抑制する、バイアスが低くなるように分類器を早期終了させる方法がある。
 独自性を使ったサンプリングの方法(逐次ブートストラップ、max_sample=avgU)と、分類器の早期終了は、前節で扱った。よって、ここでは、訓練データとテストデータ間の情報のリーケージを減らすパージングと、データ使用に禁止(猶予)期間を設けるバージングの二つの方法を扱う。

訓練データのパージング

トリプルバリア法において、ラベル$${Y_j}$$は、$${[t_{j,0},t_{j,1}]}$$区間の価格のリターンの符号$${sgn[r_{t_{j,0},t_{j.1}}]}$$で与えられている。よって、$${Y_i}$$が与えられる区間が、以下の条件のどれか一つを満たしている判断された場合、同じ情報を共有していることから取り除かれる。

  • $${t_{j,0}\le t_{i,0} \le t_{j,1}}$$

  • $${t_{j,0}\le t_{i,1} \le t_{j,1}}$$

  • $${t_{j,0}\le t_{i,0} \le t_{j,1} \le t_{i,1}}$$

これは、スニペット7.1で実装されている。

def getTrainTimes(t1, testTimes):
    
    trn = t1.copy(deep=True)
    for i, j in testTimes.iteritems():
        df0 = train[(i <= train.index) & (train.index <= j)].index    # train starts within test
        df1 = train[(i <= train) & (train <= i)].index                # train ends within test
        df2 = train[(train.index <= i) & (j <= train)].index          # train envelops test
        trn = trn.drop(df0.union(df1).union(df2))
    return trn

エンバーゴ(猶予期間)

パージングによって全てのリーケージを防ぐことができない場合、エンバーゴを課す。
$${t_{i,1}\let_{j,0}}$$である訓練ラベル$${Y_i=f\bigl[[t_{i,0},t_{i,1}]\bigl]}$$は、$${Y_j}$$のテストデータが始まる前に終わっているから、このようなテストデータより前にある訓練データにはエンバーゴは作用しない。テストデータの直後、$${t_{j,1} \le t_{i,0} \le t_{j, 1}+h}$$内に入っている訓練ラベルがエンバーゴの対称である。
エンバーゴの期間$${h}$$は、$${h \simeq 0.001 T}$$(Tは全訓練期間)で十分であり、これより大きくしてもパフォーマンスには変わらない。
 この実装はスニペット7.2で与えられている

def getEmbargoTimes(times, pctEmbargo= 0.0):
    
    step = int(times.shape[0] * pctEmbargo)
    if step == 0:
        mbrg = pd.Series(times, index=times)
    else:
        mbrg = pd.Series(times[step:], index=times[:-step])
        mbrg = mbrg.append(pd.Series(times[-1], index=times[-step:]))
    return mbrg
## Examples including Embargo before Purging

# testtimes=pd.Series(mbrg[dt1],index=[dt0]) # include embargo before purge
# trainTimes=getTrainTimes(t1,testTimes)
# testTimes=t1.loc[dt0:dt1].index

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