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

tslearn时间序列KMeans聚类报x/y数组至少需2个条目错误

问题说明

使用tslearn库的TimeSeriesKMeans对110个文件的时间序列做基于DTW的聚类,遍历2、3、4三类聚类数,通过轮廓系数选最优结果。数据编码固定为-1(否)、0(不确定)、1(是),不能替换NaN值,无需归一化。处理部分文件时抛出错误:ValueError: x and y arrays must have at least 2 entries,尝试过对to_time_series_dataset(x)输出做/不做squeeze操作都无法解决。

执行squeeze后的样例数据:

[[ 0.  1. -1. nan]
 [-1.  1.  0. -1.]
 [ 0. -1. nan nan]
 [ 0.  0. -1. nan]
 [ 0.  1.  0. -1.]
 [ 0. -1. nan nan]
 [ 0. -1. -1. nan]
 [ 0.  0. -1. nan]
 [ 0. -1. nan nan]
 [ 0. -1. nan nan]
 [ 0.  0. -1. nan]
 [-1. -1. nan nan]
 [ 1.  1. -1. nan]
 [ 1. -1. nan nan]
 [ 0. -1. nan nan]
 [ 1. -1. nan nan]
 [ 0. -1. -1. nan]
 [ 0. -1. nan nan]
 [ 1. -1. nan nan]
 [ 0.  0. -1. nan]
 [ 0. -1. -1. nan]
 [ 0.  1. -1. nan]
 [ 0.  0. -1. nan]
 [ 1. -1. nan nan]]

不执行squeeze的标准tslearn三维输入格式样例:

[[[ 0.]
  [ 1.]
  [-1.]
  [nan]]

 [[-1.]
  [ 1.]
  [ 0.]
  [-1.]]

 [[ 0.]
  [-1.]
  [nan]
  [nan]]
...
]

原有聚类代码:

for j in [2,3,4]:
    km = TimeSeriesKMeans(n_clusters=j, metric="dtw")
    labels = km.fit_predict(x)
    silhouetteScore = silhouette_score(x, labels, metric="dtw")

    num_of_clusters_list.append(j)
    silhouetteScore_list.append(silhouetteScore)
    print(f"{j} clusters, score is {silhouetteScore}")
报错根因
  • 首先squeeze操作是多余的,tslearn要求输入形状为(n_samples, n_timestamps, n_features),单变量时间序列最后一维为1是符合规范的,squeeze反而会破坏输入形状。
  • 原生DTW度量不支持带NaN的输入,当单条时间序列非NaN有效值少于2个,或两条序列的非NaN位置无足够重叠时,DTW距离计算会因有效计算点对不足2个抛出上述值错误。
  • 即使没有触发报错,带NaN的输入传入原生DTW计算逻辑也会得到全NaN的距离结果,导致后续聚类、轮廓系数计算完全失效。
解决步骤
  • 过滤无效样本
    加载每个文件的数据后,先逐样本统计非NaN值数量,剔除有效长度小于2的样本,这类样本本身信息量不足,既无法参与距离计算,也会干扰聚类结果。过滤后如果剩余有效样本数不足2,直接跳过该文件的聚类流程(样本量不足无法完成聚类)。
  • 替换支持缺失值的距离度量
    不要使用默认的dtw度量,换成支持部分观测序列计算的softdtw度量,不需要替换NaN值即可完成距离计算,符合数据编码要求。如果对DTW的硬对齐需求很高,可以自行实现带掩码的DTW逻辑:计算两个序列的距离时,仅对两个序列同一时间步均不为NaN的位置计算点对距离,跳过所有含NaN的位置,预计算完全部样本对的距离矩阵后,传入聚类和轮廓系数接口时指定metric="precomputed"即可。
  • 动态调整聚类数遍历范围
    聚类数必须小于有效样本总数(轮廓系数计算要求每个簇至少有1个样本,且聚类数不能等于样本数),过滤完有效样本后,从[2,3,4]里筛选出小于有效样本数的值作为实际遍历的聚类数,比如有效样本只有3个时,仅遍历聚类数为2的情况即可,避免触发新的参数错误。

调整后的参考代码:

# 不要执行squeeze,保留tslearn要求的三维输入格式
x = to_time_series_dataset(raw_x)
# 过滤有效样本:单序列非NaN值≥2
valid_mask = np.array([np.count_nonzero(~np.isnan(seq.squeeze())) >= 2 for seq in x])
x_valid = x[valid_mask]
n_samples = len(x_valid)
# 有效样本不足直接跳过
if n_samples < 2:
    print(f"当前文件有效样本不足,跳过聚类")
    continue
# 动态确定待测试的聚类数
test_cluster_list = [k for k in [2,3,4] if k < n_samples]
num_of_clusters_list = []
silhouetteScore_list = []
for j in test_cluster_list:
    # 用支持缺失值的softdtw作为度量
    km = TimeSeriesKMeans(n_clusters=j, metric="softdtw", random_state=42)
    labels = km.fit_predict(x_valid)
    silhouetteScore = silhouette_score(x_valid, labels, metric="softdtw")
    num_of_clusters_list.append(j)
    silhouetteScore_list.append(silhouetteScore)
    print(f"{j} clusters, score is {silhouetteScore}")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 22:06:18