Python中的分层时间序列预测:自底向上与自顶向下聚合方法的实现与优化

Python中的分层时间序列预测:自底向上与自顶向下聚合方法的实现与优化

大家好,今天我们来深入探讨一个在时间序列预测领域非常重要的概念:分层时间序列预测(Hierarchical Time Series Forecasting, HTSF)。HTSF 涉及到对具有层次结构的时间序列进行预测,例如,销售数据可以按照地区、产品类别等多维度进行组织,形成一个层次结构。我们将会重点讨论两种常见的聚合方法:自底向上(Bottom-Up)和自顶向下(Top-Down)方法,并探讨如何在 Python 中实现和优化它们。

1. 分层时间序列的结构

在开始讨论预测方法之前,首先要明确分层时间序列的结构。一个典型的分层时间序列可以被表示为一个树状结构,其中:

  • 根节点 (Root Node): 代表整个时间序列的总和。
  • 中间节点 (Intermediate Nodes): 代表不同层次的聚合级别,例如,按地区划分的总销售额。
  • 叶节点 (Leaf Nodes): 代表最细粒度的时间序列,例如,每个地区每个产品的销售额。

考虑一个简单的销售数据示例,我们可以构建如下的层次结构:

层次 描述 例子
总销售额 所有地区所有产品的总销售额
L1 地区销售额 北区销售额,南区销售额,中区销售额
L2 地区+产品销售额 北区-产品A销售额,南区-产品B销售额等

2. 分层时间序列预测的挑战

与传统的单变量时间序列预测相比,HTSF 面临着一些独特的挑战:

  • 一致性 (Coherency): 各个层次的预测必须保持一致。例如,所有子区域的预测销售额之和必须等于总销售额的预测值。
  • 信息利用: 如何有效地利用各个层次的信息来提高预测精度?
  • 计算复杂度: 随着层次的增加,计算复杂度也会显著增加。

3. 自底向上 (Bottom-Up) 方法

自底向上方法是最直观也是最简单的 HTSF 方法之一。它的核心思想是:

  1. 预测叶节点: 对所有最细粒度(叶节点)的时间序列进行独立预测。
  2. 向上聚合: 将叶节点的预测值向上聚合,得到更高层次的预测值。

3.1 Python 实现

假设我们已经有了每个地区每个产品的销售额的预测值(leaf_forecasts)。我们可以使用 Pandas 来实现自底向上聚合:

import pandas as pd
import numpy as np

# 假设 leaf_forecasts 是一个 DataFrame,包含 'region', 'product', 'forecast' 列
# 以及一个时间索引 (datetime index)
# 例如:
# index      region  product  forecast
# 2023-01-01  North    A        100
# 2023-01-01  North    B        150
# 2023-01-01  South    A        120
# ...

def bottom_up_forecast(leaf_forecasts):
    """
    使用自底向上方法进行分层时间序列预测。

    Args:
        leaf_forecasts:  包含 'region', 'product', 'forecast' 列的 Pandas DataFrame,
                        索引为时间序列索引.

    Returns:
        一个字典,包含各个层次的预测值 DataFrame。
    """

    # 1. 地区销售额
    region_forecasts = leaf_forecasts.groupby(['index', 'region'])['forecast'].sum().reset_index()
    region_forecasts = region_forecasts.pivot(index='index', columns='region', values='forecast')

    # 2. 总销售额
    total_forecasts = leaf_forecasts.groupby('index')['forecast'].sum().reset_index()
    total_forecasts = total_forecasts.set_index('index')['forecast']

    return {'leaf': leaf_forecasts.pivot(index='index', columns=['region','product'], values='forecast'),
            'region': region_forecasts,
            'total': total_forecasts}

# 示例数据生成
dates = pd.date_range(start='2023-01-01', end='2023-01-10', freq='D')
regions = ['North', 'South', 'East', 'West']
products = ['A', 'B', 'C']

data = []
for date in dates:
    for region in regions:
        for product in products:
            forecast = np.random.randint(50, 200) # 随机生成预测值
            data.append([date, region, product, forecast])

leaf_forecasts_df = pd.DataFrame(data, columns=['index', 'region', 'product', 'forecast'])
leaf_forecasts_df = leaf_forecasts_df.set_index('index')

# 进行自底向上预测
forecasts = bottom_up_forecast(leaf_forecasts_df.copy())

# 打印结果
print("叶节点预测:n", forecasts['leaf'].head())
print("n地区预测:n", forecasts['region'].head())
print("n总预测:n", forecasts['total'].head())

