Python中时间序列互相关系数超[-1,1]范围的原因及解决办法
问题根源:计算方法错误,与数据集无关
你得到的结果超出-1到1范围,是因为scipy.signal.correlate返回的是未归一化的互相关原始值,不是你需要的互相关系数。同时你的代码里存在重复去均值、错误归一化的问题,导致结果异常。
代码中的错误点
- 重复去均值:已经对序列做了
wl=w_sub['a'] - np.mean(w_sub['a']),后续又计算wl-np.mean(wl),此时序列均值已经为0,重复操作无意义。 - 错误的归一化方式:用
np.max(wl)做归一化不是标准化操作,无法让序列方差为1,后续互相关值的尺度会失控。 - 未对互相关结果归一化:原始互相关值的大小取决于序列能量,必须经过归一化处理才能得到范围在-1到1的系数。
修正后的实现
方法一:手动归一化(兼容所有scipy版本)
import numpy as np import pandas as pd import matplotlib.pyplot as plt from dateutil.relativedelta import relativedelta from scipy import signal np.random.seed(1) tidx = pd.date_range('1975-01-01', periods=36, freq='MS') tim=pd.to_datetime(tidx) df_t=pd.DataFrame(tim, columns=['time']) p1=pd.DataFrame([13, 17, 13, 15, 9, 9, 16, 11, 11, 16, 11, 10, 23, 19, 23, 9, 3, 6, 4, 27, 8, 16, 26, 17, 16, 15, 16, 8, 36, 9, 9, 11, 11, 16, 7, 5], columns=['a']) p2=pd.DataFrame([1182.7,1191.5,1206.1,1259.6,1351.2,1473.2,1531.6,1531.2,1531.4,1530.7,1527.8,1526.9, 1526.9, 1520.3, 1511.9, 1501.7, 1491.7, 1516.8, 1526.1, 1541.7, 1541.7, 1530.7, 1518.4, 1490.6, 1479.1, 1465.4, 1409.1, 1329.5, 1302.4, 1379.2, 1520.9, 1545.6, 1550.0, 1539.1, 1498.7, 1468.4],columns=['b']) df_final=pd.concat([df_t, p1, p2], axis=1) fig, ax1 = plt.subplots(figsize=(10,4), sharey=False, dpi=300) t1=df_final['time'].iloc[0] cr=[] for i in range(0, 36, 12): t2=t1+relativedelta(months=i) t3=t1+ relativedelta(months=i+12) sub=df_final[(df_final.time>=t2) & (df_final.time<t3)] w_sub=sub['a'] e_sub=sub['b'] # 正确标准化:去均值后除以标准差,使序列方差为1 wl = (w_sub - w_sub.mean()) / w_sub.std() eq = (e_sub - e_sub.mean()) / e_sub.std() # 计算未归一化互相关 corr_raw = signal.correlate(wl, eq, mode='same', method='direct') # 归一化得到互相关系数:除以序列长度(适配mode='same'的有效样本量) corr_coeff = corr_raw / len(wl) cr.append(corr_coeff) cc=pd.DataFrame(cr) ccc=np.mean(cc) lags = signal.correlation_lags(len(w_sub), len(e_sub), mode="same") ax1.plot(lags, ccc, 'red') ax1.set_ylim(-1, 1) # 强制显示-1到1范围,验证结果 plt.show()
方法二:使用scipy内置归一化(scipy 1.7.0+支持)
直接利用signal.correlate的normalize参数,自动完成归一化:
# 替换互相关计算部分 corr_coeff = signal.correlate(wl, eq, mode='same', method='direct', normalize='full')
normalize='full'会用两个序列的L2范数乘积做归一化,确保结果在-1到1之间。
关键说明
- 互相关系数的核心是归一化的互相关值,必须保证输入序列是标准化(去均值+除以标准差)的,或者对原始互相关结果做归一化处理。
signal.correlation_lags返回的滞后值范围是-5到6(12个点),不是你之前用的0到11,修正后才能正确对应滞后关系。
内容的提问来源于stack exchange,提问作者danial
相关产品推荐
相关产品推荐

