4、数据预处理技术:标准化、归一化、差分处理、滚动窗口统计

各位同学,咱们今天聊点实在的。宏观择时信号的质量,很大程度上取决于你喂给模型的数据长什么样。我见过太多人,模型选得花里胡哨,结果数据预处理一塌糊涂,最后跑出来的信号跟随机数没啥区别。

数据预处理,说白了就是给原始数据「洗澡」。把脏的、乱的、不听话的数据,收拾得服服帖帖。咱们这一章就讲四个最常用的手段:标准化、归一化、差分处理、滚动窗口统计。嗯,一个一个来。

核心观点:预处理不是随便选个方法就往上套。你得理解数据本身的特性,再决定用哪种手法。我个人的习惯是:先看分布,再定策略。

数据预处理技术体系 原始宏观数据 标准化 (Z-score) 均值0,标准差1 归一化 (Min-Max) 缩放到[0,1]区间 差分处理 消除趋势与季节性 滚动窗口统计 均值、标准差、分位数 四种方法各有适用场景,需根据数据特性选择

4.1 标准化(Z-score)

标准化,也叫Z-score标准化。公式很简单:(x - mean) / std。处理完之后,数据均值变成0,标准差变成1。

什么时候用?我个人习惯是:当数据分布近似正态,或者你要用线性模型、SVM、PCA这类对尺度敏感的方法时,标准化是首选。

我的经验:我在做宏观因子库的时候,CPI和M2的量级差了好几个数量级。如果不做标准化,模型基本只看M2,CPI直接被忽略。标准化之后,两个因子才能公平竞争。

import pandas as pd
import numpy as np
from sklearn.preprocessing import StandardScaler

# 假设 df 包含宏观数据
scaler = StandardScaler()
df_standardized = pd.DataFrame(
    scaler.fit_transform(df),
    columns=df.columns,
    index=df.index
)

注意:标准化对异常值非常敏感。我曾经处理过一组PMI数据,里面有个异常值,结果标准化之后大部分数据都被压缩到很小的范围。遇到这种情况,我建议先做异常值处理,或者用RobustScaler。

4.2 归一化(Min-Max)

归一化是把数据缩放到[0,1]区间。公式:(x - min) / (max - min)

你想想看,什么时候用归一化更合适?当数据有明确上下界,比如百分比、比率这类指标,归一化就很自然。另外,神经网络通常喜欢输入在0-1之间,这时候归一化也是好选择。

from sklearn.preprocessing import MinMaxScaler

mm_scaler = MinMaxScaler()
df_normalized = pd.DataFrame(
    mm_scaler.fit_transform(df),
    columns=df.columns,
    index=df.index
)

关键区别:标准化不改变数据分布形状,归一化会改变。标准化保留异常值信息,归一化会把异常值拉到边界。选哪个?看你的业务需求。

4.3 差分处理

差分处理,说白了就是算「变化量」。一阶差分:diff = x_t - x_{t-1}。二阶差分:在一阶差分基础上再来一次。

为什么要做差分?因为很多宏观时间序列是非平稳的。GDP、CPI这些数据,长期看都有趋势。直接用原始数据建模,容易出现伪回归。差分之后,趋势被消除,序列变得平稳。

避坑指南:我曾经在构建利率择时信号时,直接用原始利率数据做回归,结果R²高得离谱,但回测一塌糊涂。后来才发现是伪回归。做了差分之后,模型才真正有效。记住:平稳性是时间序列建模的前提。

# 一阶差分
df_diff = df.diff().dropna()

# 二阶差分
df_diff2 = df.diff().diff().dropna()

# 季节性差分(比如月度数据,周期12)
df_seasonal_diff = df.diff(12).dropna()

怎么判断要不要差分?我一般用ADF检验。p值大于0.05,说明序列非平稳,需要差分。

from statsmodels.tsa.stattools import adfuller

result = adfuller(df['GDP_growth'])
print(f'ADF统计量: {result[0]:.4f}')
print(f'p值: {result[1]:.4f}')
# p值 < 0.05 表示平稳

4.4 滚动窗口统计

滚动窗口统计,就是在一个固定大小的窗口内,计算各种统计量。比如滚动均值、滚动标准差、滚动分位数。

这招在宏观择时里特别实用。为什么?因为宏观数据往往有噪音,单期数据波动大。滚动均值可以平滑噪音,让你看到真正的趋势。滚动标准差可以衡量波动率,这在风险控制里是核心指标。

# 滚动窗口统计
window = 12  # 12个月滚动

df['rolling_mean'] = df['CPI'].rolling(window=window).mean()
df['rolling_std'] = df['CPI'].rolling(window=window).std()
df['rolling_max'] = df['CPI'].rolling(window=window).max()
df['rolling_min'] = df['CPI'].rolling(window=window).min()

# 滚动分位数(比如20%分位数)
df['rolling_q20'] = df['CPI'].rolling(window=window).quantile(0.2)

实战技巧:我在做宏观择时信号时,经常用滚动Z-score。公式是 (当前值 - 滚动均值) / 滚动标准差。这个指标能告诉你当前数据相对于近期历史是偏高还是偏低。比如滚动Z-score大于2,说明当前值异常高,可能是卖出信号。

# 滚动Z-score
df['rolling_zscore'] = (
    df['CPI'] - df['CPI'].rolling(window=window).mean()
) / df['CPI'].rolling(window=window).std()

注意:滚动窗口大小的选择很关键。窗口太小,噪音大;窗口太大,反应迟钝。我一般会试3个月、6个月、12个月,看哪个窗口在回测中表现最好。没有标准答案,得根据数据频率和策略周期来定。

4.5 四种方法的对比与选择

方法 适用场景 优点 缺点
标准化 线性模型、PCA、数据近似正态 保留分布形状,不受量纲影响 对异常值敏感
归一化 神经网络、有界数据 简单直观,有明确区间 改变分布,异常值被压缩
差分处理 非平稳时间序列 消除趋势,获得平稳性 丢失长期信息
滚动窗口统计 平滑噪音、衡量波动 捕捉局部特征,实用性强 窗口大小需调参

嗯,四种方法讲完了。其实在实际项目中,我经常组合使用。比如先差分消除趋势,再标准化消除量纲,最后用滚动窗口统计生成特征。你想想看,这样一套组合拳下来,数据质量能提升不少。

最后说一句:数据预处理没有银弹。多试、多对比、多思考,才是正道。

专注资料整理