seq2seq 预测下一个时间步
Posted
技术标签:
【中文标题】seq2seq 预测下一个时间步【英文标题】:seq2seq to predict next time step 【发布时间】:2020-02-28 02:52:46 【问题描述】:我目前正在尝试预测客户可能在下一个时间段内购买的下一个商品序列。以下示例用于说明目的(我的实际数据集有大约 600 万个客户 ID 和 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 在 2017 年的第一周购买了商品“product_1”、“product_5”和“product_15”(因此给定年份最多有 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 模型,我想使用 products_bought_last_period
预测客户在日期 201721 购买的产品序列,因此 products_bought_last_period
是我的输入,products_bought
现在是我的目标变量。
然后我对我的产品 ID 进行了编码,并在我的数据框中填充了我的 products_bought_last_period
和 products_bought
arrays(基于产品最多的数组)。之后,我转换了 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 方法是否正确开始
理想情况下,我希望预测客户(大约 600 万客户)可能购买的下一篮子商品。我非常感谢任何帮助
【问题讨论】:
如果您仍然对此感兴趣:我建议查看github.com/HaojiHu/Sets2Sets 【参考方案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 是否是最佳选择,并且必须对您购买的产品列表进行一次性编码。
编辑:在下面添加了一个简单的示例。
如果您查看以下链接,将会有几个很好的示例。有关使用 keras 的 seq2seq 的进一步查询,请参阅这些。
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 方案共享一个状态的两个结果序列似乎还可以。(至少试一试)
【讨论】:
@kidae_Kim 感谢您的回复。抱歉,如果这是一个愚蠢的问题,但我将如何定义我的编码器/解码器,以便我可以将 [train_encoder_input, train_decoder_input], train_decoder_output 合并到 model.fit() 中? @M3105,没问题。我用一个小例子进行了编辑。也可以查看链接的示例。以上是关于seq2seq 预测下一个时间步的主要内容,如果未能解决你的问题,请参考以下文章
如何在没有嵌入的情况下使用 tensorflow seq2seq?