You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Darts进行含缺失数据的时间序列建模:销量预测问题求助

解决Darts中TFT模型处理周末缺失销量数据的最优方案

针对你遇到的周末销量缺失、填充0效果差的问题,以下是几个优先级从高到低的处理方案:

1. 显式添加工作日标记协变量,保留缺失值并让模型学习规则

这是最推荐的方案,核心是让模型明确区分工作日和周末,而非盲目填充缺失值:

  • 先构建包含所有日期(含周末)的完整时间索引,将原始工作日数据合并到这个索引上,让周末的销量自然为NaN;
  • 添加一个布尔型协变量is_working_day,工作日设为1,周末设为0;
  • 广告支出的缺失可根据实际情况填充(比如周末无广告则填0,有历史数据则用前向填充);
  • 模型会通过is_working_day学习到“非工作日销量为0”的规则,同时结合广告支出预测工作日销量。

代码示例:

import pandas as pd
from darts import TimeSeries

# 读取原始数据
df = pd.read_csv('sales_data.csv', parse_dates=['date'])
# 生成包含所有日期的完整序列
full_date_range = pd.date_range(start=df['date'].min(), end=df['date'].max(), freq='D')
full_df = pd.DataFrame({'date': full_date_range})
# 合并原始数据,周末的销量、广告支出自动设为NaN
full_df = full_df.merge(df, on='date', how='left')
# 添加工作日标记协变量
full_df['is_working_day'] = full_df['date'].dt.weekday < 5  # 周一至周五为1,周末为0
# 填充广告支出缺失值(示例:周末无广告则填0)
full_df['ad_spend'] = full_df['ad_spend'].fillna(0)
# 创建Darts序列,销量保留NaN
sales_series = TimeSeries.from_dataframe(full_df, 'date', 'sales', fillna_value=None)
covs_series = TimeSeries.from_dataframe(full_df, 'date', ['ad_spend', 'is_working_day'])

2. 自定义掩码损失函数,忽略缺失值的损失计算

如果不想修改数据结构,可以通过自定义损失函数,只对工作日的有效销量计算损失,避免NaN干扰:

  • 构建一个掩码,标记哪些时间步是有真实销量的工作日;
  • 在损失函数中仅计算掩码覆盖区域的误差,模型会自动学习周末销量应为0的模式。

代码示例:

import torch
from darts.models import TFTModel

def masked_mae(y_true, y_pred):
    # 生成掩码:仅保留y_true不为NaN的时间步
    mask = ~torch.isnan(y_true)
    # 计算掩码区域内的MAE
    return torch.mean(torch.abs(y_true[mask] - y_pred[mask]))

# 初始化TFT模型时指定自定义损失
model = TFTModel(
    input_chunk_length=14,
    output_chunk_length=7,
    loss_fn=masked_mae,
    # 其他模型参数(如hidden_size、attention_head_size等)按需设置
)

3. 调整数据频率为工作日模式

如果你的预测目标仅针对工作日,不需要输出周末的销量预测,可以直接将数据频率调整为工作日(B频率),彻底规避周末的缺失值问题:

  • 将原始数据的索引转换为工作日频率,自动过滤周末日期;
  • 确保协变量(广告支出)也同步调整为工作日频率,保持时间对齐。

代码示例:

df = pd.read_csv('sales_data.csv', parse_dates=['date'])
# 设置索引并转换为工作日频率
df = df.set_index('date').asfreq('B')
# 创建Darts序列
sales_series = TimeSeries.from_dataframe(df, value_cols='sales')
covs_series = TimeSeries.from_dataframe(df, value_cols='ad_spend')

4. 合理插值填充(不推荐0填充)

如果必须填充周末销量,不要用0,而是选择更贴合业务逻辑的插值方式(比如线性插值、前向填充),但这种方法会引入人工假数据,仅作为备选:

# 线性插值填充销量缺失值
full_df['sales'] = full_df['sales'].interpolate(method='linear')
# 或者前向填充+反向填充
full_df['sales'] = full_df['sales'].ffill().bfill()

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 12:40:28