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

在R中按距离聚类空间点:无需指定聚类数实现组内间距≤11km

基于11km阈值的空间点聚类解决方案

核心思路

你需要的是组内任意两点间距不超过11km的聚类,这类需求适合用完全连接(Complete Linkage)的层次聚类,结合地理距离计算,无需提前指定聚类数量。此前的问题大概率是因为用了错误的距离计算方式(比如直接对经纬度算欧氏距离),或是采用了需要指定聚类数的算法(如K-means)。

实现步骤(R语言)

1. 加载依赖包

需要geosphere包计算球面地理距离,层次聚类函数是R自带的:

library(geosphere)

2. 导入数据

假设你的数据框名为df,直接使用你提供的结构:

df <- structure(list(station = c("BE01", "BE02", "BEUWM01", "BL01", 
"BL02", "PB01", "PB02", "PB03", "PB04", "PB05", "PB06", "PB07", 
"PB09", "PB10", "PB11", "PB12", "PB13", "PB14", "PB15", "PB16", 
"PB17", "PB18", "PB19", "PB20", "PB21", "PB22", "PB23", "PB24", 
"PB25", "PB26", "PB27", "PB28", "PB29", "PB30", "PB4G01", "PB4G02", 
"PBUWM01", "PBUWM02", "SA01", "SA02", "SA02b", "SA03", "SA04", 
"SA05", "SA06", "SA07", "SA11", "SAUWM01", "VB01", "VB02", "VB03", 
"VB04"), longitude = c(71.6546833333333, 71.6748333333333, 71.66293, 
72.4337833333333, 72.4347, 71.7342, 71.7632, 71.7992, 71.8092, 
71.8326916667, 71.8405, 71.8796, 71.96835, 71.9697666666667, 
71.9727, 71.9745666666667, 71.9385075, 71.8685, 71.8524, 71.8414, 
71.8294, 71.758275, 71.7578, 71.7468, 71.9733, 71.9795, 71.9741, 
71.9209, 71.8959, 71.8228, 71.7498, 71.7323, 71.9068, 71.7474, 
71.9398, 71.8329, 71.98115, 71.75197, 72.24793, 72.241, 72.23027, 
72.2569, 72.2812, 72.1980666667, 72.2116, 72.221, 72.2636, 72.24754, 
72.2155, 72.2405, 72.2156, 72.2488), latitude = c(-5.25671666666667, 
-5.2662, -5.24915, -5.2579, -5.2432, -5.2815, -5.2459, -5.2461, 
-5.2448, -5.23439583333, -5.2567, -5.2694, -5.24165, -5.33015, 
-5.3344, -5.37878333333333, -5.39709575, -5.4271, -5.4229, -5.4308, 
-5.4406, -5.456505, -5.3823, -5.3512, -5.2695, -5.3039, -5.3521, 
-5.4126, -5.4243, -5.4644, -5.3957, -5.3181, -5.2668, -5.4261, 
-5.2582, -5.445, -5.33995, -5.38898, -5.31183, -5.3056, -5.316745, 
-5.2985, -5.3347, -5.35026666667, -5.3686, -5.3225, -5.3327, 
-5.30114, -5.5452, -5.5207, -5.5247, -5.546)), row.names = c(NA, 
-52L), class = "data.frame")

3. 计算地理距离矩阵(单位:km)

不能直接用经纬度计算欧氏距离(经纬度的度单位无法代表实际公里数),必须用球面距离算法:

# 提取经纬度坐标,geosphere要求顺序为经度、纬度
coords <- df[, c("longitude", "latitude")]
# 计算所有点对的球面距离,转换为km(默认输出为米)
dist_matrix <- distm(coords, fun = distHaversine) / 1000

4. 执行聚类并分配组ID

采用完全连接的层次聚类,保证组内最远两点距离不超过设定阈值,正好满足你的需求:

# 构建层次聚类树,方法为完全连接
hc <- hclust(as.dist(dist_matrix), method = "complete")
# 按11km阈值切割聚类树,生成组ID
df$group_id <- cutree(hc, h = 11)

5. 验证结果

可以检查分组数量和组内最大距离是否符合要求:

# 查看各分组的点数分布
table(df$group_id)

# 验证每个组的最大点间距
lapply(split(df, df$group_id), function(x) {
  coords_group <- x[, c("longitude", "latitude")]
  max_dist <- max(distm(coords_group, fun = distHaversine)/1000)
  cat("分组", unique(x$group_id), "最大间距:", round(max_dist, 2), "km\n")
})

此前方法失败的原因

  • 若使用K-means等需要指定聚类数的算法,显然不符合无需预设分组数的需求;
  • 若直接对经纬度计算欧氏距离,得到的数值无实际地理意义,会导致聚类逻辑完全错误,出现每个点单独分组的情况;
  • 若使用DBSCAN等密度聚类算法,其核心逻辑是基于“核心点邻域密度”,和你要求的“组内任意两点间距不超过阈值”逻辑不符。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 23:47:02