时间序列可能用于回答业务在不同时间段的波动等问题(比如今天的订单为什么降了)

关于图表,在统计学角度只关心曲线三件事:

  1. 趋势:上升还是下降,或者趋势拟合成什么函数?
  2. 周期性:信息规律是否会周期性的重现?
  3. 残差:把周期性和趋势去掉之后,剩下的“没用的部分”

为了说明这几件事,引用最常见的时间序列模型:加法模型和乘法模型

一、加法模型

时间序列数据被表示为各个成分的线性加和,适用于当季节性变化的幅度与时间无关的情况。即季节性波动的大小是固定的。模型表示为:Y(t)=T(t)+S(t)+R(t)

  • Y(t):时间序列在时间t的值
  • T(t):趋势成分,表示长期趋势
  • S(t):季节性成分,表示周期波动
  • R(t):残差成分,表示随机波动或误差

加法模型意味着,三件事情是互相独立的,增长是增长,周期是周期。

二、乘法模型

时间序列数据被表示为各个成分的乘积。适用于当季节性变化的幅度随时间变化而变化的情况,即季节性波动的大小是与趋势相关的。模型表示为:Y(t)=T(t)×S(t)×R(t)

各指标之间是互相影响的,那么属于乘法模型

三、时间序列的统计量

(1)同比增长率YoY:指的是当前时间段与前一年度同一时间段相比的增长率——年与年

=(本期值-去年同期值)/去年同期值*100%

(2)环比增长率MoM:指的是当前时间段与前一个时间段相比的增长率——月与月

=(本期值-去年同期值)/去年同期值*100%

(3)累计增长率CGR:指一段时间内的累积变化情况,通常用于衡量一个时间段内的总增长情况

=(期末值/期初值-1)*100%

(4)年化增长率CAGR:指某一项指标在特定时间段内按年计算的平均增长率(n为年数)

(5)移动平均值MA:是一种平滑时间序列数据的方法,通过计算特定时间窗口内的平均值来减少数据中的噪声

案例:以共享出行作为例子解析

1、选择有业务场景的统计量做时间序列

