如何为R语言自定义K-means迭代函数添加收敛停止规则?
在K-means函数中添加收敛停止规则的实现方法
这是个很实用的优化需求——K-means确实不需要固定跑满所有迭代次数,当相邻两次迭代的簇分配结果完全一致时,说明算法已经收敛,此时可以提前终止循环,节省计算资源。下面是具体的修改方案:
核心思路
我们需要在迭代过程中记录上一次的簇分配结果,每次计算出新的簇分配后,和上一次做对比:
- 如果两者完全一致,说明簇结构不再变化,算法收敛,直接终止迭代
- 如果不一致,继续迭代,直到达到预设的最大迭代次数(防止极端情况下出现无限循环)
修改后的完整代码
# 保留原有的欧氏距离计算函数 euclid <- function(points1, points2) { distanceMatrix <- matrix(NA, nrow=dim(points1)[1], ncol=dim(points2)[1]) for(i in 1:nrow(points2)) { distanceMatrix[,i] <- sqrt(rowSums(t(t(points1)-points2[i,])^2)) } distanceMatrix } # 修改后的K-means函数,添加收敛停止规则 K_means <- function(x, centers, distFun, maxItter) { # 初始化历史记录列表,动态添加迭代结果 clusterHistory <- list() centerHistory <- list() # 第一次迭代:计算初始簇分配 distsToCenters <- distFun(x, centers) clusters <- apply(distsToCenters, 1, which.min) clusterHistory[[1]] <- clusters centerHistory[[1]] <- centers # 开始迭代(从第2次到最大迭代次数) for(i in 2:maxItter) { # 基于当前簇更新聚类中心 centers <- apply(x, 2, tapply, clusters, mean) centerHistory[[i]] <- centers # 计算新的簇分配结果 distsToCenters <- distFun(x, centers) new_clusters <- apply(distsToCenters, 1, which.min) clusterHistory[[i]] <- new_clusters # 检查收敛:对比新簇和旧簇是否完全一致 if(all(new_clusters == clusters)) { message(paste("算法在第", i, "次迭代时收敛,提前终止")) break } # 更新簇变量,为下一次迭代做准备 clusters <- new_clusters } # 返回包含所有迭代历史的结果列表 list(clusters=clusterHistory, centers=centerHistory) }
关键改动说明
- 参数调整:把原函数的
nItter改为maxItter,明确这是迭代的上限,而非必须执行的次数 - 动态历史记录:将
clusterHistory和centerHistory改为空列表,根据实际迭代次数动态添加结果,避免内存浪费 - 收敛判断逻辑:每次迭代后用
all(new_clusters == clusters)检查簇分配是否完全不变,满足条件则打印收敛信息并终止循环 - 迭代流程优化:先更新中心,再计算新簇,确保每次迭代的逻辑连贯
使用示例
和原来的调用方式几乎一致,只是明确maxItter是最大迭代次数:
test=data # 你的输入data.frame ktest=as.matrix(test) # 转换为矩阵格式 centers <- ktest[sample(nrow(ktest), 5),] # 随机选取5个初始中心 res <- K_means(ktest, centers, euclid, 100) # 最大迭代100次,收敛则提前停止
可选扩展(额外优化)
如果你想更严谨,还可以添加中心变化阈值的判断:比如当所有聚类中心的欧氏距离变化之和小于某个极小值(如1e-6)时,也判定为收敛。不过根据你的需求,簇分配不变的判断已经足够直接有效。
内容的提问来源于stack exchange,提问作者HelpNeeded3
相关产品推荐
相关产品推荐

