LSTM:時系列を予測するときに非定常性を処理する方法


8

LSTMを使用して、時系列の1ステップ先の予測を行いたい。アルゴリズムを理解するために、私はおもちゃの例を作成しました:単純な自己相関プロセス。

def my_process(n, p, drift=0, displacement=0):
    x = np.zeros(n)

    for i in range(1, n):
        x[i] = drift * i + p * x[i-1] + (1-p) * np.random.randn()
    return x + displacement

次に、この例に従ってKerasでLSTMモデルを作成しました。p=0.99長さの自己相関が高いプロセスをシミュレートn=10000し、その最初の80%でニューラルネットワークをトレーニングし、残りの20%に対して1ステップ先の予測を実行させました。

私が設定した場合drift=0, displacement=0、すべてが正常に動作します: ここに画像の説明を入力してください

それから私は設定しdrift=0, displacement=10、物事は洋ナシ形になりました(y軸の異なるスケールに注意してください): ここに画像の説明を入力してください

[11]ここに画像の説明を入力してください

次に、を設定しdrift=0.00001, displacement=10、データを再度正規化して、その上でアルゴリズムを実行しました。これはよく見えません: ここに画像の説明を入力してください

バツtバツt1バツtここに画像の説明を入力してください

私の質問:時差アルゴリズムでアルゴリズムを使用すると、なぜアルゴリズムが壊れるのですか?時系列のドリフトに対処する良い方法は何ですか?

これが私のモデルの完全なコードです:

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)

from keras.layers.core import Dense, Activation, Dropout
from keras.layers.recurrent import LSTM
from keras.models import Sequential


# The LSTM model
my_model = Sequential()

my_model.add(LSTM(input_shape=(1, 1), units=50, return_sequences=True))
my_model.add(Dropout(0.2))

my_model.add(LSTM(units=100, return_sequences=False))
my_model.add(Dropout(0.2))

my_model.add(Dense(units=1))
my_model.add(Activation('linear'))

my_model.compile(loss='mse', optimizer='rmsprop')


def my_prediction(x, model, normalize=False, difference=False):
    # Plot the process x
    plt.figure(figsize=(15, 7))
    plt.subplot(121)
    plt.plot(x)
    plt.title('Original data')

    n = len(x)
    thrs = int(0.8 * n)    # Train-test split
    # Save starting values for test set to reverse differencing
    x_test_0 = x[thrs + 1]
    # Save minimum and maximum on test set to reverse normalization
    x_min = min(x[:thrs])  
    x_max = max(x[:thrs])

    if difference:
        x = np.diff(x)   # Take difference to remove drift
    if normalize:
        x = (2*x - x_min - x_max) / (x_max - x_min)   # Normalize to [-1, 1]

    # Split into train and test set. The model will be trained on one-step-ahead predictions.
    x_train, y_train, x_test, y_test = x[0:(thrs-1)], x[1:thrs], x[thrs:(n-1)], x[(thrs+1):n]

    x_train, x_test = x_train.reshape(-1, 1, 1), x_test.reshape(-1, 1, 1)
    y_train, y_test = y_train.reshape(-1, 1), y_test.reshape(-1, 1)

    # Fit the model
    model.fit(x_train, y_train, batch_size=200, epochs=10, validation_split=0.05, verbose=0)

    # Predict the test set
    y_pred = model.predict(x_test)

    # Reverse differencing and normalization
    if normalize:
        y_pred = ((x_max - x_min) * y_pred + x_max + x_min) / 2
        y_test = ((x_max - x_min) * y_test + x_max + x_min) / 2  
    if difference:
        y_pred = x_test_0 + np.cumsum(y_pred)
        y_test = x_test_0 + np.cumsum(y_test)

    # Plot estimation
    plt.subplot(122)
    plt.plot(y_pred[-100:], label='One-step-ahead-predictions')
    plt.plot(y_test[-100:], label='Actual data')
    plt.title('Prediction on test set')
    plt.legend()
    plt.show()

# Make plots
x = my_process(10000, 0.99, drift=0, displacement=0)
my_prediction(x, my_model, normalize=False, difference=False)

x = my_process(10000, 0.99, drift=0, displacement=10)
my_prediction(x, my_model, normalize=False, difference=False)

x = my_process(10000, 0.99, drift=0, displacement=10)
my_prediction(x, my_model, normalize=True, difference=False)

x = my_process(10000, 0.99, drift=0.00001, displacement=10)
my_prediction(x, my_model, normalize=True, difference=False)

x = my_process(10000, 0.99, drift=0.00001, displacement=10)
my_prediction(x, my_model, normalize=True, difference=True)

回答:


1

自己相関プロセスをもう一度見てみましょう。

    def my_process(n, p, drift=0, displacement=0):
        x = np.zeros(n)

        for i in range(1, n):
            x[i] = drift * i + p * x[i-1] + (1-p) * np.random.randn()
    return x + displacement

の値displacementが高い場合、物事が壊れているように見えます。LSTMは正規化されたデータを必要とするため、これは当然のことです。

driftパラメータは少し異なっています。ドリフトが少量含まれている場合、ドリフトがp大きいため、ドリフト量はを介して追加されるランダムノイズの量に似ていnp.random.randn()ます。

のプロットでdrift=0.00001, displacement=10は、yシフトを除いて予測が適切であるように見えます。このため、問題の根本はまだdisplacementパラメーターではなくパラメーターにあると思いdriftます。行われたように、差異はdisplacementパラメータに役立ちません。代わりに、ドリフトを修正します。

あなたのコードからdisplacementはわかりませんが、おそらくで考慮されていなかったようmodel.predictです。それが私の推測です。


ご覧いただきありがとうございます!displacementただし、差分はパラメータを使用するのに役立ちます。バツt+1+cバツt+c=バツt+1バツt。また、最後の例では(差分後の)正規化を使用しているため、これは問題になりません...
エリアスストレー

1
こんにちは、よし、いい点!うーん。私はあなたが「ドリフト」と呼んでいるものを考えています。私は移動平均と呼んでいます(私はそう思います)。移動平均を説明するために、モデルにある種の共変量を含めることを試みることができます。理想的には、LSTMはもちろんそれ自体でそれを発見しますが、ここでは行き詰まっているようです。
StatsSorceress 2018年

LSTMを株価に適用したいので、少し心配です。それらにはドリフト/移動平均があり、標準的なアプローチ(少なくとも統計では)は差分を適用することです。つまり、価格の代わりにリターンを使用します。したがって、これがLSTMで(このような単純なモデルでも)機能しないように見える理由を理解したいと思います。
エリアスストレーレ2018年

1
元の値と差分値を使用して、フォワードパスとバックワードパスをトレースしましたか?差分値で何らかの勾配の消失問題が発生しているのでしょうか。もちろん、LSTMはこれに対してより堅牢ですが、これらの種類の問題が発生する可能性があるため、一見の価値があります。
StatsSorceress 2018年

1

x_minand を選択するとx_max、1 1:threshold人から選択します。シリーズが単調に増加しているため(ほぼ..)、テスト値はすべて> 1の値です。これは、LSTMモデルがトレーニング中にまったく見られなかったためです。

あなたが見ているものを見ているのはそのためですか?

あなたが同じことを試すことができますx_minし、x_max全体ではなく、データセットから来ますか?


これは私のおもちゃの例ではうまくいくかもしれません。しかし、LSTMを使用して実際に何かを予測する場合、これには将来を検討する必要があります。
エリアスストレー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.