TimeSeriesSplitで時系列交差検証する:gapを入れた12行の分割を読む

時間順に増えるデータを評価するなら、「過去から学び、その後のデータで確かめる」分割が必要です。TimeSeriesSplitはそのための行番号を返す道具です。今回は架空の機器センサー12時間分を使い、学習行・評価行・その間に空ける行を見える形にします。

予測時点で分からないデータを先に除く

毎時の始めに「次の1時間で機器に異常があるか」を予測する教材を考えます。同じ行の「1時間終了時の最高温度」は予測時点では分かりません。行を時間順に分けても、この列を使えば未来の情報が混ざります。分割を設定する前に、各列の記録時刻と利用可能時刻を書き出してください。

教材の列予測時点に使えるか理由
直前1時間の平均温度使える候補直前の集計が確定し取得できた時刻を確認する
次の1時間の最高温度使えない予測対象の時間が終わってから確定する
異常判定ラベル説明変数に使わない予測したい正解そのもの

12行を3回に分け、1行のgapを設ける

行番号0〜11を時刻順に並べます。評価行を毎回2行、評価直前の1行を学習から外す教材です。これは実際の待機時間の推奨値ではありません。ラベルの確定に時間がかかる問題では、情報の利用可能時刻に合わせて間隔を決めます。

from sklearn.model_selection import TimeSeriesSplit

splitter = TimeSeriesSplit(n_splits=3, test_size=2, gap=1)
for train, test in splitter.split(range(12)):
    print(train.tolist(), test.tolist())
分割学習直前の除外行評価
10〜456、7
20〜678、9
30〜8910、11

前の評価行が後の学習に入るのは、時間が進んだ後の学習を模擬するためです。最初の時点のモデルで全期間を評価する設計とは異なります。比較したい運用を先に決めましょう。

gapは行数であり、時間単位ではない

公式APIのgapは、評価直前に学習から除くサンプル数です。不規則な間隔のデータでgap=1にしても、1時間空けたことにはなりません。今回のような等間隔の教材と、イベントごとに記録される実データを区別してください。評価期間の長さをそろえて比較する前提も確認します。[出典1]

また、gapを入れればすべてのリークが防げるわけではありません。複数日にまたがる集計、重複した利用者、終了後に修正された列などは、別に点検します。

前処理も各分割の学習側で決める

全12行で平均を計算して欠損を埋め、その後で上の分割をすると、評価側の値が学習に影響します。前処理を学習行でfitし、同じ変換を評価行へ適用します。Pipelineなどで学習と変換の順を管理できます。[出典2]

分割表で確かめるチェック項目

個別適用や説明の拡張時に確認する事項:最初の提出物は性能の高い数値より、この分割表です。どの時点で何を知っていたかを説明できる形にすると、評価の意味を第三者が確認できます。上のコードは分割を表示する例で、機器データでの学習や性能測定を実施した結果ではありません。

出典

  1. scikit-learn: TimeSeriesSplit。
  2. scikit-learn: Pipeline。