Інтервал прогнозування навколо прогнозу часових рядів LSTM


14

Чи існує метод обчислення інтервалу прогнозування (розподілу ймовірностей) навколо прогнозу часових рядів з нейронної мережі LSTM (або іншої періодичної)?

Скажімо, наприклад, я прогнозую 10 зразків у майбутнє (t + 1 до t + 10), виходячи з останніх 10 спостережуваних вибірок (t-9 до t), я б очікував, що прогноз при t + 1 буде більше точніше прогнозування при t + 10. Зазвичай можна намалювати смуги помилок навколо прогнозу, щоб показати інтервал. За допомогою моделі ARIMA (за припущенням нормально розподілених помилок) я можу обчислити інтервал прогнозування (наприклад, 95%) навколо кожного прогнозованого значення. Чи можу я обчислити те саме (або щось, що стосується інтервалу прогнозування) з моделі LSTM?

Я працюю з LSTM в Keras / Python, дотримуючись безліч прикладів з machinelearningmastery.com , з яких базується мій приклад коду (нижче). Я розглядаю можливість переформулювання проблеми як класифікації на дискретні бункери, оскільки це дає впевненість на клас, але це здається поганим рішенням.

Існує декілька подібних тем (наприклад, наведених нижче), але, здається, ніщо безпосередньо не вирішує питання проміжків прогнозування з НСТМ (або взагалі інших) нейронних мереж:

/stats/25055/how-to-calculate-the-confidence-interval-for-time-series-prediction

Прогнозування часових рядів за допомогою ARIMA проти LSTM

from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from math import sin
from matplotlib import pyplot
import numpy as np

# Build an LSTM network and train
def fit_lstm(X, y, batch_size, nb_epoch, neurons):
    X = X.reshape(X.shape[0], 1, X.shape[1]) # add in another dimension to the X data
    y = y.reshape(y.shape[0], y.shape[1])      # but don't add it to the y, as Dense has to be 1d?
    model = Sequential()
    model.add(LSTM(neurons, batch_input_shape=(batch_size, X.shape[1], X.shape[2]), stateful=True))
    model.add(Dense(y.shape[1]))
    model.compile(loss='mean_squared_error', optimizer='adam')
    for i in range(nb_epoch):
        model.fit(X, y, epochs=1, batch_size=batch_size, verbose=1, shuffle=False)
        model.reset_states()
    return model

# Configuration
n = 5000    # total size of dataset
SLIDING_WINDOW_LENGTH = 30
SLIDING_WINDOW_STEP_SIZE = 1
batch_size = 10
test_size = 0.1 # fraction of dataset to hold back for testing
nb_epochs = 100 # for training
neurons = 8 # LSTM layer complexity

# create dataset
#raw_values = [sin(i/2) for i in range(n)]  # simple sine wave
raw_values = [sin(i/2)+sin(i/6)+sin(i/36)+np.random.uniform(-1,1) for i in range(n)]  # double sine with noise
#raw_values = [(i%4) for i in range(n)] # saw tooth

all_data = np.array(raw_values).reshape(-1,1) # make into array, add anothe dimension for sci-kit compatibility

# data is segmented using a sliding window mechanism
all_data_windowed = [np.transpose(all_data[idx:idx+SLIDING_WINDOW_LENGTH]) for idx in np.arange(0,len(all_data)-SLIDING_WINDOW_LENGTH, SLIDING_WINDOW_STEP_SIZE)]
all_data_windowed = np.concatenate(all_data_windowed, axis=0).astype(np.float32)

# split data into train and test-sets
# round datasets down to a multiple of the batch size
test_length = int(round((len(all_data_windowed) * test_size) / batch_size) * batch_size)
train, test = all_data_windowed[:-test_length,:], all_data_windowed[-test_length:,:]
train_length = int(np.floor(train.shape[0] / batch_size)*batch_size) 
train = train[:train_length,...]

half_size = int(SLIDING_WINDOW_LENGTH/2) # split the examples half-half, to forecast the second half
X_train, y_train = train[:,:half_size], train[:,half_size:]
X_test, y_test = test[:,:half_size], test[:,half_size:]

# fit the model
lstm_model = fit_lstm(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epochs, neurons=neurons)

# forecast the entire training dataset to build up state for forecasting
X_train_reshaped = X_train.reshape(X_train.shape[0], 1, X_train.shape[1])
lstm_model.predict(X_train_reshaped, batch_size=batch_size)

# predict from test dataset
X_test_reshaped = X_test.reshape(X_test.shape[0], 1, X_test.shape[1])
yhat = lstm_model.predict(X_test_reshaped, batch_size=batch_size)

#%% Plot prediction vs actual

x_axis_input = range(half_size)
x_axis_output = [x_axis_input[-1]] + list(half_size+np.array(range(half_size)))

