如何基于模式变化自动分割含活动/休息段的时间序列(Python实现)
时间序列活动/休息段自动分段方案
问题特征
待处理时间序列包含两类长度不固定的片段,固定长度分割方法完全不适用:
- 活动段:存在稳定的周期振荡特征
- 休息段:无规律随机波动,无固定模式

图中竖线为手动标注的分段边界。
方案1:轻量无监督实现(优先推荐)
本方案仅依赖numpy/scipy/scikit-learn,和现有TensorFlow环境完全兼容,不存在Protobuf版本冲突问题,仅需1个弱超参数,鲁棒性极强。
核心原理
周期振荡信号和随机噪声在两个统计维度上有明确、稳定的区分度:
- 谱熵差异:周期信号能量集中在少数固定频率,功率谱熵极低;随机无规律信号能量均匀分布在全频段,功率谱熵显著更高
- 自相关峰值差异:周期信号的自相关序列在滞后等于周期长度的位置有明显尖锐峰值;随机信号自相关无显著的非零滞后峰值
实现步骤
- 滑动窗口长度取数据中最短片段长度的1/2即可;如果提前不知道最短段长度,默认取信号总长度的1%(最小不低于32个采样点),对最终结果影响极小
- 逐窗口计算谱熵、自相关峰值高度两个特征
- 对二维特征做KMeans二聚类(k=2,无监督无需任何标注),自动标记每个窗口属于活动/休息类别
- 对聚类得到的二值标记序列做简单去毛刺:移除长度小于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
相关产品推荐
相关产品推荐

