seq2seq для прогнозирования следующего шага по времени - PullRequest
5 голосов
/ 01 ноября 2019

В настоящее время я пытаюсь предсказать следующую последовательность товаров, которые покупатель может купить в следующий период времени. Следующий пример приведен для иллюстративных целей (мой фактический набор данных содержит около 6 миллионов идентификаторов клиентов и 5000 различных продуктов)

Мои текущие данные выглядят следующим образом:

date  customer_nbr  products_bought
201701  123 ["product_1","product_5","product_15"]
201704  123 ["product_4","product_10","product_11"]
201721  123 ["product_1","product_6"]
201713  456 ["product_7","sproduct_11","product_12","product_15"]
201714  456 ["product_1","product_3"]
201721  456 ["product_4","product_9","product_10","product_13","product_15"]

где частота данныхпо неделям. Таким образом, customer_id 123 купил товары «product_1», «product_5» и «product_15» в первую неделю 2017 года (таким образом, на данный год может быть до 52 недель). После задержки для получения моей входной переменной мой окончательный кадр данных выглядит следующим образом:

date  customer_nbr  products_bought_last_period   products_bought
201704  123 ["product_1","product_5","product_15"]  ["product_4","product_10","product_11"]
201721  123 ["product_4","product_10","product_11"]  ["product_1","product_6"]
201714  456 ["product_7","sproduct_11","product_12","product_15"]   ["product_1","product_3"]
201721  456 ["product_1","product_3"]  
["product_4","product_9","product_10","product_13","product_15"]

, поэтому для моей модели seq2seq я бы хотел предсказать последовательность продуктов, купленных покупателем на дату 2017 года с использованием products_bought_last_period, таким образом products_bought_last_period - это мой ввод, products_bought - теперь моя целевая переменная. Затем я кодировал свои идентификаторы продуктов и дополнил массивы products_bought_last_period и products_bought в моем фрейме данных (на основе массива с большинством продуктов). После этого я конвертировал все в np.arrays. Наконец, общее количество продуктов в моем фактическом наборе данных составляет 5000, поэтому я установил total_nbr_of_products = 5000 и попытался сделать следующее:

train = df[df['date'] < 201721].set_index('date')
test = df[df['date'] >= 201721].set_index('date')
X = train["products_bought_last_period"].copy()  
X_test = test["products_bought_last_period"].copy()


y = train['products_bought'].copy()  
y_test = test['products_bought'].copy()


X = np.array(X)
X_test = np.array(X_test)
y = np.array(y)
y_test = np.array(y_test)

# Encoder model
total_nbr_of_products = 5000
encoder_input = Input(shape=(None,total_nbr_of_products))
encoder_LSTM = LSTM(256,return_state = True)
encoder_outputs, encoder_h, encoder_c = encoder_LSTM (encoder_input)
encoder_states = [encoder_h, encoder_c]
# Decoder model
decoder_input = Input(shape=(None,total_nbr_of_products))
decoder_LSTM = LSTM(256,return_sequences=True, return_state = True)
decoder_out, _ , _ = decoder_LSTM(decoder_input, initial_state=encoder_states)
decoder_dense = Dense(total_nbr_of_products,activation='softmax')
decoder_out = decoder_dense (decoder_out)


model = Model(inputs=[encoder_input, decoder_input],outputs=[decoder_out])

model = Model(inputs=[encoder_input, decoder_input],outputs=[decoder_out])
model.compile(optimizer='adam', loss='categorical_crossentropy')
model.fit(X,y, 
          validation_data=(X_test, y_test),
          batch_size=64,
          epochs=5)

однако, когда я попытался сделать это, я получил следующую ошибку:

