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

为何dtw()结合pam()与tsclust()聚类结果不一致?

基于DTW的PAM聚类结果不一致的原因分析

你使用以下两种语法实现基于DTW距离的PAM聚类,参数均设置为Manhattan局部距离、symmetric1步模式,但结果却不一致:

语法1(手动构建DTW距离矩阵+cluster包pam)

dtw_distances <- matrix(0, nrow = nrow(data_wide), ncol = nrow(data_wide))
rownames(dtw_distances) <- rownames(data_wide)
colnames(dtw_distances) <- rownames(data_wide)
for (i in 1:(nrow(data_wide)-1)) {
  for (j in (i+1):nrow(data_wide)) {
    ts1 <- as.vector(data_wide[i, ])
    ts2 <- as.vector(data_wide[j, ])
    alignment <- dtw(ts1, ts2, step.pattern=symmetric1, dist.method = "manhattan", keep.internals = T)
    dtw_distances[i, j] <- alignment$distance
    dtw_distances[j, i] <- alignment$distance
    
  }
}
ks_kmedoids <- data.frame(k = integer(), sil_kmeans = numeric())
silhouette_scores_kmedoids <- numeric()
for (k in 2:10) {
  kmedoids_result <- pam(dtw_distances, k)
  silhouette_scores_kmedoids[k] <- mean(silhouette(kmedoids_result$clustering, dtw_distances)[, 3])
  
  ks_kmedoids <- rbind(ks_kmedoids, data.frame(k=k, sil_kmedoids = silhouette_scores_kmedoids[k] ))
}
print(ks_kmedoids)

语法2(tsclust直接实现)

ks_kmedoids <- data.frame(k = integer(), sil_kmedoids = numeric())
silhouette_scores_kmedoids <- numeric()
for (k in 2:10) {
  kmedoids_result <- tsclust(data_wide, type="partitional", k=k,distance="dtw_basic",dist_args = list(method = "manhattan",step.pattern=symmetric1),centroid = "pam",seed=123)
  silhouette_scores_kmedoids[k] <- mean(silhouette(kmedoids_result@cluster, dtw_distances)[, 3])
  
  ks_kmedoids <- rbind(ks_kmedoids, data.frame(k=k, sil_kmedoids = silhouette_scores_kmedoids[k] ))
}
print(ks_kmedoids)

注:data_wide为已标准化的宽格式时间序列数据。

导致结果不一致的核心原因如下:

1. DTW距离矩阵的计算细节存在差异

  • 语法1使用dtw包的dtw()函数计算距离,直接返回原始累计对齐距离;而语法2使用tsclust的dtw_basic计算距离,二者在底层逻辑上存在细微区别:比如dtw_basic是否默认对距离做缩放、对步模式权重的处理是否和dtw()完全一致,都会导致最终生成的距离矩阵数值不同。PAM聚类完全依赖距离矩阵,这是结果差异的核心根源之一。
  • 语法1中手动转换向量的as.vector(data_wide[i, ]),和tsclust直接处理宽格式数据行的方式,可能存在维度顺序的隐性差异(需验证数据框转向量的顺序是否与tsclust的处理逻辑一致)。

2. PAM算法的初始化与执行逻辑不同

  • 语法1调用cluster包的pam()函数,默认采用启发式的"build"初始化方法,通过逐步筛选最优medoid完成初始化;而语法2中tsclust的partitional聚类默认采用随机初始化(即使设置seed=123固定了随机种子,但初始化逻辑本身和pam()的"build"完全不同)。初始medoid的选择差异,会直接导致PAM迭代后的最终聚类结果不同。
  • tsclust内部对PAM的实现,和cluster包的pam()并非完全一致,比如迭代终止条件、medoid更新的细节逻辑,都可能存在差异。

3. 轮廓系数计算的数据源不匹配

语法2中计算轮廓系数时,使用的是语法1生成的dtw_distances矩阵,但tsclust聚类时实际使用的是自身计算的DTW距离矩阵,这两个矩阵可能因上述DTW计算差异而不匹配,导致轮廓系数计算结果失真,进一步放大了结果差异。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 14:05:56