Python 中的朴素时间序列预测

2025年3月5日 | 阅读 12 分钟

朴素预测法是需求预测中最简单的形式之一,常被销售和财务部门使用。该方法基于简单原则:它假设未来需求最好由最近一个实际销售周期的模式来建模。换句话说,它假设下一期的需求将与上一期的需求相同。

关于朴素时间序列预测的工作

朴素预测法遵循一个简单的原则:它预测下一期的需求将与上一期(最近一期)的需求相同。换句话说,下一期要预测的值是固定的,并且固定为前一期的实际观测值。该方法基于这样的假设:最近的周期对未来的时间周期最相关,并且不会发生其他变化。

如何计算朴素预测?

朴素预测计算:朴素预测非常简单,几乎可以用 Excel 表格模板完成。方法是输入特定时期(例如,可以是一年或几个季度的月度数据)的实际销售数据,例如最近两年。

为了对后续的每个时期进行预测,您只需将前一期的销售数据用作当前时期的预测。例如,如果数据是按月间隔的,那么预测当前年份一月份的销售额,将使用前一年一月份的销售数据。

误差计算和方差分析:由于朴素预测技术很简单,并且不考虑可能影响预测的几个因素,因此通过衡量预测偏差或预测值与实际销售额之间的差异来评估预测的可信度非常重要。

该公式有助于确定预测值与实际销售额的偏离程度。

  • 正方差:如果方差为正(例如,9.05%),则表示实际销售额大于预测的销售水平。对于销售组织来说,这通常是一个有利的位置,因为客户的期望低于实际交付量。
  • 负方差:另一方面,负方差(-9.05%)表明存在过度供应销售的情况。这意味着该时期的销售额低于预期。这可能有很多原因,例如市场需求低迷或其他市场压力。

方差解读

  • 可接受方差:这表明预测误差是可以接受的,因为方差最多为百分之十,在这种情况下,您选择的方法对您的上下文来说相当不错。
  • 显著方差:绝对值较大的数值,即 41% 或 -41%,意味着情况更严重、不确定或严峻。如果差异很大,可能包括缺货或库存过多的情况,这些情况需要更高级的预测方法或其他的库存管理手段。

季节性朴素预测

季节性是您的销售数据在很长一段时间内可能出现的一种现象;您很可能会发现数据是周期性的,并且有与季节相关的趋势。例如,一家生产毛衣的公司在年末最后一个季度到新年伊始可能会经历巨大的需求,而在年中到年末可能会需求较低。另一方面,专注于销售太阳裙的商家可能会发现它们在温暖的月份受欢迎,而在寒冷的月份则不受欢迎。

季节性朴素预测基本上基于朴素预测法,但将季节性纳入了该过程。这种方法根据销售数据的季节性特点调整预测,因此有可能为一年中的不同季节提供更好的预测。

窗口平均预测

窗口平均模型的工作方式非常基本;它首先定义一个窗口大小,然后,对于每个时间序列,计算最近窗口大小个点的平均值。关键在于要清楚,这种方法实际上考虑了“窗口”中的最近观测值(数量固定),并计算其平均值。然后,此值用于根据当前数据集中的值来预测数据集的下一个值。

这种方法对于去除时间序列数据中的噪声特别有用,从而在短时期内揭示趋势。这意味着,通过对窗口内的值进行平均,该模型能够减少由于个体值出现不规则变化而对模型产生的影响。因此,它可以提供更少波动且更准确的未来预测,这在数据波动性很高的情况下可能很有帮助。

尽管窗口平均模型相对简单,但它可以在各种时间序列分析应用中用于过滤噪声并生成基本预测。然而,它不考虑长期季节性或趋势,因此更适用于相对平衡的序列或作为其他模型的一部分。

季节性窗口平均预测

季节性朴素模型是通过扩展简单的朴素方法而开发的,在该方法中,预测值是通过前一个周期中同一季节的上一个值来确定的。季节性朴素与纯朴素模型不同,它使用前一个相同季节的周期进行预测。在此模型中,强烈的季节性很有用,因为所使用的模型将应用同一类型的周期。

例如,如果要预测下周五的销售额,模型将使用上周五的销售额,或者上周、上个月或上年同一时期的其他周五的销售额。这使得预测更能与典型的周/双周/月度预期保持一致,因为它考虑到销售额在周五可能与一周中的其他任何一天遵循不同的趋势。

朴素预测的问题

朴素方法易于计算,但可能不是最准确或最可靠的方法。之前没有讨论过的是,朴素预测法并未考虑可能影响需求波动的几个重要因素。

例如,您可以解释这些因素,如您当前销售额与预测销售额之间的百分比差异,我们之前已讨论过。实际上,高于 1 的比率表明方差很高,例如,41% 的方差意味着您销售的产品比预测的多了 41%。也许如果您没有缺货,并且您的库存水平仅比预测高 41%,您本可以销售更多。另一方面,如果方差为 -41%,则表示您的销售额低于预期,导致公司拥有比需要更多的库存。由于仓储费用,库存成本也更高,对于食品行业的公司来说,这种盈余可能导致变质或所谓的“死库存”。

