前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >平滑时间序列数据,别再用移动平均线了

平滑时间序列数据,别再用移动平均线了

作者头像
数据STUDIO
发布2024-08-01 09:02:45
1980
发布2024-08-01 09:02:45
举报
文章被收录于专栏:数据STUDIO
在分析时间序列数据时,去除噪声平滑数据是非常重要的一步,因为噪声会掩盖真实的数据趋势。目前最流行的两种平滑技术是移动平均线和Savitzky-Golay滤波器。虽然移动平均线一直是快速平滑数据的首选方法,但Savitzky-Golay滤波器通常能够更准确地反映数据的真实趋势。

本文将解释为什么Savitzky-Golay滤波器能够比移动平均线更好地平滑时间序列数据,并附带Python代码示例。

时间序列平滑的本质

想象你正在分析传感器数据或股票价格数据,原始数据由于噪声的存在,其起伏波动很大,就像过山车一样。平滑的目的就是抑制这些波动噪声,从而发现潜在的真实数据趋势信号。

加载时间序列数据

我们首先需要导入必要的Python库。

代码语言:javascript
复制
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
from scipy.signal import savgol_filter
import plotly.express as px
from statsforecast import StatsForecast
train = pd.read_csv('https://auto-arima-results.s3.amazonaws.com/M4-Hourly.csv')
test = pd.read_csv('https://auto-arima-results.s3.amazonaws.com/M4-Hourly-test.csv').rename(columns={'y': 'y_test'})
uid = np.array(['H386'])
df_train = train.query('unique_id in @uid')
df_test = test.query('unique_id in @uid')
StatsForecast.plot(df_train, df_test, plot_random = False, engine='plotly')

该时间序列取自 M4 竞赛数据集,我选择这个是因为它具有重复性(季节性)但不平滑的行为

平滑时间序列

平滑窗口大小的重要性

在平滑时间序列数据时,"窗口大小"是一个非常重要的参数,它决定了在任意给定点附近,我们考虑多大范围的数据来进行平滑。这就好比相机镜头的光圈大小 - 光圈越大,捕获的图像画面就越多,从而影响最终图像的清晰度和细节程度。

对于移动平均线来说,窗口大小定义了计算某个平滑点时,需要平均多少个相邻数据点。而对于Savitzky-Golay滤波器,除了能平均数据点外,它还可以将多项式拟合到窗口内的数据,从而在平滑和保留数据细节之间取得平衡。如果你对 Savitzky-Golay 滤波器的详细信息感兴趣,可以阅读: https://inst.eecs.berkeley.edu/~ee123/sp16/docs/SGFilter.pdf。代码如下:

因此,窗口大小对于平滑的效果有着重大影响。选择一个合适的窗口大小是使用这些平滑技术的关键所在。

代码如下:

代码语言:javascript
复制
computed_features = [] # 我稍后需要此列表来绘制 window_size 在 [ 10 , 25 ] 中的平for window_size in [10, 25]:
  df_train.loc[:,f'moving_average_{window_size}'] = df_train['y'].rolling(window=window_size, , center=True).mean()
  df_train.loc[:,f'savgol_filter_{window_size}'] = savgol_filter(df_train['y'], window_size, 2)
  computed_features.append(f'moving_average_{window_size}')
  computed_features.append(f'savgol_filter_{window_size}')

我们计算了原始时间序列的总共 4 个平滑版本,使用窗口大小 10 和 25。

窗口大小为 10

现在让我们看看第一个窗口大小与原始时间序列的结果对比。

代码语言:javascript
复制
fig = px.line(df_train[df_train.ds>500], x='ds', y=['y'] + computed_features[:2], title='Different moving average estimators',
              labels={'Value': 'y', 'Date': 'Date'},
              line_shape='linear')

# Improve layout
fig.update_layout(
    xaxis_title='Date',
    yaxis_title='Sensor Value',
    hovermode='x'
)

fig.show()

使用 Savitzky-Golay 滤波器和移动平均线(窗口大小为 10)的原始和平滑时间序列

移动平均线的缺陷

移动平均线虽然简单,但它存在一些明显的缺陷。首先,它对数据变化的反应相对滞后。当数据趋势发生改变时,移动平均线往往无法及时跟上。

另外,移动平均线在计算时,对窗口内所有数据点的重视程度是完全一样的,忽视了它们之间的细微差别和相关性。

相比之下,Savitzky-Golay滤波器利用最小二乘法,将低阶多项式拟合到局部相邻数据点上,从而能更好地保留原始数据的形状和特征,包括峰值和谷值等重要细节。这些细节在使用移动平均线时可能会被过度平滑掉。

如下图所示,随着窗口大小的增加,Savitzky-Golay滤波器能通过预测峰值的方式,更好地捕捉数据的变化趋势,而移动平均线则往往无法做到这一点。

因此,尽管移动平均线简单易用,但它反应迟钝且容易失去数据细节,这就是它的致命缺陷所在。

窗口大小为 25

正如我们在上图中看到的,Savitzky-Golay 滤波器仍然报告了峰值,这可能是我们想要消除它们的情况。所以让我们看看增加窗口大小是否能得到这个结果。

代码语言:javascript
复制
fig = px.line(df_train[df_train.ds>500], x='ds', y=['y'] + computed_features[2:4], title='Different moving average estimators',
              labels={'Value': 'y', 'Date': 'Date'},
              line_shape='linear')

# Improve layout
fig.update_layout(
    xaxis_title='Date',
    yaxis_title='Sensor Value',
    hovermode='x'
)

fig.show()

使用 Savitzky-Golay 滤波器和移动平均线(窗口大小为 25)的原始和平滑时间序列

在这里,Savitzky-Golay 滤波器非常出色地捕捉了时间序列的季节性,没有延迟,并消除了尖峰,而移动平均线将所有注意力集中在长期平均值上,丢失了信号中包含的许多信息。

结论

总体而言,当窗口大小适当调整时,Savitzky-Golay 滤波器倾向于保持更高的信号保真度,同时消除不必要的尖峰。无论如何,移动平均线仍然可以用于计算时间序列的平均值,即使通过扩大 Savitzky-Golay 滤波器的窗口大小可以获得相同的结果(并且可能具有更好的精度),但如果有兴趣捕捉过程围绕的底层平均值,则可以评估使用它。但对于大多数平滑用例,Savitzky-Golay 滤波器的表现要好得多。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-07-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据STUDIO 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 时间序列平滑的本质
  • 加载时间序列数据
  • 平滑时间序列
    • 平滑窗口大小的重要性
      • 窗口大小为 10
        • 移动平均线的缺陷
          • 窗口大小为 25
          • 结论
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档