web-dev-qa-db-ja.com

Keras LSTMは、時系列が押しつぶされてシフトすることを予測します

休暇中にKerasを実際に体験しようとしています。まず、株式データの時系列予測の教科書の例から始めようと思いました。したがって、私がやろうとしていることは、過去48時間分の平均価格変動(前回からのパーセント)を与えられ、次の1時間の平均価格変動が何であるかを予測します。

ただし、テストセット(またはトレーニングセット)に対して検証する場合、予測された系列の振幅は大きくずれており、常に正または常に負になるようにシフトされることがあります。つまり、0%の変化からシフトされます。この種のことには正しいと思います。

問題を示すために、次の最小限の例を考え出しました。

df = pandas.DataFrame.from_csv('test-data-01.csv', header=0)
df['pct'] = df.value.pct_change(periods=1)

seq_len=48
vals = df.pct.values[1:] # First pct change is NaN, skip it
sequences = []
for i in range(0, len(vals) - seq_len):
    sx = vals[i:i+seq_len].reshape(seq_len, 1)
    sy = vals[i+seq_len]
    sequences.append((sx, sy))

row = -24
trainSeqs = sequences[:row]
testSeqs = sequences[row:]

trainX = np.array([i[0] for i in trainSeqs])
trainy = np.array([i[1] for i in trainSeqs])

model = Sequential()
model.add(LSTM(25, batch_input_shape=(1, seq_len, 1)))
model.add(Dense(1))
model.compile(loss='mse', optimizer='adam')
model.fit(trainX, trainy, epochs=1, batch_size=1, verbose=1, shuffle=True)

pred = []
for s in trainSeqs:
    pred.append(model.predict(s[0].reshape(1, seq_len, 1)))
pred = np.array(pred).flatten()

plot(pred)
plot([i[1] for i in trainSeqs])
axis([2500, 2550,-0.03, 0.03])

ご覧のとおり、最後の48時間を選択し、次のステップをタプルに入れて1時間進め、手順を繰り返して、トレーニングとテストのシーケンスを作成します。モデルは非常に単純な1つのLSTMと1つの高密度レイヤーです。

個々の予測点のプロットがトレーニングシーケンスのプロット(結局、これはトレーニングされたものと同じセットです)とかなりうまく重なり、テストシーケンスの一種の一致を期待していました。ただし、トレーニングデータで次の結果が得られます。

  • オレンジ:真のデータ
  • 青:予測データ

enter image description here

何が起こっているのか考えはありますか?私は何かを誤解しましたか?

Update:シフトして押しつぶしたことの意味をわかりやすくするために、実際のデータに一致するようにシフトバックし、振幅に一致するように乗算して、予測値をプロットしました。

plot(pred*12-0.03)
plot([i[1] for i in trainSeqs])
axis([2500, 2550,-0.03, 0.03])

enter image description here

予測が実際のデータにうまく適合していることがわかるように、それは押しつぶされて何らかの形でオフセットされているだけであり、その理由はわかりません。

14
cdecker

私はあなたが過剰適合していると思います、データの次元は1であり、25単位のLSTMは、このような低次元のデータセットではかなり複雑に見えるためです。これが私が試すことのリストです:

  • LSTM次元を減らす。
  • 過剰適合と戦うために何らかの形の正則化を追加します。たとえば、 dropout が適切な選択である可能性があります。
  • より多くのエポックのためのトレーニングまたは学習率の変更。モデルは、適切なパラメーターを見つけるために、より多くのエポックまたはより大きな更新を必要とする場合があります。

UPDATE。コメントセクションで説明した内容を要約します。

明確にするために、最初のプロットは検証セットの予測系列を示していませんが、トレーニングセットの予測系列を示しています。したがって、私の最初の過剰適合の解釈は不正確である可能性があります。適切な質問は次のようになると思います。このような低次元のデータセットから将来の価格変動を予測することは実際に可能ですか?機械学習アルゴリズムは魔法ではありません。パターンが存在する場合にのみ、データ内のパターンを検出します。

過去の価格変更だけでは、将来の価格変更についてあまり情報がない場合は、次のようにします。

  • モデルは、価格の変化の平均(おそらく0前後)を予測することを学習します。これは、有益な機能がない場合に損失が最小になる値だからです。
  • タイムステップt + 1での価格変化は、タイムステップtでの価格変化とわずかに相関しているため、予測はわずかに「シフト」しているように見える場合があります(ただし、0に近いものを予測するのが最も安全な選択です)。それは確かに、私が専門家として観察できない唯一のパターンです(つまり、タイムステップt + 1の値がタイムステップtの値と似ている場合があります)。

タイムステップtとt + 1の値が一般により相関している場合、モデルはこの相関についてより自信を持っており、予測の振幅はより大きくなると思います。

8
rvinas
  1. エポックの数を増やします。 EarlyStoppingを使用して、過剰適合を回避できます。
  2. データはどのようにスケーリングされますか?時系列は、データの外れ値に非常に敏感です。たとえば、MinMax((0.1、0.9))を試してみてください。そうすれば、RobustScalerも良い選択です。
  3. 大量のデータが得られるまで、LSTM(seq_len)が本当に必要かどうかはわかりません。小さい寸法を試してみませんか?

これらすべてを試して、過剰適合を試みてください(実際のデータセットではmseはほぼゼロである必要があります)。次に、正則化を適用します。

更新

なぜあなたが通りかかったのか説明させてください

plot(pred*12-0.03)

ぴったり。

さて、LSTMレイヤーをブラックボックスと見なして忘れましょう。 25個の値が返されます-それだけです。この値はDenseレイヤーに進み、25値のベクトル関数に適用されます。

y = w * x + b

ここでwおよびb --NNによって定義され、最初はゼロに近いベクトル。 x --LSTMレイヤー後の値およびy --target(単一値)。

エポックが1つしかない場合、wとbはデータにまったく適合しません(実際にはほぼゼロです)。しかし、あなたが適用した場合はどうなりますか

plot(pred*12-0.03)

あなたの予測値に?あなたは(どういうわけか)ターゲット変数に適用しますwおよびb。これで、wbは単一の値であり、ベクトルではなく、単一の値に適用されます。しかし、それらは(ほぼ)高密度レイヤーと同じ働きをします。

したがって、エポックの数を増やして、より適切に適合させます。

UPDATE2ちなみに、データにいくつかの外れ値があります。 MAEを損失/精度の指標として使用することもできます。

2
avchauzov

今週も同じ問題があり、解決策を見つけました。私のために働いた唯一のことは、ここで説明されているウィンドウ正規化方法を使用することでした:

https://www.altumintelligence.com/articles/a/Time-Series-Prediction-Using-LSTM-Deep-Neural-Networks

(sp500予測に関する部分を確認してください)

良い一日を過ごしてください :)

0
Yanick Bourbeau