python - seq2seq 预测下一个时间步

标签 python keras time-series lstm seq2seq

我目前正在尝试预测客户在下一个时间段内可能购买的下一个商品序列。以下示例用于说明目的(我的实际数据集有大约 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_periodproducts_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 方法是否正确

理想情况下,我希望预测客户(大约 600 万客户)可能购买的下一批商品。我将不胜感激任何帮助

最佳答案

  • 就匹配我的尺寸而言,我可能做错了什么?

  • 查看您的模型是如何定义的。
    model = Model(inputs=[encoder_input, decoder_input], outputs=[decoder_out])
    

    您需要两个输入([ encoder_inputdecoder_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 方案共享一个状态的两个结果序列似乎没问题。(至少试一试)

    关于python - seq2seq 预测下一个时间步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58665482/

    相关文章:

    python - Scikit-Learn 决策树 : Probability of prediction being a or b?

    python - URL检索错误处理

    python - openCV错误模块 'cv2.face'没有属性 'createEigenFaceRecognizer'

    python - Keras 测试后预测值

    javascript - 如何在 c3.js 图表中使用时间序列?

    r - 将每日和定期数据合并到一个数据框中

    python - 将标志添加到 cffi 编译过程

    tensorflow - 使用 Keras 对 GPU 进行推理

    python - CNN keras中图像的混淆矩阵

    r - Auto.arima() 函数不会产生白噪声。我还应该如何进行数据建模