fig = pyplot.figure()
ax = fig.add_subplot(111)
line1, = ax.plot(x_axis_input,np.zeros_like(x_axis_input), 'r-')
line2, = ax.plot(x_axis_output,np.zeros_like(x_axis_output), 'o-')
line3, = ax.plot(x_axis_output,np.zeros_like(x_axis_output), 'g-')
ax.set_xlim(np.min(x_axis_input),np.max(x_axis_output))
ax.set_ylim(-4,4)
pyplot.legend(('Input','Actual','Predicted'),loc='upper left')
pyplot.show()

# update plot in a loop
for idx in range(y_test.shape[0]):

    sample_input = X_test[idx]
    sample_truth = [sample_input[-1]] + list(y_test[idx]) # join lists
    sample_predicted = [sample_input[-1]] + list(yhat[idx])

    line1.set_ydata(sample_input)
    line2.set_ydata(sample_truth)
    line3.set_ydata(sample_predicted)
    fig.canvas.draw()
    fig.canvas.flush_events()

    pyplot.pause(.25)

Відповіді:


10

Безпосередньо це неможливо. Однак якщо ви будете моделювати його по-іншому, ви можете отримати довірчі інтервали. Ви можете замість нормальної регресії підходити до цього як до оцінки постійного розподілу ймовірностей. Роблячи це для кожного кроку, ви зможете побудувати свій розподіл. Способи зробити це мережеві суміші ядра ( https://janvdvegt.github.io/2017/06/07/Kernel-Mixture-Networks.html , розкриття, мій блог) або мережі щільності суміші ( http: //www.cedar .buffalo.edu / ~ srihari / CSE574 / Chap5 / Chap5.7-MixDensityNetworks.pdf ), перший використовує ядра як основу і оцінює суміш по цих ядрах, а другий оцінює суміш розподілів, включаючи параметри кожного з розподіли. Ви використовуєте ймовірність журналу для навчання моделі.

Іншим варіантом моделювання невизначеності є використання відмовки під час тренувань, а потім і під час виведення. Ви робите це кілька разів і кожен раз, коли отримуєте зразок із задньої частини. Ви не отримуєте дистрибуції, а лише зразки, але це найпростіше у виконанні, і це працює дуже добре.

У вашому випадку ви повинні думати про те, як ви генеруєте t + 2 до t + 10. Залежно від вашого поточного налаштування, можливо, доведеться взяти вибірку з попереднього етапу часу та подати його для наступного. Це не дуже добре справляється ні з першим підходом, ні з другим. Якщо у вас є 10 виходів за крок часу (t + 1 до t + 10), всі ці підходи є більш чистими, але трохи менш інтуїтивними.


2
Використання сумішових мереж цікаво, я спробую це реалізувати. Тут є ґрунтовні дослідження щодо використання відсіву: arxiv.org/abs/1709.01907 та arxiv.org/abs/1506.02142
4Oh4


Це правда @CharlesChow, але це поганий спосіб побудувати інтервал довіри в цьому контексті. Краще було б сортувати значення та використовувати кванти через потенційно дуже перекошений розподіл.
Ян ван дер Вегт

Погодьтеся @JanvanderVegt, але ви все ще можете оцінити статистику відмови від МС без припущення про розподіл випуску, я маю на увазі, що ви також можете використовувати процентиль або завантажувальний інструмент для побудови
Чарльз Чоу

2

Неформальне передбачення як гучне слово може бути цікавим для вас, оскільки воно працює в багатьох умовах - зокрема, воно не потребує нормальної розподіленої помилки і працює майже для будь-якої моделі машинного навчання.

Два приємних вступу дають Скотт Локлін та Генрік Лінуссон .


1

Я збираюся трохи розходитися і стверджую, що інтервал довіри розрахунку на практиці зазвичай не є цінною справою. Причина в тому, що завжди потрібно зробити цілу купу припущень. Навіть для найпростішої лінійної регресії потрібно мати

  • Лінійна залежність.
  • Багатовимірна нормальність.
  • Немає або мало мультиколінеарності.
  • Відсутня автоматична кореляція.
  • Гомоседастичність.

Набагато більш прагматичний підхід - це зробити моделювання Монте-Карло. Якщо ви вже знаєте чи готові зробити припущення щодо розподілу вхідних змінних, візьміть цілу купу зразків і подайте її вам LSTM, тепер ви зможете емпірично розрахувати свій "інтервал довіри".


1

Так, ти можеш. Єдине, що вам потрібно змінити - це функція втрат. Реалізуйте функцію втрат, використану в квантильній регресії, та інтегруйте її. Крім того, ви хочете подивитися, як ви оцінюєте ці інтервали. Для цього я використовував би показники ICP, MIL та RMIL.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.