一段代码:
python
y = np.concatenate([
np.random.normal(0, 0.5, 100), # 低波动
np.random.normal(0, 3.0, 50), # 高波动
np.random.normal(0, 0.5, 100) # 低波动
])
window = 20
rolling_std = np.array([np.std(y[max(0,i-window+1):i+1]) for i in range(len(y))])
plt.figure(figsize=(10, 4))
plt.plot(rolling_std, color='orange')
plt.title('Rolling std dev')
plt.xlabel('index')
plt.ylabel('std')
这段代码实现的是滚动标准差 (Rolling Standard Deviation),也叫移动标准差 。让我详细解释它的原理和物理含义:
补充:方差 标准差计算公式

代码解析
python
window = 20
rolling_std = np.array([np.std(y[max(0,i-window+1):i+1]) for i in range(len(y))])
核心逻辑 :对于每个位置 i,计算过去 window 个数据点的标准差:
-
当
i < window-1时(数据不足20个):- 切片从
0开始,只取i+1个数据 - 这是部分窗口(前向填充)
- 切片从
-
当
i >= window-1时:- 切片从
i-window+1到i+1,正好window个数据 - 这是完整窗口
- 切片从
物理含义
1. 波动性的动态监测
滚动标准差衡量的是局部波动性,而不是整体波动:
- 低滚动标准差:最近的数据点都很接近均值 → 市场平稳/信号稳定
- 高滚动标准差:最近的数据点剧烈波动 → 市场动荡/信号变化剧烈
2. 实际应用场景
| 领域 | 应用 |
|---|---|
| 金融 | 波动率计算(如 Bollinger Bands)、风险管理 |
| 信号处理 | 检测信号突变点、噪声水平估计 |
| 质量控制 | 监测生产过程的稳定性 |
| 气象学 | 温度/气压的短期波动分析 |
3. 与整体标准差的对比
python
# 整体标准差(全局视角)
global_std = np.std(y) # 一个值,描述整体波动
# 滚动标准差(局部视角)
rolling_std = [...] # 一系列值,描述波动随时间的变化
例子:
- 整体标准差可能很大(因为包含所有波动)
- 但滚动标准差可以告诉你:什么时候波动大,什么时候波动小
改进建议
1. 正确处理边界(避免部分窗口混淆)
python
window = 20
rolling_std = np.array([
np.std(y[i-window+1:i+1]) if i >= window-1 else np.nan
for i in range(len(y))
])
用 nan 代替前几个不完整的窗口,更清晰。
2. 使用 Pandas(更高效、更简洁)
python
import pandas as pd
rolling_std = pd.Series(y).rolling(window=20).std().values
Pandas 默认 ddof=1(样本标准差),如需总体标准差:
python
rolling_std = pd.Series(y).rolling(window=20).std(ddof=0).values
3. NumPy 向量化版本(更快)
python
def rolling_std_numpy(y, window):
# 使用卷积或 cumsum 实现,比列表推导快很多
cumsum = np.cumsum(y)
cumsum_sq = np.cumsum(np.square(y))
# 计算窗口和
sum_win = cumsum[window-1:] - np.append([0], cumsum[:-window])
sum_sq_win = cumsum_sq[window-1:] - np.append([0], cumsum_sq[:-window])
# 计算均值和方差
mean_win = sum_win / window
var_win = sum_sq_win / window - mean_win**2
# 添加 NaN 填充前 window-1 个位置
return np.concatenate([np.full(window-1, np.nan), np.sqrt(var_win)])
可视化示例
python
import numpy as np
import matplotlib.pyplot as plt
# 生成数据:平稳 + 高波动 + 平稳
np.random.seed(42)
y = np.concatenate([
np.random.normal(0, 0.5, 100), # 低波动
np.random.normal(0, 3.0, 50), # 高波动
np.random.normal(0, 0.5, 100) # 低波动
])
window = 20
rolling_std = pd.Series(y).rolling(window).std()
plt.figure(figsize=(12, 6))
plt.subplot(2,1,1)
plt.plot(y, alpha=0.7)
plt.title('原始数据')
plt.ylabel('值')
plt.grid(True)
plt.subplot(2,1,2)
plt.plot(rolling_std, color='orange')
plt.axhline(y=np.std(y), color='red', linestyle='--', label=f'全局标准差 = {np.std(y):.2f}')
plt.title('滚动标准差 (window=20)')
plt.xlabel('索引')
plt.ylabel('标准差')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
输出效果:
- 前100个点:滚动标准差 ~0.5
- 中间50个点:滚动标准差 ~3.0(明显升高,捕捉到波动增加)
- 后100个点:滚动标准差 ~0.5(回降,检测到波动减小)
关键要点
- 滚动标准差 ≠ 整体标准差 :它是时变的,能捕捉局部波动特征
- 窗口大小影响灵敏度 :
- 小窗口(如 5):反应快,但噪声多
- 大窗口(如 50):反应慢,但更平滑
- 物理意义 :衡量"最近的波动能量",是检测变化点 和异常的利器