数据平滑处理是数据分析流程中非常重要的预处理环节,主要作用是过滤掉数据中的随机噪声和短期波动,凸显数据的长期变化趋势,为后续的建模、预测等工作提供更可靠的数据基础。移动平均法是数据平滑领域最经典、应用最广泛的方法之一,核心思想是用当前时间点及其相邻时间点的数据平均值,替换当前时间点的原始数据,以此达到平滑效果。

移动平均法的常见类型
根据计算平均值时选取的相邻数据范围不同,移动平均法可以分为以下几种常见类型:
- 简单移动平均(SMA):选取固定窗口大小的历史数据,计算算术平均值作为当前点的平滑值,所有数据的权重相同。
- 加权移动平均(WMA):给窗口内的不同位置数据赋予不同权重,通常越靠近当前点的数据权重越高,平滑结果更贴合近期趋势。
- 指数移动平均(EMA):对历史数据赋予指数级递减的权重,不需要固定窗口大小,对近期数据的变化反应更灵敏。
Python实现简单移动平均
简单移动平均是最容易实现的移动平均类型,使用pandas库的rolling方法可以快速完成计算,以下是完整的实现示例:
import pandas as pd
import numpy as np
# 生成模拟的原始数据,包含随机波动
np.random.seed(42)
raw_data = pd.Series(np.random.randn(100).cumsum() + 10)
# 设置移动平均窗口大小,这里选择5
window_size = 5
# 计算简单移动平均,min_periods=1表示窗口内至少有1个数据就计算平均值
sma_result = raw_data.rolling(window=window_size, min_periods=1).mean()
# 打印前10条结果对比
print("原始数据前10条:")
print(raw_data.head(10))
print("n简单移动平均结果前10条:")
print(sma_result.head(10))
上述代码中,rolling(window=window_size)表示创建一个大小为5的滑动窗口,mean()方法会计算每个窗口内数据的平均值。min_periods=1的作用是避免窗口未填满时返回空值,当窗口内只有1个数据时,平滑值就是该数据本身。
Python实现加权移动平均
加权移动平均需要手动定义权重数组,再结合滑动窗口计算加权和,以下是实现代码:
import pandas as pd
import numpy as np
# 使用之前的模拟数据
np.random.seed(42)
raw_data = pd.Series(np.random.randn(100).cumsum() + 10)
# 定义窗口大小为5,权重从远到近依次为1、2、3、4、5
window_size = 5
weights = np.array([1, 2, 3, 4, 5])
# 归一化权重,保证权重和为1
weights = weights / weights.sum()
# 自定义加权移动平均函数
def weighted_moving_average(series, window, weights):
result = []
for i in range(len(series)):
# 获取当前窗口内的数据,不足窗口大小则取全部已有数据
start = max(0, i - window + 1)
window_data = series.iloc[start:i+1]
# 截取对应长度的权重
current_weights = weights[-len(window_data):]
current_weights = current_weights / current_weights.sum()
# 计算加权平均值
weighted_avg = (window_data * current_weights).sum()
result.append(weighted_avg)
return pd.Series(result, index=series.index)
wma_result = weighted_moving_average(raw_data, window_size, weights)
# 打印前10条结果对比
print("原始数据前10条:")
print(raw_data.head(10))
print("n加权移动平均结果前10条:")
print(wma_result.head(10))
Python实现指数移动平均
pandas库已经内置了指数移动平均的实现方法,不需要手动计算权重,使用ewm方法即可,代码如下:
import pandas as pd
import numpy as np
# 使用之前的模拟数据
np.random.seed(42)
raw_data = pd.Series(np.random.randn(100).cumsum() + 10)
# 计算指数移动平均,span参数表示平滑跨度,类似窗口大小的作用
ema_result = raw_data.ewm(span=5, adjust=False).mean()
# 打印前10条结果对比
print("原始数据前10条:")
print(raw_data.head(10))
print("n指数移动平均结果前10条:")
print(ema_result.head(10))
这里的span=5表示平滑效果相当于5期简单移动平均,adjust=False表示使用递归计算方式,结果和常见的指数移动平均公式一致。
不同参数对平滑效果的影响
移动平均的窗口大小(或span参数)是影响平滑效果的核心因素:
- 窗口越小,平滑后的数据越接近原始数据,保留的细节越多,但过滤噪声的效果越弱。
- 窗口越大,平滑效果越明显,数据趋势越平缓,但可能会丢失一些重要的短期变化信息。
实际使用时需要根据数据的特点和分析目标选择合适的参数,比如分析短期波动可以选择较小的窗口,分析长期趋势则可以选择较大的窗口。
注意事项
移动平均法属于滞后性平滑方法,平滑后的数据点会比原始数据滞后一定的周期,窗口越大滞后越明显,在需要实时预测的场景中需要特别注意这个问题。
另外,移动平均法只适合处理平稳或趋势性较强的数据,如果数据存在明显的季节性波动,需要结合季节性分解等方法先做处理,再使用移动平均平滑,否则会得到不符合预期的平滑结果。