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

如何基于模式变化自动分割含活动/休息段的时间序列(Python实现)

时间序列活动/休息段自动分段方案

问题特征

待处理时间序列包含两类长度不固定的片段,固定长度分割方法完全不适用:

  • 活动段:存在稳定的周期振荡特征
  • 休息段:无规律随机波动,无固定模式
    活动-休息-活动分段示例图
    图中竖线为手动标注的分段边界。

方案1:轻量无监督实现(优先推荐)

本方案仅依赖numpy/scipy/scikit-learn,和现有TensorFlow环境完全兼容,不存在Protobuf版本冲突问题,仅需1个弱超参数,鲁棒性极强。

核心原理

周期振荡信号和随机噪声在两个统计维度上有明确、稳定的区分度:

  1. 谱熵差异:周期信号能量集中在少数固定频率,功率谱熵极低;随机无规律信号能量均匀分布在全频段,功率谱熵显著更高
  2. 自相关峰值差异:周期信号的自相关序列在滞后等于周期长度的位置有明显尖锐峰值;随机信号自相关无显著的非零滞后峰值

实现步骤

  1. 滑动窗口长度取数据中最短片段长度的1/2即可;如果提前不知道最短段长度,默认取信号总长度的1%(最小不低于32个采样点),对最终结果影响极小
  2. 逐窗口计算谱熵、自相关峰值高度两个特征
  3. 对二维特征做KMeans二聚类(k=2,无监督无需任何标注),自动标记每个窗口属于活动/休息类别
  4. 对聚类得到的二值标记序列做简单去毛刺:移除长度小于1/2窗口长度的跳变杂点,剩余的类别跳变位置即为分段边界

可直接运行的代码

import numpy as np
from scipy.fft import fft
from scipy.signal import correlate
from sklearn.cluster import KMeans

def calculate_spectral_entropy(window):
    # 计算窗口内信号的功率谱熵
    fft_power = np.abs(fft(window))**2
    fft_power = fft_power[1:]  # 去掉零频直流分量避免偏移干扰
    fft_power = fft_power / fft_power.sum()
    entropy = -np.sum(fft_power * np.log2(fft_power + 1e-12))
    return entropy

def calculate_autocorr_peak(window):
    # 计算窗口内去均值信号的非零滞后自相关最大峰值
    window = window - np.mean(window)
    autocorr = correlate(window, window, mode='full')
    autocorr = autocorr[len(autocorr)//2:]
    autocorr = autocorr[1:] / (autocorr[0] + 1e-12)  # 归一化,跳过零滞后点
    return np.max(autocorr[:len(window)//2])

def detect_segment_boundaries(signal, window_len=None):
    # 未指定窗口长度时自动估计
    if window_len is None:
        window_len = max(32, int(len(signal)*0.01))
    features = []
    for i in range(len(signal) - window_len):
        win = signal[i:i+window_len]
        features.append([
            calculate_spectral_entropy(win),
            calculate_autocorr_peak(win)
        ])
    features = np.array(features)
    # 二分类标记窗口属性
    kmeans = KMeans(n_clusters=2, n_init=10, random_state=42).fit(features)
    labels = kmeans.labels_
    # 提取跳变点作为边界,对齐窗口中心位置
    boundaries = np.where(np.diff(labels) != 0)[0] + window_len//2
    # 过滤间隔过近的假边界
    if len(boundaries) > 1:
        valid_mask = np.concatenate([[True], np.diff(boundaries) > window_len//2])
        boundaries = boundaries[valid_mask]
    return boundaries

调用时直接传入一维时间序列数组,返回值即为所有分段边界对应的X轴坐标。

方案2:零特征工程变点检测实现

如果不想手动编写特征提取逻辑,可以使用专门做时间序列变点检测的ruptures库,该库仅依赖numpy/scipy,无任何版本冲突问题,安装命令:
pip install ruptures
核心代码仅3行,基于径向基核的变点检测可以直接捕捉序列统计特性的突变,不需要手动设计特征:

import ruptures as rpt
algo = rpt.KernelCPD(kernel="rbf", min_size=32).fit(signal.reshape(-1,1))
boundaries = algo.predict(n_bkps=None)  # 自动估计变点数量,无需提前指定分段数

本方法仅有的超参数min_size为允许的最短片段长度,一般设为32~64个采样点即可过滤绝大多数杂波。

其他方案说明

  • 不建议使用CNN回归段长的思路:这类监督方法需要大量手动标注数据,且对不同周期、不同幅值的活动段泛化性差,远不如无监督方法适配本场景
  • 如果确实需要用到Matrix Profile的能力,不需要安装官方库,其核心STOMP矩阵轮廓计算算法仅用NumPy就能在50行代码内实现,完全可以自行编写轻量版本避开依赖冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 14:12:22