时间序列——移动平均(SMA、EMA、WMA)

如果时间序列存在季节性,可以考虑进行季节性调整以消除这种周期性的影响,使数据更具有稳定性和可预测性

1. 季节性调整方法

  • 移动平均:

使用移动平均方法平滑时间序列数据,以减少季节性的波动

  • 季节 性分解:

使用季节性分解 方法,如加法模型或乘法模型,将时间序列分解成趋势、季节性和残差。 这样可以更清晰地了解季节性的影响,并有助于进一步的调整

  • 差分:

对时间序列进行差分是一种常见的方法。 可以计算一阶差分(对当前值减去前一个值),或者更高阶的差分,以减少季节性的影响。 差分后的序列可能更为稳定,更适合建模

  • 季节性调整模型:

使用专门设计用于处理季节性的模型,如SARIMA、Prophet、XGBoost和LightGBM等集成模型, 这些模型考虑了季节性的影响,并可以在建模过程中进行调整

  • 季节性指数:

计算季节性指数,以了解每个季节的相对影响。 然后,可以将这些指数应用到原始数据中,以进行季节性调整

  • 回归模型:

如果季节性是由特定因素引起的,可以考虑使用回归模型,将这些因素纳入考虑,并从时间序列中移除 它们的影响

选择合适的方法取决于数据的性质和季节性的特点。在进行调整之前,最好先对数据进行详细的分析,以确保选择的方法是合适的

2. 代码实例

2.1 具有季节性的时间序列数据生成


          
import numpy as np
          
import matplotlib.pyplot as plt
          
plt.rcParams['font.sans-serif'] = 'SimHei' # 设置中文显示
          
plt.rcParams['axes.unicode_minus'] = False
          

          
# 设置时间周期和数据点数
          
period = 12
          
size = 120
          

          
# 设置两个幅度参数
          
beta1 = 0.3
          
beta2 = 0.6
          

          
# 生成一个包含正弦和余弦值的数组
          
sin1 = np.asarray([np.sin(2 * np.pi * i / 12) for i in np.arange(1, size + 1)])
          
cos1 = np.asarray([np.cos(2 * np.pi * i / 12) for i in np.arange(1, size + 1)])
          

          
# 生成随机游走数据
          
xt = np.cumsum(np.random.normal(scale=0.1, size=size))
          

          
# 生成包含趋势、正弦和余弦成分以及噪声的时间序列
          
series_det = xt + beta1 * sin1 + beta2 * cos1 + np.random.normal(scale=0.1, size=size)
          

          
# 可视化不平稳数据
          
plt.figure(figsize=(15,5 ),dpi=300)
          
plt.plot(series_det,color = 'c')
          
plt.title('时间序列数据')
          
plt.xlabel('Time')
          
plt.ylabel('Value')
          
plt.show()
      

picture.image

2.2 移动 平均

2.2.1 简单移动平均值(SMA)


          
def simple_moving_average(data, window_size):
          
    """
          
    计算简单移动平均值
          

          
    参数:
          
    - data: 包含时间序列数据的列表或数组
          
    - window_size: 移动平均的窗口大小(时期数)
          

          
    返回:
          
    - 移动平均值的列表,长度为 len(data) - window_size + 1
          
    """
          
    sma_values = []
          

          
    for i in range(len(data) - window_size + 1):
          
        window_data = data[i:i + window_size]
          
        sma = sum(window_data) / window_size
          
        sma_values.append(sma)
          

          
    return sma_values
          

          
window_size = 10
          
result = sliding_average(series_det, window_size)
          

          
# 可视化不平稳数据
          
plt.figure(figsize=(15,5 ),dpi=300)
          
plt.plot(series_det, color = 'c', label='原始数据')
          
plt.plot(range(window_size-1,len(series_det)),result, color = 'r', label=f'滑动平均后数据 (窗口大小={window_size})')
          
plt.title('时间序列数据')
          
plt.xlabel('Time')
          
plt.ylabel('Value')
          
plt.legend()
          
plt.show()
      

picture.image

简单移动平均是一种用于平滑时间序列数据的方法,其公式为:

其中:

  • 是时间序列数据点
  • 是计算平均值的时期数,即移动平均的窗口大小

2.2.2 指数 移动平均(EMA)


          
def calculate_ema_with_n(data, n):
          
    """
          
    计算指数移动平均(EMA)
          

          
    参数:
          
    - data: 包含价格数据的列表
          
    - n: 时间周期,用于计算平滑指数 alpha,通常是 alpha = 2 / (n + 1)
          

          
    返回值:
          
    - ema_values: 包含指数移动平均值的列表
          
    """
          
    alpha = 2 / (n + 1)
          
    ema_values = [data[0]]  # 初始值为第一个数据点
          

          
    for i in range(1, len(data)):
          
        ema = alpha * data[i] + (1 - alpha) * ema_values[-1]
          
        ema_values.append(ema)
          

          
    return ema_values
          

          

          
