基于LSTM的用户产品序列下一项及间隔时长双输出预测问询
问题:同时预测下一个购买产品及间隔时长
我有一份包含近10年用户产品购买序列的数据集,每条记录包含用户ID、最多20项产品及对应购买日期,不足20项则填充空值。数据集示例如下:
| 用户ID | 产品1 | 购买日期1 | 产品2 | 购买日期2 | 产品3 | 购买日期3 |
|---|---|---|---|---|---|---|
| 1 | A | 1/1/2020 | B | 1/18/2020 | ||
| 2 | B | 5/1/2020 | C | 1/18/2021 | D | 4/20/2022 |
我希望用n-1个产品序列预测最后一个产品,同时引入相邻产品的间隔月数作为特征(首个产品间隔设为0)。输入输出示例如下:
[[A, 0], [B, 6], [B, 12], [C, 18]] --> [D, 12]
目前训练的LSTM模型只能预测下一个产品,无法预测间隔时长,想知道是否能实现同时预测两个目标,且有没有更简便的实现方式。当前模型代码如下:
input_layer = tf.keras.Input(shape=(reshaped_padded_X.shape[1], 1)) lstm = tf.keras.layers.LSTM(64, return_sequences=True)(input_layer) dropout = tf.keras.layers.Dropout(0.2)(lstm) lstm = tf.keras.layers.LSTM(32)(dropout) dropout = tf.keras.layers.Dropout(0.2)(lstm) dense = tf.keras.layers.Dense(16, activation='relu')(dropout) output_layer = tf.keras.layers.Dense(y_cat.shape[1], activation='softmax')(dense) model = tf.keras.models.Model(inputs=input_layer, outputs=output_layer)
输入形状为(sample_size, 16, 2),16是填充后的序列长度,2对应产品序列和时间间隔特征。
实现方案
完全可以通过多输出神经网络同时实现产品分类和间隔时长回归两个任务,核心思路是共享序列特征提取模块,再分分支处理不同任务。以下是具体实现方式:
关键调整点
- 特征正确编码:产品是类别特征,需用
Embedding层转换为低维数值向量;时间间隔是数值特征,可直接输入。两者拼接后作为LSTM的输入特征。 - 多输出分支:LSTM提取序列特征后,分两个Dense分支:一个用
softmax输出产品分类结果,一个用线性激活输出间隔时长的回归结果。 - 组合损失函数:针对分类和回归任务分别选择合适的损失函数(交叉熵+均方误差),并可通过权重调整两个任务的优先级。
修改后的完整代码
import tensorflow as tf # 配置参数(根据你的数据集调整) num_product_categories = 15 # 产品总类别数(含空值类别) sequence_length = 16 # 填充后的序列长度 # 定义两个输入分支:产品序列(整数编码)、时间间隔序列 product_seq_input = tf.keras.Input(shape=(sequence_length,), name="product_sequence") interval_seq_input = tf.keras.Input(shape=(sequence_length, 1), name="interval_sequence") # 产品类别嵌入转换 product_embedding = tf.keras.layers.Embedding( input_dim=num_product_categories, output_dim=8, # 嵌入维度可根据需求调整 mask_zero=True # 忽略填充的空值(编码为0的项) )(product_seq_input) # 拼接嵌入后的产品特征与时间间隔特征 combined_features = tf.keras.layers.Concatenate(axis=-1)([product_embedding, interval_seq_input]) # LSTM序列特征提取 lstm_layer1 = tf.keras.layers.LSTM(64, return_sequences=True)(combined_features) dropout1 = tf.keras.layers.Dropout(0.2)(lstm_layer1) lstm_layer2 = tf.keras.layers.LSTM(32)(dropout1) dropout2 = tf.keras.layers.Dropout(0.2)(lstm_layer2) shared_dense = tf.keras.layers.Dense(16, activation="relu")(dropout2) # 输出分支1:产品分类 product_pred = tf.keras.layers.Dense( num_product_categories, activation="softmax", name="next_product" )(shared_dense) # 输出分支2:间隔时长回归(线性激活,因为时长是连续非负数值) interval_pred = tf.keras.layers.Dense( 1, activation="linear", name="next_interval" )(shared_dense) # 构建多输出模型 model = tf.keras.Model( inputs=[product_seq_input, interval_seq_input], outputs=[product_pred, interval_pred] ) # 编译模型:组合损失函数 model.compile( optimizer="adam", loss={ "next_product": "categorical_crossentropy", # 若y用one-hot编码;用类别索引则换sparse_categorical_crossentropy "next_interval": "mean_squared_error" }, loss_weights={"next_product": 1.0, "next_interval": 0.6}, # 调整权重平衡两个任务 metrics={ "next_product": "accuracy", "next_interval": "mean_absolute_error" } )
额外注意事项
- 预处理要求:需将产品编码为整数(空值编码为0),时间间隔的空值可填充为0;输入需拆分为产品序列和间隔序列两个数组。
- 模型优化:可尝试加入
Bidirectional双向LSTM提升序列特征捕捉能力,或调整LSTM神经元数量、嵌入维度优化效果。 - 回归输出处理:若间隔时长不可能为负,可将回归分支的激活函数改为
relu,确保输出非负。
内容的提问来源于stack exchange,提问作者Iden Crisler
相关产品推荐
相关产品推荐

