为何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
相关产品推荐
相关产品推荐

