You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python基于时间序列PSD/FFT自动判定不存在季节性?

基于PSD/FFT自动判定时间序列无季节性的实现方案

核心判定逻辑

针对高斯噪声、单脉冲这类无季节性的信号,和存在周期性的信号的PSD特征差异,可通过以下几个可量化的规则自动判定:

  • 先排除直流分量干扰:频率为0的分量对应信号均值,和季节性无关,计算峰值前先过滤掉freqs < 1/len(y)的区间,避免直流分量干扰峰值判断
  • 计算峰值突出度:取排除直流后的PSD最大值,和同区间PSD的中位数做差。高斯噪声的PSD是近似平坦的白谱,单脉冲的PSD是缓慢下降的sinc谱,两者的峰值突出度普遍低于10dB;存在显著季节性的信号峰值突出度通常在12dB以上
  • 校验峰值孤立性:对筛选出的最高PSD峰值,检查其前后相邻3~5个频率点的PSD差值,如果最大差值小于3dB,说明是宽峰(单脉冲、噪声随机波动都属于这类),不属于周期性信号的窄尖峰
  • 可选合理性校验:计算得到的周期长度不能超过序列总长度的1/2,否则属于无统计意义的假周期,直接判定为无季节性

补全后的可运行代码

import numpy as np

def psd_time_series(y):
    # 修正原代码变量大小写、括号缺失问题
    y_demean = y - np.mean(y)
    yAC = np.correlate(y_demean, y_demean, mode='full')
    yAC = yAC / np.max(yAC)
    fft_yAC = np.fft.fft(yAC)
    freqs = np.arange(0, len(fft_yAC)) / len(fft_yAC)
    psd = 10 * np.log10(np.abs(fft_yAC) / max(np.abs(fft_yAC)))
    return psd, freqs

def determine_if_seasonal(psd, freqs, seq_len):
    # 1. 过滤直流分量和超低频分量(周期超过序列长度一半的无意义)
    valid_mask = (freqs >= 2 / seq_len) & (freqs <= 0.5)
    valid_psd = psd[valid_mask]
    valid_freqs = freqs[valid_mask]
    if len(valid_psd) < 5:
        # 序列过短无法判断,直接返回无季节性
        return False, None
    
    # 2. 找最高峰值
    max_psd_idx = np.argmax(valid_psd)
    max_psd = valid_psd[max_psd_idx]
    median_psd = np.median(valid_psd)
    
    # 3. 峰值突出度校验,经验阈值10dB,可根据自己的数据集调整
    if (max_psd - median_psd) < 10:
        return False, None
    
    # 4. 峰值孤立性校验,检查前后2个点的差值
    left = max(max_psd_idx - 2, 0)
    right = min(max_psd_idx + 2, len(valid_psd)-1)
    neighbor_mean = np.mean(np.concatenate([valid_psd[left:max_psd_idx], valid_psd[max_psd_idx+1:right+1]]))
    if (max_psd - neighbor_mean) < 3:
        return False, None
    
    # 所有校验通过,判定为有季节性
    return True, valid_freqs[max_psd_idx]

def detect_seasonality(y):
    psd, freqs = psd_time_series(y)
    seasonality, peak_freq = determine_if_seasonal(psd, freqs, len(y))
    if seasonality:
        periodicity = round(1 / peak_freq)
        # 额外校验周期不能超过序列长度的1/2
        if periodicity > len(y)//2:
            return None
        return periodicity
    else:
        return None

阈值调整建议

你可以根据自己的数据集特性调整两个核心阈值:

  • 若你的序列普遍噪声较高,可把峰值突出度阈值下调到8~9dB,降低漏判率
  • 若你对假阳性(把噪声误判为有季节性)容忍度低,可把峰值突出度阈值上调到15~18dB,提升判定严格度
  • 峰值孤立性校验的相邻点范围,可以根据序列长度调整,最长不超过总频率点的2%即可

内容的提问来源于stack exchange,提问作者kspr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 23:24:02