n = 10
          
result_ema = calculate_ema_with_n(series_det, n)
          

          
# 可视化不平稳数据
          
plt.figure(figsize=(15,5 ),dpi=300)
          
plt.plot(series_det, color = 'c', label='原始数据')
          
plt.plot(result_ema, color = 'r', label=f'移动平均后数据 (窗口大小={n})')
          
plt.title('时间序列数据')
          
plt.xlabel('Time')
          
plt.ylabel('Value')
          
plt.legend()
          
plt.show()
      

picture.image

指数移动平均,是以指数式递减加权的移动平均,各数值的加权影响力随时间而指数式递减,越近期的数据加权影响力越重,但较旧的数据也给予一定的加权值,其计算公式如下:

其中:

  • 是时间 的 值
  • 是时间 的数据
  • 是平滑指数,通常通过公式 计算,其中 是选中的时间周期

需要注意的是,计算EMA时需要提供一个初始值,通常选择最初的移动平均值或第一个数据作为初始值,在这选中的是第一个数据

周期为15时的滑动窗口对应的权重系数


          
def plot_ema_weights(n):
          
    alpha = 2 / (n + 1)
          
    weights = [alpha * (1 - alpha)**i for i in range(n)]
          

          
    plt.bar(range(1, n+1), weights)
          
    plt.xlabel('时间步')
          
    plt.ylabel('权重系数')
          
    plt.title(f'EMA权重系数(周期={n})')
          
    plt.show()
          

          
# 以周期为15为例
          
plot_ema_weights(15)
      

picture.image

各数值的加权按指数递减,而非线性递减,理论上这是一个无穷级数,后面的数值会越来越小

2.2.3 加权 移动平均(WMA)


          
def weighted_moving_average_sequence(data, T):
          
    """
          
    计算加权移动平均(WMA)序列
          

          
    参数:
          
    - data: 包含时间序列数据的列表,最新的数据位于列表末尾
          
    - T: 时间周期
          

          
    返回:
          
    - 包含加权移动平均值序列的列表
          
    """
          

          
    if len(data) < T:
          
        raise ValueError("数据点数量应不小于时间周期 T")
          

          
    weights = list(range(1, T + 1))
          
    denominator = T * (T + 1) / 2
          

          
    wma_sequence = []
          
    for i in range(T, len(data) + 1):
          
        wma_sum = sum(w * p for w, p in zip(weights, data[i - T:i]))
          
        wma = wma_sum / denominator
          
        wma_sequence.append(wma)
          

          
    return wma_sequence
          

          
T = 10
          
result_wma = weighted_moving_average_sequence(series_det, T)
          

          
# 可视化不平稳数据
          
plt.figure(figsize=(15,5 ),dpi=300)
          
plt.plot(series_det, color = 'c', label='原始数据')
          
plt.plot(range(T-1,len(series_det)),result_wma, color = 'r', label=f'移动平均后数据 (时间周期大小={n})')
          
plt.title('加权移动平均')
          
plt.xlabel('Time')
          
plt.ylabel('Value')
          
plt.legend()
          
plt.show()
      

picture.image

指计算平均值时将个别数据乘以不同数值,在技术分析中,n日WMA的最近期一个数值乘以n、次近的乘以n-1,如此类推,一直到0,其计算公式如下:

其中:

  • 是在时间 处的加权移动平均值
  • 是时间 的数据
  • 是时间周期

周期为15时的滑动窗口对应的权重系数


          
def plot_weight_coefficients(T, weights):
          
    """
          
    绘制周期为 T 时的权重系数柱状图
          

          
    参数:
          
    - T: 时间周期
          
    - weights: 权重系数列表
          
    """
          
    plt.bar(range(1, T+1), weights[::-1])  # 反转列表以正确显示权重递减
          
    plt.xlabel('时间点')
          
    plt.ylabel('权重系数')
          
    plt.title(f'周期为 {T} 时的权重系数')
          
    plt.show()
          

          
# 示例用法
          
T = 15
          
weights = list(range(1, T + 1))
          
total_weight = sum(weights)
          
normalized_weights = [w / total_weight for w in weights]
          

          
plot_weight_coefficients(T, normalized_weights)
      

picture.image

加权是随日子远离而线性递减,直至递减至零

2.2 季节性分解

时间序列——季节性检验

2.3 差分

时间序列——平稳性检验

2.4 季节性调整模型

时间序列预测神器Prophet python实现

结论

重点介绍 了 移动平均的三种形式 ,以及它在 时间序列上的运用, 移动平均值是一种用于平滑时间序列数据的统计方法。它通过计算一系列连续数据点的平均值来减少噪音和波动,从而更好地显示数据的趋势,除了移动平均外还存在其它方法进行季节性调整,选择合适的方法取决于数据的性质和季节性的特点

如果你对类似于这样的文章感兴趣。

欢迎关注、点赞、转发~

0
0
0
0
评论
未登录
暂无评论