3.2 优点和缺点

  • 优点: 简单易懂,易于实现。
  • 缺点: 忽略了更高层次的信息,可能导致较高层次的预测精度较低。对叶节点数据的质量要求高,任何一个叶节点的误差都会累积到更高的层级。

4. 自顶向下 (Top-Down) 方法

自顶向下方法与自底向上方法相反,其核心思想是:

  1. 预测根节点: 对整个时间序列(根节点)进行预测。
  2. 向下分解: 将根节点的预测值按照某种比例分解到更低的层次。

4.1 分解比例的确定

自顶向下方法的关键在于如何确定分解比例。常见的比例计算方法包括:

  • 历史比例 (Historical Proportions): 使用历史数据计算每个子序列占总序列的比例,并将该比例应用于未来的预测值。
  • 平均历史比例 (Average Historical Proportions): 计算一段时间内历史比例的平均值,并将其用于未来的预测值。
  • 预测比例 (Forecasted Proportions): 使用单独的模型预测未来的比例。

4.2 Python 实现 (历史比例)

import pandas as pd
import numpy as np

def top_down_forecast_historical(total_history, leaf_history, total_forecast):
    """
    使用自顶向下方法和历史比例进行分层时间序列预测。

    Args:
        total_history: 根节点历史时间序列 (Pandas Series). 索引为时间序列索引.
        leaf_history:  叶节点历史时间序列 (Pandas DataFrame),包含 'region', 'product', 'sales' 列,
                       索引为时间序列索引.
        total_forecast: 根节点的预测值 (Pandas Series). 索引为时间序列索引.

    Returns:
        一个字典,包含各个层次的预测值 DataFrame。
    """

    # 1. 计算历史比例
    leaf_history['total'] = leaf_history.groupby('index')['sales'].transform('sum')
    leaf_history['proportion'] = leaf_history['sales'] / leaf_history['total']
    leaf_proportions = leaf_history.pivot(index='index', columns=['region', 'product'], values='proportion')
    leaf_proportions = leaf_proportions.fillna(0) # 处理比例为0的情况

    # 2. 计算地区历史比例
    region_history = leaf_history.groupby(['index', 'region'])['sales'].sum().reset_index()
    region_history['total'] = region_history.groupby('index')['sales'].transform('sum')
    region_history['proportion'] = region_history['sales'] / region_history['total']
    region_proportions = region_history.pivot(index='index', columns='region', values='proportion')
    region_proportions = region_proportions.fillna(0) # 处理比例为0的情况

    # 3. 应用比例进行预测
    leaf_forecasts = pd.DataFrame(index=total_forecast.index, columns=leaf_proportions.columns)
    for col in leaf_proportions.columns:
        leaf_forecasts[col] = total_forecast * leaf_proportions[col].mean()  # 使用平均历史比例

    region_forecasts = pd.DataFrame(index=total_forecast.index, columns=region_proportions.columns)
    for col in region_proportions.columns:
        region_forecasts[col] = total_forecast * region_proportions[col].mean() # 使用平均历史比例

    return {'leaf': leaf_forecasts,
            'region': region_forecasts,
            'total': total_forecast}

# 示例数据生成
dates = pd.date_range(start='2022-01-01', end='2023-01-10', freq='D')
regions = ['North', 'South', 'East', 'West']
products = ['A', 'B', 'C']

# 历史数据
data = []
for date in dates[:-10]:  # 2022-01-01 到 2022-12-31 作为历史数据
    for region in regions:
        for product in products:
            sales = np.random.randint(50, 200)
            data.append([date, region, product, sales])

leaf_history_df = pd.DataFrame(data, columns=['index', 'region', 'product', 'sales'])
leaf_history_df = leaf_history_df.set_index('index')

total_history_df = leaf_history_df.groupby('index')['sales'].sum()

# 预测数据
total_forecast_values = np.random.randint(500, 800, size=10)  # 10个预测值
total_forecast_index = dates[-10:] # 2023-01-01 到 2023-01-10 作为预测区间
total_forecast_series = pd.Series(total_forecast_values, index=total_forecast_index)

# 进行自顶向下预测
forecasts = top_down_forecast_historical(total_history_df, leaf_history_df.copy(), total_forecast_series)

# 打印结果
print("叶节点预测:n", forecasts['leaf'].head())
print("n地区预测:n", forecasts['region'].head())
print("n总预测:n", forecasts['total'].head())

4.3 优点和缺点

  • 优点: 确保了各个层次的预测一致性。 可以利用总体趋势信息来指导子序列的预测。对根节点数据的质量要求高。
  • 缺点: 可能忽略了子序列的独特性,导致子序列的预测精度较低。历史比例可能不稳定,影响预测精度。

