У меня есть рабочий keras lstm для данных временных рядов, созданный с использованием одноразовых данных. Я перестал работать над ним, чтобы работать с другими частями моей системы, но теперь я внедряю его для производства, и мне нужно преобразовать свой подход к работе с переменным количеством функций. Пользователи начнут с небольшого количества функций и постепенно добавят их со временем.
[continous_value: 0.1, categoryA: 1]
[continous_value: 0.2, categoryA: 0, categoryB: 1]
[continous_value: 0.3, categoryA: 1, categoryB: 0]
...
Большинство «выпадет» в том смысле, что они не будут повторяться, и поэтому их легко обрезать, перемещая окно с течением времени - но некоторые повторяются с регулярностью. В настоящее время мой lstm построен на данных, которые были в окне для одного пользователя.
Каждая строка представляет собой 15-минутную выборку, и мои данные выборки имеют 2 непрерывных и 7 категориальных признаков. У меня 14-дневная сезонность (4 * 24 * 14 = 1344 временного шага), поэтому я выполнял повторную выборку в форму, подобную x:(1344, 14, 9)
и y:(1344, 9)
Теперь, чтобы позволить модели работать для разных пользователей, я начал добавлять «столбцы заполнения», но это не идеально: мне нужно угадать, каким будет максимум, и чем больше число, тем менее прогнозирующим модель.
Keras LSTM могут иметь переменное число объектов путем установки временного шага = Нет (поэтому x:(b, None, 9)
, я полагаю), но я не вижу, как реализовать это с многомерными данными временных рядов.
Как бы я изменил это для правильной генерации данных?
обработка данных:
# the memory of RNN depends on the number of timesteps you select
# if timesteps = n then the output depends on the previous n inputs
n = 14 # well over the weekly periodicity of the data
# Create input set that consists of n dimensions
# hence, the output of current day will be based on
# the prices of previous n days
len_train = 49 * DAYS
len_test = 7 * DAYS #(4 * 24)
train, test, endog, exog = dataForTest(len_train=len_train, len_test=len_test, offset=3*DAYS)
#print(train.iloc[-1],'\n',test.iloc[-1])
print(endog, exog)
dim = len(endog) + len(exog)
window = len_test # dim * 100 #using dim ensures it is reshapable dividing by dim
X_train = []
y_train = []
for i in range(n, n+(window)):
X_train.append(train[i - n: i].values)
y_train.append(train[i:i+1].values)
X_train, y_train = np.array(X_train), np.array(y_train)
y_train = y_train.reshape((window,dim))
print(X_train.shape, y_train.shape)
(batch_size, timesteps, dim) = X_train.shape
Модель:
# Initialise Sequential model
regressor = Sequential()
# units is the output dimensionality
# return sequences will return the sequence
# which will be required to the next LSTM
# as a great big rule-o-thumb, layers should be less than 10, and perhaps 1 per endog plus 1 for all exog
# also see: https://stats.stackexchange.com/questions/181/how-to-choose-the-number-of-hidden-layers-and-nodes-in-a-feedforward-neural-netw/1097#1097
alphaNh = len(columns) if len(columns) < 10 else 10 # 2-10, with 2 or 5 being common
nh = int(batch_size/(alphaNh*2*len(series.columns)))
dropout = 0.2
print('nh', nh)
# input shape will need only the last 2 dimensions
# of your input
################# 1st layer #######################
regressor.add(LSTM(units=nh, return_sequences=True, stateful=True, batch_size=batch_size,
input_shape=(timesteps, dim)))
# add Dropout to do regulariztion
# standard practise to use 20%
# regressor.add(Dropout(dropout))
layers = (len(endog) + 1) if len(endog) > 1 else 2
print('layers', layers)
for i in range(1, layers):
# After the first time, it's not required to
# specify the input_shape
################# layer #######################
# if i > 5:
# break
if i < layers - 1:
cell = LSTM(units=nh, return_sequences=True, stateful=True, batch_size=batch_size)
else:
cell = LSTM(units=nh, stateful=True, batch_size=batch_size)
regressor.add(cell)
################# Dropout layer #################
# After training layers we use some dropout.
# another option is to put this after each dim
# layer (above)
#
# standard practise to use 20%
regressor.add(Dropout(dropout))
################# Last layer ####################
# Last layer would be the fully connected layer,
# or the Dense layer
#
# The last word will predict a single number
# hence units=1
regressor.add(Dense(units=dim))
# Compiling the RNN
# The loss function for classification problem is
# cross entropy, since this is a regression problem
# the loss function will be mean squared error
regressor.compile(optimizer='adam', loss='mean_squared_error')
### src: https://keras.io/callbacks/
#saves the model weights after each epoch if the validation loss decreased
###
checkpointer = ModelCheckpoint(filepath='weights.hdf5', verbose=1, monitor='loss', mode='min', save_best_only=True)