You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用LSTM结合历史与当前特征预测?含DataFrame重塑咨询

嘿,这两个问题都是时序预测里非常典型的场景,我来给你拆解清楚~

一、如何用LSTM结合历史特征与当前/未来特征开展预测

LSTM的核心优势是捕捉时序数据的时间依赖关系,而你提到的“当前/未来特征”(比如次日要执行的折扣)属于非时序的条件特征,我们需要把这两类特征合理整合,让模型同时学习时序规律和条件约束。具体步骤如下:

  • 第一步:明确特征分类
    先把特征分成两类,避免混淆:

    • 时序历史特征:过去N天的unit_sales(销量)、Discount(折扣)——这部分是随时间变化的序列,LSTM会学习它们的趋势、周期等规律。
    • 非时序条件特征:次日将要执行的Discount——这部分是每个预测样本对应的“已知条件”,因为你提前知道次日的折扣,所以可以作为附加特征输入模型。
  • 第二步:构造适配LSTM的输入数据
    LSTM的标准输入是三维张量:(样本数量, 时间步长, 特征维度)。针对两类特征,有两种常用的整合方式:

    1. 将条件特征拼接在每个时间步上:把次日折扣加到过去3天每个时间步的特征里,比如每个时间步的特征从[销量, 当日折扣]变成[销量, 当日折扣, 次日折扣],这样输入张量形状为(样本数, 3, 3)。这种方式简单直接,适合条件特征对整个时序都有影响的场景。
    2. LSTM编码后拼接条件特征:先用LSTM处理历史时序特征,得到一个包含时序信息的编码向量,再把次日折扣和这个向量拼接,通过全连接层输出预测结果。这种方式更灵活,能区分时序规律和条件特征的独立影响。
  • 第三步:模型构建与训练
    用TensorFlow/Keras举个简单的伪代码示例:

    # 方式1:条件特征拼接在每个时间步
    from tensorflow.keras import Input, Model
    from tensorflow.keras.layers import LSTM, Dense
    
    input_layer = Input(shape=(3, 3))  # 3个时间步,每个步3个特征
    lstm_layer = LSTM(64)(input_layer)
    output_layer = Dense(1)(lstm_layer)
    model = Model(inputs=input_layer, outputs=output_layer)
    model.compile(optimizer='adam', loss='mse')
    
    # 方式2:LSTM后拼接条件特征
    seq_input = Input(shape=(3, 2))  # 时序特征:3步,每步2个特征(销量、当日折扣)
    lstm_out = LSTM(64)(seq_input)
    static_input = Input(shape=(1,))  # 条件特征:次日折扣
    concat = tf.keras.layers.Concatenate()([lstm_out, static_input])
    dense = Dense(32, activation='relu')(concat)
    output_layer = Dense(1)(dense)
    model = Model(inputs=[seq_input, static_input], outputs=output_layer)
    model.compile(optimizer='adam', loss='mse')
    

    训练时,方式2需要把时序数据和条件数据分开传入模型。

  • 第四步:预测阶段
    预测时,要和训练时的输入结构一致:比如要预测某一天的销量,先取出过去3天的销量和折扣组成时序序列,再加上已知的次日折扣,输入模型即可得到预测结果。

二、如何重塑DataFrame以适配上述预测逻辑

首先要确保你的DataFrame是按日期升序排列的,这是时序处理的基础。假设你的原始DataFrame包含datepricemarked_priceDiscountunit_sales列,下面提供两种重塑方式:

方式1:生成扁平特征列(适合数据清洗和可视化)

这种方式把所有需要的特征展开成单独的列,方便你查看每个样本的完整信息:

import pandas as pd

# 1. 按日期排序
df = df.sort_values('date').reset_index(drop=True)

# 2. 生成过去3天的销量和折扣特征
for day in range(1, 4):
    df[f'unit_sales_{day}d_ago'] = df['unit_sales'].shift(day)
    df[f'Discount_{day}d_ago'] = df['Discount'].shift(day)

# 3. 生成次日的折扣(条件特征)和目标销量(要预测的y)
df['next_day_Discount'] = df['Discount'].shift(-1)
df['next_day_unit_sales'] = df['unit_sales'].shift(-1)

# 4. 丢弃缺失值(前3天没有足够历史数据,最后一行没有次日数据)
df_clean = df.dropna().reset_index(drop=True)

此时df_clean的每一行就是一个完整的样本:包含过去3天的销量、折扣,次日的折扣,以及要预测的次日销量。

方式2:直接生成LSTM所需的3D张量(适合直接喂入模型)

如果想跳过扁平列的步骤,直接生成模型需要的输入张量,可以写一个简单的函数:

import numpy as np

def create_lstm_sequences(df, seq_length=3):
    # 提取时序特征、条件特征和目标变量
    seq_features = df[['unit_sales', 'Discount']].values
    static_features = df['Discount'].shift(-1).values
    target = df['unit_sales'].shift(-1).values

    X_seq, X_static, y = [], [], []

    # 遍历生成每个样本
    for i in range(len(df) - seq_length):
        # 取过去seq_length天的时序特征
        X_seq.append(seq_features[i:i+seq_length])
        # 取对应样本的次日折扣
        X_static.append(static_features[i+seq_length-1])
        # 取对应样本的目标销量
        y.append(target[i+seq_length-1])

    # 转换为numpy数组,适配LSTM输入格式
    X_seq = np.array(X_seq)
    X_static = np.array(X_static).reshape(-1, 1)  # 转为(样本数, 1)的形状
    y = np.array(y)

    return X_seq, X_static, y

# 生成模型输入数据
X_seq, X_static, y = create_lstm_sequences(df)

X_seq是形状为(样本数, 3, 2)的时序输入,X_static是形状为(样本数, 1)的次日折扣特征,y是目标销量,刚好可以对应上面方式2的模型输入。

内容的提问来源于stack exchange,提问作者Aaron_Geng

火山引擎 最新活动