5. 方法选择与优化

在实际应用中,如何选择合适的 HTSF 方法?

  • 数据质量: 如果叶节点数据质量较高,且各个子序列的模式差异较大,则自底向上方法可能更合适。如果根节点数据质量较高,且各个子序列的模式相似,则自顶向下方法可能更合适。
  • 预测目标: 如果关注高层次的预测精度,则自顶向下方法可能更合适。如果关注低层次的预测精度,则自底向上方法可能更合适。
  • 计算资源: 自底向上方法通常计算复杂度较高,而自顶向下方法计算复杂度较低。

5.1 优化策略

  • 组合方法: 将自底向上和自顶向下方法结合起来,例如,先使用自顶向下方法得到高层次的预测值,然后使用自底向上方法对低层次的预测值进行调整,以确保一致性。
  • 加权平均: 对自底向上和自顶向下方法的预测结果进行加权平均,权重可以根据历史预测精度来确定。
  • 误差修正: 在聚合过程中,对误差进行修正,例如,使用回归模型来预测聚合误差,并将其用于修正聚合结果。
  • 模型选择: 使用更高级的时间序列模型,例如,VAR、LSTM 等,来提高各个层次的预测精度。
  • 特征工程: 针对不同层次的时间序列,进行特征工程,例如,提取趋势、季节性、周期性等特征,以提高预测精度。
  • 约束优化: 在预测过程中,加入约束条件,例如,销售额不能为负数,各个子序列的销售额之和必须等于总销售额等,以提高预测结果的合理性。

6. 更高级的方法

除了自底向上和自顶向下方法,还有一些更高级的 HTSF 方法,例如:

  • 中间方法 (Middle-Out Approach): 选择中间层次进行预测,然后向上和向下聚合。
  • 最优组合方法 (Optimal Combination Approach): 使用线性回归或其他方法,找到最佳的组合权重,以最小化预测误差。
  • 机器学习方法: 使用机器学习模型,例如,梯度提升树、神经网络等,来学习各个层次之间的关系,并进行预测。

这些方法通常更加复杂,但可以获得更高的预测精度。

7. Python 库

在 Python 中,有一些专门用于 HTSF 的库,例如:

  • hts (Hierarchical Time Series): 提供了一系列 HTSF 方法的实现,包括自底向上、自顶向下、最优组合等。
  • scikit-hts: 基于 scikit-learn 的 HTSF 库,提供了更丰富的机器学习模型支持。

使用这些库可以简化 HTSF 的实现过程。

8. 实际案例分析

假设一个零售公司需要在全国范围内预测其产品的销售额。该公司的数据按照地区(华东、华南、华北)和产品类别(服装、家居、电器)进行组织。

  • 自底向上: 公司可以首先预测每个地区每个产品类别的销售额,然后向上聚合得到每个地区和每个产品类别的总销售额,以及全国总销售额。这种方法适用于各个地区和产品类别的销售模式差异较大的情况。
  • 自顶向下: 公司可以首先预测全国总销售额,然后按照历史比例将总销售额分解到各个地区和产品类别。这种方法适用于全国总体销售趋势较为稳定的情况。
  • 组合方法: 公司可以先使用自顶向下方法预测全国总销售额和每个地区的总销售额,然后使用自底向上方法预测每个地区每个产品类别的销售额,并对结果进行调整,以确保一致性。这种方法可以结合两种方法的优点,提高预测精度。

公司可以根据自身的数据特点和预测目标,选择合适的 HTSF 方法。

未来方向

分层时间序列预测仍然是一个活跃的研究领域,未来的发展方向包括:

  • 深度学习: 将深度学习模型应用于 HTSF,以更好地捕捉各个层次之间的复杂关系。
  • 不确定性量化: 对 HTSF 的预测结果进行不确定性量化,例如,计算预测区间,以帮助决策者更好地评估风险。
  • 动态层次结构: 研究如何处理动态变化的层次结构,例如,新增或删除地区或产品类别。
  • 因果推断: 将因果推断方法应用于 HTSF,以更好地理解各个层次之间的因果关系。

最后的话:选择方法,持续优化

分层时间序列预测是一个复杂的问题,没有一种方法能够适用于所有情况。选择合适的 HTSF 方法需要根据具体的数据特点和预测目标进行判断。重要的是理解各种方法的优缺点,并根据实际情况进行调整和优化。希望今天的讲解能够帮助大家更好地理解和应用分层时间序列预测。

更多IT精英技术系列讲座,到智猿学院

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注