ValueError: Error when checking model input: the list of Numpy arrays that you are passing to your model is not the size the model expected. Expected to see 2 array(s), but instead got the following list of 1 arrays: [array([[array([1209, 2280, 1066, 3308, 3057, 4277, 3000, 4090,    0,    0,    0,

Я не уверен насчет двух основных вещей:

1.) Что я могу сделать неправильно, если сопоставить мои измерения

2.) ИМой подход seq2seq правильный для начала с

, в идеале я рассчитываю предсказать следующую корзину товаров, которую покупатель (примерно для 6 миллионов покупателей) может купить. Буду очень признателен за любую помощь

1 Ответ

0 голосов
/ 02 ноября 2019
  1. Что я могу сделать неправильно, сравнивая мои размеры?

Посмотрите, как определяется ваша модель.

model = Model(inputs=[encoder_input, decoder_input], outputs=[decoder_out])

Вам нужны два входа ([encoder_input, decoder_input] и decoder_out), чтобы соответствовать вашим данным. Ваш model.fit() должен выглядеть следующим образом:

model.fit([train_encoder_input, train_decoder_input], train_decoder_output)
Правильно ли здесь seq2seq?

Мне кажется, это необычное использование seq2seq, но хорошо. Вы должны увидеть, является ли отстаивание на 1 оптимальным выбором, и придется ли в одно касание кодировать ваш список купленных продуктов.

EDIT : добавлен простой пример ниже.

Есть пара превосходных примеров, которые можно объяснить, если вы посмотрите следующие ссылки. Обратитесь к ним для дальнейших запросов на seq2seq с keras.

https://blog.keras.io/a-ten-minute-introduction-to-sequence-to-sequence-learning-in-keras.html

https://github.com/philipperemy/keras-seq2seq-example


Для наглядности я написал небольшой пример. Давайте рассмотрим случай, когда мы хотим преобразовать строку в строку. Скажем, мы вводим новую систему почтовых индексов.

import numpy as np
from keras.layers import Input, LSTM, Dense
from keras.models import Model

df = {'old': ['ABCDBA', 'EFFEBA', 'CDDCAA', 'BBBBAA', 'FFDDCD', 'DCFEEF', 
              'AAFFBA'],
      'new': ['XYX', 'ZZX', 'YYX', 'XXX', 'ZYY', 'YZZ', 'XZX']}

Для моего удобства я установил фиксированное количество токенов и длину последовательности. Мы устанавливаем начало ('M') и конечный символ ('N') для данных, подаваемых в декодер.

encoder_texts = [[char for char in word] for word in df['old']]
decoder_texts = [[char for char in word] for word in df['new']]

old_char = ['A', 'B', 'C', 'D', 'E', 'F']
new_char = ['M', 'N', 'X', 'Y', 'Z']

encoder_seq_length = 6
decoder_seq_length = 4
num_encoder_tokens = len(old_char)
num_decoder_tokens = len(new_char)

old_token_index = dict((c, i) for i, c in enumerate(old_char))
new_token_index = dict((c, i) for i, c in enumerate(new_char))

Возьмем пример 'XYZ'. В качестве входа в декодер это 'MXYZ', а в качестве выхода из декодера - XYZN'. В конце концов, мы все равно должны кодировать эту последовательность символов одним щелчком, поэтому я делаю это в целом следующим образом:

encoder_input_data = np.zeros((7, encoder_seq_length, num_encoder_tokens), dtype='float32')
decoder_input_data = np.zeros((7, decoder_seq_length, num_decoder_tokens), dtype='float32')
decoder_output_data = np.zeros((7, decoder_seq_length, num_decoder_tokens), dtype='float32')

for i, (encoder_text, decoder_text) in enumerate(zip(encoder_texts, decoder_texts)):
    for t, char in enumerate(encoder_text):
        encoder_input_data[i, t, old_token_index[char]] = 1
    for t, char in enumerate(decoder_text):
        decoder_input_data[i, t+1, new_token_index[char]] = 1

        if t > 0:
            decoder_output_data[i, t-1, new_token_index[char]] = 1

        decoder_input_data[i, 0, new_token_index['M']] = 1
        decoder_output_data[i, 3, new_token_index['N']] = 1

Затем вы можете продолжить работу с вашим кодом.

encoder_input = Input(shape=(None, num_encoder_tokens))
encoder_LSTM = LSTM(units=128, return_state = True)
encoder_output, encoder_h, encoder_c = encoder_LSTM(encoder_input)
encoder_states = [encoder_h, encoder_c]

decoder_input = Input(shape=(None, num_decoder_tokens))
decoder_LSTM = LSTM(128, return_sequences=True, return_state=True)
decoder_output, _, _ = decoder_LSTM(decoder_input, initial_state=encoder_states)
decoder_dense = Dense(num_decoder_tokens, activation='softmax')
decoder_output = decoder_dense(decoder_output)

model = Model(inputs=[encoder_input, decoder_input], outputs=[decoder_output])
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
model.fit([encoder_input_data, decoder_input_data], decoder_output_data)

Чтобы ответить на ваш второй вопрос еще немного, вы можете использовать свою отсроченную серию продуктов, приобретенных для ввода и вывода вашего декодера. У меня нет теоретической основы для этого, но две последовательные последовательности, разделяющие состояние через схему seq2seq, кажутся нормальными. (По крайней мере, для этого)

...