在当今这个需求激烈且极不稳定的世界中,朴素预测可能是一种极具破坏性的策略。销售额的波动可能导致您预测到需求变化,从而可能导致您订购过多的库存,这会在其他时期导致更多损失。另一方面,需求的急剧下降可能导致缺货情况,从而错过潜在的销售机会,并可能将客户流失给竞争对手。此外,需求计划者难以理解导致这些波动的因素,这阻碍了他们在预测和库存技术方面的改进。

在这种动态的商业环境中,仅仅使用基本技术不足以得出正确的需求预测;这就需要一个考虑某些因素和市场波动性的模型。这将能够实现更有效的库存控制,并最终最大限度地减少库存过剩或库存不足的情况,这两种情况分别对盈利能力和客户关系都有害。

要在 Python 中实现朴素预测,我们将使用 statsforecast 库,该库提供了流行朴素模型的访问权限,用于在 Python 中实现时间序列预测。

要安装 stats forecast 库,请打开命令提示符并输入命令

让我们来实现 Python 中的朴素预测。在这里,我们有来自 Favorita 连锁店 2013 年至 2017 年的销售数据。要实现朴素预测,让我们导入所需的库。

代码

说明

Pandas 用于执行数据分析和操作,numpy 涉及数据操作;matplotlib 用于图形说明。此外,它从 stats forecast 包中导入 StatsForecast 类以及一些预测模型功能,例如 Naive、SeasonalNaive、WindowAverage 和 SeasonalWindowAverage。这些模型通过尝试重现数据的模式(例如平均值和季节性)来生成简单的时序预测,从而利用数据过去的趋势和模式进行预测。

导入库后,让我们加载数据,即我们的 train.csv 文件。

代码

输出

 
	date	store_nbr	family	sales	onpromotion
id					
0	2013-01-01	1	AUTOMOTIVE	0.0	0
1	2013-01-01	1	BABY CARE	0.0	0
2	2013-01-01	1	BEAUTY	0.0	0
3	2013-01-01	1	BEVERAGES	0.0	0
4	2013-01-01	1	BOOKS	0.0	0

说明

上面的代码将包含存储销售数据的时序的 CSV 文件加载到 pandas DataFrame 中。它将“id”列设置为 DataFrame 的索引,并将“date”列转换为 datetime 以便进行灵活的操作。df.head() 函数用于显示 DataFrame 的前五行,以便可以初步了解数据。

让我们定义加权平均绝对百分比误差 (WMAPE) 来衡量预测的准确性。

代码

上面的代码单元建立了一个函数映射,该函数接受两个参数来给出加权平均绝对百分比误差 (WMAPE)。由于它量化了预测值与实际值之间的误差,因此它能够提供一个与平均绝对误差等其他度量标准进行标准化的误差,平均绝对误差计算了时间序列预测中实际值 y_true 和预测值 y_pred 之间的绝对误差的平均值。

让我们预处理数据。

代码

输出

 
	ds	unique_id	y
id			
24	2013-01-01	MEATS	0.000
25	2013-01-01	PERSONAL CARE	0.000
1806	2013-01-02	MEATS	369.101
1807	2013-01-02	PERSONAL CARE	194.000
3588	2013-01-03	MEATS	272.319
3589	2013-01-03	PERSONAL CARE	153.000
5370	2013-01-04	MEATS	454.172
5371	2013-01-04	PERSONAL CARE	88.000
7152	2013-01-05	MEATS	328.940
7153	2013-01-05	PERSONAL CARE	141.000

说明

上面的代码单元用于仅选择必要的记录,即 store nbr 为 1 且 org_product_family 为 MEATS 或 PERSONAL CARE 的记录。然后,它在列选择步骤中仅获取日期、家族和销售额。过滤后,对列进行重命名:例如,变量 'date' 被转换为 'ds','sales' 被转换为 'y',而 'family' 被转换为 'unique_id',可能是为了创建时间序列分析所需的格式。最后,df.head(10) 显示修改后的数据帧样本的前 10 行以供参考。

让我们将数据分为训练集和验证集。训练数据用于训练预测模型,验证数据用于测试和验证模型。

代码

输出

 
ds	unique_id	y
0	2013-01-01	MEATS	0.000
1	2013-01-01	PERSONAL CARE	0.000
2	2013-01-02	MEATS	369.101
3	2013-01-02	PERSONAL CARE	194.000
4	2013-01-03	MEATS	272.319
5	2013-01-03	PERSONAL CARE	153.000
6	2013-01-04	MEATS	454.172
7	2013-01-04	PERSONAL CARE	88.000
8	2013-01-05	MEATS	328.940
9	2013-01-05	PERSONAL CARE	141.000

说明