相比较【订单数】来说,【人均骑行次数】更能说明人的需求变多了,这时候就要去看:是结构性问题(高需求的人占比变多了,所以整体的人均骑行次数起来了),还是个体需求有增长(需求由低到高,然后稳定了

这两个问题可能是交织的(因为一个人的需求变高了,所以高需求的人的占比变多了),所以需要进一步的验证:

(1)各骑行频次的人流失率同比是否变化

(2)各骑行频次的人年度变化(低频到高频)情况如何

如果低频次流失人数>低频词跃迁到高频词人数,那么导致人均骑行频增长的主要原因是低频次用户流失。

2、选择相关的业务统计量的时间序列做验证

只有大盘分析是不够,还要把量化的结果取到各区域,然后观察:

是不是因为车辆流失的多的地方,低频词用户流失的原因更大?

要从业务视角了解为什么低频次的用户会流失,细拆分之后可能会出现大城市低频次用户流失,小城市低频词用户跃迁,导致整体的人均骑行次数变大。那么就看时间序列的指标对比:是否人均骑行频次【年同比】提高,且低频次流失用户高于低频次跃迁为高频次的【城市】【车辆数的年同比】在下降?

如果车辆数下降,影响的不只是低频词用户,同样会有其他的情况。例如:

(1)是否单次付费用户聚集地方车辆少了

(2)各区域的车辆都在下降,因为骑行卡变得更贵了,更多的用户慢慢选择了单次骑行

(3)竞争对手的单次定价更便宜

因此能够把整个过程梳理清楚:城市总车辆变少>>车辆往中心调度>>提高单均价,骑行卡用户流失>>高频次用户变低频次>>去到竞对方

四、时间序列模型(*)

4.1 自回归模型AR

是基于时间序列自身过去的值来预测当前值的一种模型,假设当前时刻的值是由过去若干时刻的值线性组合得到的。公式:

这个模型非常依赖稳定的周期性.

from statsmodels.tsa.ar_model import AutoReg
import matplotlib.pyplot as plt

# 假设数据已经加载并处理
# data['value'] 是时间序列数据

# 建立AR(p)模型
p = 2  # 选择自回归阶数
model = AutoReg(data['value'], lags=p)
model_fit = model.fit()

# 预测
predictions = model_fit.predict(start=len(data), end=len(data)+10)

# 可视化
plt.plot(data['value'], label='历史数据')
plt.plot(predictions, label='预测数据', color='red')
plt.legend()
plt.show()

4.2 移动平均模型MA

是基于过去若干时刻的预测误差(残差)来预测当前值的模型,假设当前值是过去误差项的线性组合。公式:

from statsmodels.tsa.arima.model import ARIMA
import matplotlib.pyplot as plt

# 建立MA(q)模型
q = 2  # 选择移动平均阶数
model = ARIMA(data['value'], order=(0, 0, q))
model_fit = model.fit()

# 预测
predictions = model_fit.predict(start=len(data), end=len(data)+10)

# 可视化
plt.plot(data['value'], label='历史数据')
plt.plot(predictions, label='预测数据', color='red')
plt.legend()
plt.show()

4.3 自回归移动平均模型ARMA

结合了AR模型和MA模型的特点,同时考虑了时间序列过去的值和过去的误差项。公式:

from statsmodels.tsa.arima.model import ARIMA
import matplotlib.pyplot as plt

# 建立ARMA(p, q)模型
p = 2  # 自回归阶数
q = 2  # 移动平均阶数
model = ARIMA(data['value'], order=(p, 0, q))
model_fit = model.fit()

# 预测
predictions = model_fit.predict(start=len(data), end=len(data)+10)

# 可视化
plt.plot(data['value'], label='历史数据')
plt.plot(predictions, label='预测数据', color='red')
plt.legend()
plt.show()

4.4 自回归差分移动平均模型ARIMA

用于建模非平稳时间序列,通过差分(积分)使数据平稳后,再应用ARMA模型进行建模,公式:

相对来说较常用,针对不平稳时间序列。

from statsmodels.tsa.arima.model import ARIMA
import matplotlib.pyplot as plt

# 建立ARIMA(p, d, q)模型
p = 2  # 自回归阶数
d = 1  # 差分次数
q = 2  # 移动平均阶数
model = ARIMA(data['value'], order=(p, d, q))
model_fit = model.fit()

# 预测
predictions = model_fit.predict(start=len(data), end=len(data)+10, typ='levels')

# 可视化
plt.plot(data['value'], label='历史数据')
plt.plot(predictions, label='预测数据', color='red')
plt.legend()
plt.show()

4.5 季节性自回归差分移动平均模型SARIMA

是在ARIMA模型的基础上增加了季节性成分,用于处理具有季节性波动的时间序列,公式:

from statsmodels.tsa.statespace.sarimax import SARIMAX
import matplotlib.pyplot as plt

# 建立SARIMA(p, d, q)(P, D, Q, m)模型
p, d, q = 1, 1, 1  # 非季节性部分
P, D, Q, m = 1, 1, 1, 12  # 季节性部分(假设季节周期为12)
model = SARIMAX(data['value'], order=(p, d, q), seasonal_order=(P, D, Q, m))
model_fit = model.fit()

# 预测
predictions = model_fit.predict(start=len(data), end=len(data)+10)

# 可视化
plt.plot(data['value'], label='历史数据')
plt.plot(predictions, label='预测数据', color='red')
plt.legend()
plt.show()

五、ARIMA模型

ARIMA = AR(自回归) + I(差分) + MA(移动平均)

同时解决了历史时间序列对当前的影响(自回归),时间序列的不平稳问题(差分和移动平均)

Yt​=ϕ1​Yt−1​+ϕ2​Yt−2​+⋯+ϕp​Yt−p​+ϵt​+θ1​ϵt−1​+θ2​ϵt−2​+⋯+θq​ϵt−q​

Yt′​=Yt​−Yt−d

  • p:自回归的阶数,表示用多少个过去值来预测当前值
  • d:差分阶数,表示需要几次差分操作来使序列平稳
  • q:移动平均部分的阶数,表示使用多少个过去的误差项
  • ϕ和θ都是回归模型的参数结果

1、建模过程

(1)观察自己的时间序列数据

  • 周末订单比工作日低,因为工作日有很多规律骑行的需求,周末较少
  • 今年的订单普遍比去年高,因为投车数量多了很多,人均骑行频次基本没变化
  • 订单呈现季节性趋势,冬夏极端天气下订单少,春秋气候适宜订单多
  • 有明显的寒暑假趋势,因为学生骑行订单占一定比例

为什么要把背后的业务也一起解读出来?

  • 第一个原因是当你建模的时候,模型的调整方向,背后是否是能被解释的?
  • 第二个原因是当你要解读结果的时候,结果是否符合业务逻辑?

所以建模第一步需要充分了解你的数据和背景

(2)确定公式&参数

如何确定到底选择几级差分,和自回归的阶数呢?通常情况下看两个指标:ACF、PACF

2、开始建模

  • 导入必要的库
  • 需要用到 statsmodels 的 ARIMA 模型以及 pandas 来处理数据。
  • 加载数据
  • 通常,你会有一个时间序列数据集,这个数据需要按时间顺序排列。
  • 指定 ARIMA 模型的参数
  • 参数 p 是自回归部分的阶数,d 是差分阶数,q 是移动平均部分的阶数。
  • 拟合模型
  • 使用 ARIMA 函数并传入数据和参数 p、d、q,然后使用 fit() 方法拟合模型。
  • 模型诊断和评估
  • 通过查看模型的 AIC/BIC 值、残差分析等,评估模型的性能。
  • 预测未来值
  • 使用拟合后的模型进行预测,得到未来的预测值。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.arima.model import ARIMA

# 生成模拟时间序列数据
np.random.seed(42)
date_range = pd.date_range(start='2023-01-01', periods=180, freq='D')
order_count = 50 + 10 * np.sin(2 * np.pi * date_range.dayofyear / 365) + np.random.normal(size=len(date_range))

# 创建时间序列 DataFrame
data = pd.DataFrame({'Date': date_range, 'Orders': order_count})
data.set_index('Date', inplace=True)

# 设定 ARIMA 模型的参数 p, d, q
p = 2  # 自回归阶数
d = 1  # 差分阶数
q = 2  # 移动平均阶数

# 构建 ARIMA 模型
model = ARIMA(data['Orders'], order=(p, d, q))

# 拟合模型
model_fit = model.fit()

# 打印模型拟合结果
print(model_fit.summary())

# 预测未来 10 天的数据
forecast_steps = 10
forecast = model_fit.forecast(steps=forecast_steps)

# 打印预测结果
print(f"未来 {forecast_steps} 天的预测值: \n", forecast)

# 可视化预测结果
plt.figure(figsize=(10, 6))
plt.plot(data.index, data['Orders'], label='Historical Data')
plt.plot(pd.date_range(start=data.index[-1], periods=forecast_steps+1, freq='D')[1:], forecast, label='Forecast', color='red')
plt.title('ARIMA Model Forecast')
plt.xlabel('Date')
plt.ylabel('Orders')
plt.legend()
plt.show()

模型系数

  • ar.L1 = -1.0292:表示一阶自回归项的系数,负值表明当前值和滞后一期的值之间有负相关性,且影响较强。
  • ar.L2 = -0.2363:表示二阶自回归项的系数,较小的负值表明滞后两期的值对当前值的影响较小。
  • ma.L1 = 0.2647:表示一阶移动平均项的系数,正值表明一阶误差项对当前值有一定的正向影响。
  • ma.L2 = -0.5117:表示二阶移动平均项的系数,负值表明滞后两期的误差对当前值有较大的负面影响。

拟合模型之后,需要检查残差。残差应该表现为白噪声,即没有显著的自相关性。如果残差有显著的自相关性,说明模型可能拟合得不够好,需要重新调整参数 p、d、q。

可以使用 plot_acf() 或 plot_pacf() 来检查残差的自相关性,并通过 model_fit.resid 获取残差。

from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

# 绘制残差的自相关图
residuals = model_fit.resid
plt.figure(figsize=(10, 6))
plt.subplot(211)
plot_acf(residuals, ax=plt.gca())
plt.title('ACF of Residuals')

plt.subplot(212)
plot_pacf(residuals, ax=plt.gca())
plt.title('PACF of Residuals')

plt.tight_layout()
plt.show()

但是,在实际中,建模结果很难直接使用。主要是因为:一方面,纯粹的自回归模型缺乏业务指标,对业务方来说可能只是看一下的结果,很难实际运用;第二个,订单预测的结果很难直接投入使用,因为缺乏达到预测的策略路径。

解决方案:

  1. 给模型添加外生变量,解决第一个问题,即量化出业务指标对结果的影响
  2. 将模型的预测结果作为结果的一种,辅佐其他结果来用于目标制定的场合

扩展:ARIMAX 模型(带外生变量的 ARIMA 模型)是 ARIMA 模型的扩展。在模型中引入了外部变量 Xt​,这些变量被认为是影响目标变量 Yt​ 的额外信息。ARIMAX 模型的公式如下:

Yt​=ϕ1​Yt−1​+ϕ2​Yt−2​+⋯+ϕp​Yt−p​+θ1​ϵt−1​+θ2​ϵt−2​+⋯+θq​ϵt−q​+β1​Xt​+β2​Xt−1​+⋯+ϵt​(其实就是在移动平均那边加了一个X序列)

# 生成模拟时间序列数据
np.random.seed(42)
date_range = pd.date_range(start='2023-01-01', periods=180, freq='D')
order_count = 50 + 10 * np.sin(2 * np.pi * date_range.dayofyear / 365) + np.random.normal(size=len(date_range))
rainfall = np.random.randint(0, 20, size=len(date_range))  # 模拟降雨量数据作为外生变量

# 创建DataFrame
data = pd.DataFrame({'Date': date_range, 'Orders': order_count, 'Rainfall': rainfall})
data.set_index('Date', inplace=True)

# 设定 ARIMA 模型的参数 p, d, q
p = 2
d = 1
q = 2

# 将降雨量作为外生变量X加入模型
model = ARIMA(data['Orders'], order=(p, d, q), exog=data[['Rainfall']])

# 拟合模型
model_fit = model.fit()

# 打印模型结果
print(model_fit.summary())

# 预测未来 10 天的订单量(假设未来10天的降雨量)
future_rainfall = np.random.randint(0, 20, size=10)
forecast = model_fit.forecast(steps=10, exog=future_rainfall)

综合,需要用统计学的知识,把业务结果+常规的时间序列处理一起整合起来,给到老板一个更明确的答案:(建模过程)

数据为什么是那么波动的,未来预估大概由多少,为什么和现在预估有差别,背后是业务数据的什么变化,给到业务什么指导等。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