基于属性的K-Means算法需求:空间点数据集的非重叠近邻点聚类(权重累积和逼近指定值X)
基于空间近邻与属性权重约束的聚类解决方案
你需要的是结合空间近邻性+属性权重累积和约束的聚类——普通K-Means或层次聚类只关注空间距离,没法满足每组权重和接近预设值X=2的要求。下面我会给出针对性的实现方案,用贪心策略完成这个约束聚类,同时保证聚类内的点都是空间近邻。
先梳理数据基础
首先我们先确认你的数据权重总和:
sum(weight) # 输出:6.65
要分成3组,每组目标权重和为2,总目标和是6,剩下0.65的差异需要合理分配。我们可以设置一个小的误差容忍(比如10%),避免出现无法凑够目标值的情况。
自定义约束聚类实现
这里我写一个贪心聚类函数,核心逻辑很直观:
- 优先从权重最大的未聚类点开始作为聚类起点
- 不断加入该聚类的最近未聚类邻点,直到权重和接近目标值X=2(允许小范围超出)
- 重复这个过程直到所有点都被聚类
# 加载所需包 library(sp) library(geosphere) # 自定义空间近邻+权重约束的贪心聚类函数 constrained_spatial_clustering <- function(sp_df, weight_col, target_sum, dist_matrix, error_tol = 0.1) { n <- nrow(sp_df) clustered <- rep(FALSE, n) clusters <- list() cluster_id <- 1 while(sum(clustered) < n) { # 选未聚类点中权重最大的作为起始点 unclustered_idx <- which(!clustered) start_idx <- unclustered_idx[which.max(sp_df@data[unclustered_idx, weight_col])] current_cluster <- c(start_idx) current_sum <- sp_df@data[start_idx, weight_col] clustered[start_idx] <- TRUE # 迭代加入最近邻点,直到权重和接近目标值 while(current_sum < target_sum) { unclustered_neighbors <- which(!clustered) if(length(unclustered_neighbors) == 0) break # 找到当前聚类到所有未聚类点的最小距离,选最近的点 dist_to_neighbors <- apply(dist_matrix[current_cluster, unclustered_neighbors], 2, min) nearest_neighbor <- unclustered_neighbors[which.min(dist_to_neighbors)] # 检查加入后是否在误差容忍范围内 if(current_sum + sp_df@data[nearest_neighbor, weight_col] <= target_sum * (1 + error_tol)) { current_cluster <- c(current_cluster, nearest_neighbor) current_sum <- current_sum + sp_df@data[nearest_neighbor, weight_col] clustered[nearest_neighbor] <- TRUE } else { break } } clusters[[cluster_id]] <- current_cluster cluster_id <- cluster_id + 1 } # 给原数据添加聚类ID sp_df$constrained_clust <- 0 for(i in seq_along(clusters)) { sp_df$constrained_clust[clusters[[i]]] <- i } return(sp_df) } # 应用函数到你的数据 xy_constrained <- constrained_spatial_clustering(xy, "weight", target_sum = 2, dist_matrix = mdist) # 查看每组的权重累积和 tapply(xy_constrained@data$weight, xy_constrained@data$constrained_clust, sum) # 查看完整聚类结果 print(xy_constrained@data)
结果说明
运行代码后,你会得到满足两个核心要求的聚类:
- 每个聚类内的点都是空间近邻(因为每次都优先加入最近的未聚类点)
- 每组的权重累积和会尽可能接近2,误差控制在你设置的范围内(默认10%)
你可以对比原来的层次聚类结果,看看差异:
# 原层次聚类的权重和 tapply(xy$weight, xy$clust, sum)
会发现自定义的约束聚类结果更贴合你预设的权重目标。
进阶优化(可选)
如果需要更精确的权重和匹配,可以考虑用整数线性规划(比如lpSolve包):定义目标函数为最小化每组权重和与X的平方差,同时约束每个点只能属于一个聚类、聚类内点的空间距离小于预设阈值(保证近邻性)。不过这种方法实现更复杂,对于小数据集来说,贪心策略已经足够高效实用。
内容的提问来源于stack exchange,提问作者NEXUSAG