此代码基于 '2017-01-01' 的日期将 pandas 数据帧 df 的数据集分别拆分为 pandas 数据帧 train 和 valid 的训练集和验证集。训练集包含 2017 年之前的数据,而验证集包含 2017 年 1 月 1 日至 2017 年 4 月 1 日之间的数据。为了更清楚,此公式计算 h,即验证集中不同天数的计数。然后,它创建一个名为 'dec25' 的列表,用于插入 2013 年至 2016 年 12 月 25 日 MEATS 和 PERSONAL CARE 产品系列的假设值,其销售额为相应年份 12 月 18 日的销售额。然后,它将此新数据附加到 train DataFrame,然后再次根据 'ds'(或日期)重新排列整个数据。

代码

输出

 
StatsForecast(models=[Naive,SeasonalNaive,WindowAverage,SeasWA])

说明

在此代码片段中,使用 StatsForecast 八重奏(octet)创建了时间序列预测配置。它首先使用适合各种预测类型的类,例如 Naive 类和 SeasonalNaive 类,以及 WindowAverage 类和 SeasonalWindowAverage 类。每个模型都有独特的特性:最后一个方法 Naive 提供连续值作为预测;SeasonalNaive 提供一周的模式,季节长度为一周;WindowAverage 提供大小为 7 的移动平均;SeasonalWindowAverage 是季节性调整的组合,其中窗口大小为 2,季节长度为 7 天。然后使用这些模型初始化 StatsForecast,其中日频率表示为 'D',并行计算设置为 n_jobs=-1。设置模型后,fit 方法用于使用给定的训练数据集特征来训练模型。这使得模型能够基于历史输入数据进行预测。

代码

输出

 
	unique_id	ds	Naive	SeasonalNaive	WindowAverage	SeasWA	y
0	MEATS	2017-01-01	187.434006	176.259995	251.70929	176.259995	0.000
1	MEATS	2017-01-02	187.434006	80.884003	251.70929	161.768997	116.724
2	MEATS	2017-01-03	187.434006	229.281006	251.70929	249.756500	344.583
3	MEATS	2017-01-04	187.434006	236.942001	251.70929	279.700500	326.203
4	MEATS	2017-01-05	187.434006	234.882004	251.70929	273.109985	274.205
5	MEATS	2017-01-06	187.434006	616.281982	251.70929	725.903503	720.991
6	MEATS	2017-01-07	187.434006	187.434006	251.70929	189.695999	254.636
7	MEATS	2017-01-08	187.434006	176.259995	251.70929	176.259995	122.859
8	MEATS	2017-01-09	187.434006	80.884003	251.70929	161.768997	274.457
9	MEATS	2017-01-10	187.434006	229.281006	251.70929	249.756500	354.819
10	MEATS	2017-01-11	187.434006	236.942001	251.70929	279.700500	335.086
11	MEATS	2017-01-12	187.434006	234.882004	251.70929	273.109985	253.676
12	MEATS	2017-01-13	187.434006	616.281982	251.70929	725.903503	768.371
13	MEATS	2017-01-14	187.434006	187.434006	251.70929	189.695999	258.474
14	MEATS	2017-01-15	187.434006	176.259995	251.70929	176.259995	119.443
15	MEATS	2017-01-16	187.434006	80.884003	251.70929	161.768997	263.016
16	MEATS	2017-01-17	187.434006	229.281006	251.70929	249.756500	241.312
17	MEATS	2017-01-18	187.434006	236.942001	251.70929	279.700500	277.846
18	MEATS	2017-01-19	187.434006	234.882004	251.70929	273.109985	259.604
19	MEATS	2017-01-20	187.434006	616.281982	251.70929	725.903503	733.804
20	MEATS	2017-01-21	187.434006	187.434006	251.70929	189.695999	281.905
21	MEATS	2017-01-22	187.434006	176.259995	251.70929	176.259995	95.406
22	MEATS	2017-01-23	187.434006	80.884003	251.70929	161.768997	243.851
23	MEATS	2017-01-24	187.434006	229.281006	251.70929	249.756500	248.489
24	MEATS	2017-01-25	187.434006	236.942001	251.70929	279.700500	315.459
25	MEATS	2017-01-26	187.434006	234.882004	251.70929	273.109985	256.342
26	MEATS	2017-01-27	187.434006	616.281982	251.70929	725.903503	685.893
27	MEATS	2017-01-28	187.434006	187.434006	251.70929	189.695999	238.377
28	MEATS	2017-01-29	187.434006	176.259995	251.70929	176.259995	99.830
29	MEATS	2017-01-30	187.434006	80.884003	251.70929	161.768997	302.193

说明

在代码的第一行,使用 predict 方法获取模型对象对于给定预测范围 h 的预测,并将其分配给变量 p。然后将预测 DataFrame 的索引设置为验证索引,并使用 join 方法将这两个 DataFrame 以 'left' 类型连接起来,键为 'ds' 和 'unique_id' 列。此合并操作旨在将预测值与特定的验证数据合并,这有助于同步预测结果与实际值或其他类型的信息。