特征工程:时域特征、频域特征、统计特征
特征工程这件事,说白了你得跟数据“混熟”。我刚做异常检测那会儿,上来就怼深度学习模型,结果效果奇差。后来发现,问题是特征没选对。你想想看,传感器采集的原始波形,里面藏着大量信息,你不把它提炼出来,模型连看都看不懂。
我个人习惯第一步先画时序图。眼睛扫一遍,基本能判断这组数据有没有明显的周期、突变、或者漂移。然后我再决定从哪个域去挖特征。今天我们就聊三个最常用的域:时域、频域、统计特征。
时域特征:最直观,但也最容易漏
时域特征就是直接在时间轴上算各种值。平均值、方差、最大值、最小值,这些太基础了,但千万别因为基础就小看它。我记得有次在振动数据里,异常点恰恰是均值没有变化、而峰峰值突然翻倍。如果只盯着均值,你可能永远抓不到它。
我建议你至少包含这几项:
- 峰值(Peak):最大值与最小值之差,对冲击型异常非常敏感。
- 有效值(RMS):反应信号的总体能量水平,平稳型异常看它。
- 过零率(Zero Crossing Rate):单位时间内信号穿越零点的次数。频率信息的一种廉价替代。
- 波形因子:RMS 与整流平均值的比值。我在电机故障检测中经常用。
import numpy as np
def extract_time_features(signal):
peak = np.max(signal) - np.min(signal)
rms = np.sqrt(np.mean(signal**2))
zcr = np.sum(np.diff(np.sign(signal)) != 0) / len(signal)
# 波形因子
form_factor = rms / np.mean(np.abs(signal))
return {'peak': peak, 'rms': rms, 'zcr': zcr, 'form_factor': form_factor}
频域特征:周期异常无处遁形
频谱分析是我个人觉得很“性感”的一块。时域里混在一起的不同频率成分,到了频域里像分垃圾一样清清楚楚。异常很多时候就是某些频率分量突然变强或变弱。比如机器轴承磨损,高频段能量就会明显上升。
怎么做?先对窗口数据做 FFT,得到幅值谱或功率谱。
def extract_freq_features(signal, fs=1000):
n = len(signal)
fft_vals = np.fft.rfft(signal)
freqs = np.fft.rfftfreq(n, d=1/fs)
mag = np.abs(fft_vals)
# 谱能量
total_energy = np.sum(mag**2)
# 主频
peak_freq = freqs[np.argmax(mag)]
# 高频段能量占比(例如 > 200Hz)
high_energy = np.sum(mag[freqs > 200]**2)
return {'total_energy': total_energy, 'peak_freq': peak_freq,
'high_ratio': high_energy / (total_energy + 1e-12)}
这里有个经验:窗口长度选 2 的幂次(如 256, 512, 1024),并且使用汉宁窗减少频谱泄露。我曾经因为没用窗函数,导致两个相近频率的异常直接被漏掉。
统计特征:老司机最爱
统计特征不依赖时序,把数据当集合看。偏度(Skewness)告诉你分布是否左偏或右偏,峰度(Kurtosis)告诉你尾部有多厚。在异常检测里,峰度是“神级”特征——很多异常事件会让数据产生极值,峰度瞬间飙高。
除了经典的四阶矩,我还会加两个东西:
- 四分位距(IQR):Q3 - Q1,对离群值鲁棒,比标准差更稳。
- 滑动窗口熵(Sliding Entropy):窗口内数据的随机程度。如果信号突然变得规律,熵会下降,这本身就是一种异常。
def extract_stat_features(signal):
from scipy.stats import skew, kurtosis
skewness = skew(signal)
kurt = kurtosis(signal) # 超额峰度
q1, q3 = np.percentile(signal, [25, 75])
iqr = q3 - q1
# 离散熵(将值离散化为10个bin)
hist, _ = np.histogram(signal, bins=10, density=True)
hist = hist[hist > 0]
entropy = -np.sum(hist * np.log2(hist))
return {'skew': skewness, 'kurtosis': kurt, 'iqr': iqr, 'entropy': entropy}
特征选择:别什么都往里塞
提取完一大堆特征,直接喂给模型?我劝你别急。特征太多反而会引入噪声。我会先做一次相关性分析,把高度相关的特征(>0.95)去掉,然后用互信息或随机森林重要性排序,选 top-K 个。
| 特征 | 相关性(与异常标签) | 我是否保留 |
|---|---|---|
| RMS | 0.72 | 保留 |
| 峰度 | 0.81 | 保留 |
| 峰值频率 | 0.33 | 按需 |
| 均值 | 0.12 | 丢弃 |
嗯,特征工程就聊到这里。记住,时域看幅度突变,频域看周期变化,统计看分布形状。三管齐下,异常基本无处可逃。