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

无预定义段数的单变量时间序列无监督分段方法求助

问题描述

我有单变量时间序列数据,需要自动识别出明显的低分值分段(示例数据中存在一个长时段的低分分段),且预先不知道潜在状态的数量。

已尝试的方法:

  • 使用hmmlearn的Gaussian HMM:拟合后的模型经常快速跳离低状态,导致连续低分分段的识别结果不稳定(表现为低状态被频繁打断,无法覆盖完整的低分时段)
  • 临时解决方案:设置较大的n_components值(如10),拟合HMM后合并所有均值小于0.3的状态。该方法能得到正确结果,但缺乏严谨性

我了解过Sticky HMM,但不确定哪种方法最优(非HMM路线是否更合适)。需要一种严谨、可复现的方法,优先尝试简单方案(复杂方法缺乏维护完善的教程和代码示例),希望能提供针对该示例的可运行代码片段。

示例信号生成代码

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(5000)
# 生成模拟信号
y  = 0.12 + 0.02*np.random.randn(5000)                   # 基线噪声
y += 0.6*np.exp(-((x-400)**2)/(2*180**2))                # 左侧大峰值
y += 0.20*np.exp(-((x-1150)**2)/(2*90**2))               # 中部小凸起
y += 0.03*np.sin(x/35)                                   # 小幅波动
y += 0.06*np.sin(x/7) * ((x>3400) & (x<4200))            # 振荡区域
y += 0.75*np.exp(-((x-4700)**2)/(2*120**2))              # 右侧大峰值

# 绘制原始信号
plt.figure(figsize=(14,4))
plt.plot(x, y, linewidth=1.3)
plt.xlim(0, 5000)
plt.ylim(0, 0.85)
plt.tight_layout()
plt.show()

解决方案

方案一:统计阈值+滑动窗口(简单、严谨)

核心思路:基于数据的统计特征设定低分阈值,再用滑动窗口过滤孤立噪声点,保留连续的低分分段,无需假设潜在状态数量。

代码实现

import pandas as pd

# 1. 设定低分阈值:用基线区域的均值+2倍标准差适配噪声
baseline_mask = (y < 0.2)  # 粗略筛选基线区域
baseline_mean = y[baseline_mask].mean()
baseline_std = y[baseline_mask].std()
low_threshold = baseline_mean + 2 * baseline_std  # 阈值可根据需求调整

# 2. 标记初始低分点
is_low = y < low_threshold

# 3. 滑动窗口过滤:仅保留连续N个点以上的低分区域
window_size = 50  # 可根据信号时间尺度调整
is_low_series = pd.Series(is_low)
# 计算窗口内低分点的占比
rolling_ratio = is_low_series.rolling(window=window_size, center=True).mean()
# 保留占比>0.8的窗口区域(认为是连续低分)
filtered_low = (rolling_ratio > 0.8).fillna(False)

# 4. 可视化结果
plt.figure(figsize=(14,4))
plt.plot(x, y, linewidth=1.3, label='原始信号')
plt.fill_between(x, 0, 0.85, where=filtered_low, color='red', alpha=0.2, label='识别的低分分段')
plt.xlim(0,5000)
plt.ylim(0,0.85)
plt.legend()
plt.tight_layout()
plt.show()

优势:

  • 无需复杂模型,完全基于数据统计特征,可复现性强
  • 手动调整参数少,阈值和窗口大小可根据业务需求或数据分布量化确定
  • 能有效过滤噪声导致的孤立低分点,保留连续的目标分段

方案二:改进的HMM模型(解决状态跳转问题)

针对普通Gaussian HMM容易跳离低状态的问题,通过约束转移矩阵增强状态的持续性,实现类似Sticky HMM的效果,同时可自动确定最优状态数量。

代码实现

from hmmlearn import hmm
from sklearn.model_selection import GridSearchCV

# 1. 准备数据:hmmlearn要求输入为2D数组
X = y.reshape(-1, 1)

# 2. 网格搜索最优状态数量(解决预先不知道状态数的问题)
param_grid = {'n_components': [2,3,4,5]}
model = hmm.GaussianHMM(covariance_type='diag', random_state=42)
grid_search = GridSearchCV(model, param_grid, cv=3, scoring='neg_log_likelihood')
grid_search.fit(X)
best_n = grid_search.best_params_['n_components']

# 3. 构建带自转移约束的HMM
model = hmm.GaussianHMM(n_components=best_n, covariance_type='diag', random_state=42)

# 设置转移矩阵:增加每个状态的自转移概率(Sticky效果)
trans_matrix = np.eye(best_n) * 0.95  # 自转移概率0.95
# 剩余概率均匀分配给其他状态
trans_matrix += (1 - 0.95)/(best_n - 1) * (1 - np.eye(best_n))
model.transmat_ = trans_matrix

# 拟合模型
model.fit(X)

# 4. 预测状态并合并低均值状态
states = model.predict(X)
state_means = model.means_.flatten()
low_state_ids = np.where(state_means < low_threshold)[0]  # 用方案一的阈值筛选低状态
is_low_hmm = np.isin(states, low_state_ids)

# 5. 可视化结果
plt.figure(figsize=(14,4))
plt.plot(x, y, linewidth=1.3, label='原始信号')
plt.fill_between(x, 0, 0.85, where=is_low_hmm, color='blue', alpha=0.2, label='HMM识别的低分分段')
plt.xlim(0,5000)
plt.ylim(0,0.85)
plt.legend()
plt.tight_layout()
plt.show()

优势:

  • 通过网格搜索自动确定最优状态数量,解决“预先不知道状态数”的问题
  • 约束转移矩阵增强状态持续性,避免普通HMM的频繁跳转问题
  • 结合统计阈值合并低均值状态,识别结果更稳定

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 00:05:13