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

在R中绘制无重叠分类点凸包的技术问题求助

多类点无重叠凸包实现与凹包适用性分析

解决多类凸包重叠的思路与R实现

直接为每类点生成凸包会重叠,因为凸包仅以自身点集的最小包围为目标,完全不考虑其他类的位置。要实现无重叠的类级包围形状,核心是先为每类点划定专属空间区域,再在区域内生成包围形状。

基于Voronoi图的无重叠凸包实现

Voronoi图会将平面划分为多个单元,每个单元内的点到该类核心点的距离最近,天然保证单元间无重叠。我们可以在每个类对应的Voronoi单元内生成凸包,确保最终结果无重叠:

# 加载依赖包
library(sf)
library(dplyr)

# 模拟多类点数据(替换为你的实际数据)
set.seed(123)
points <- data.frame(
  x = c(rnorm(30, 0, 1), rnorm(30, 3, 1), rnorm(30, 6, 1)),
  y = c(rnorm(30, 0, 1), rnorm(30, 3, 1), rnorm(30, 6, 1)),
  class = rep(c("red", "blue", "green"), each = 30)
) %>% st_as_sf(coords = c("x", "y"))

# 生成全局Voronoi图并按类聚合单元
voronoi_units <- st_voronoi(st_union(points)) %>% 
  st_cast() %>% 
  st_sf() %>%
  st_join(points, join = st_intersects) %>%
  group_by(class) %>%
  summarise(geometry = st_union(geometry))

# 在每个Voronoi单元内生成对应类的凸包
non_overlap_convex_hulls <- points %>%
  group_by(class) %>%
  summarise(class_points = st_union(geometry)) %>%
  left_join(voronoi_units, by = "class") %>%
  mutate(
    # 取类点与对应Voronoi单元的交集,再生成凸包
    geometry = st_intersection(class_points, geometry) %>% st_convex_hull()
  ) %>%
  select(class, geometry)

基于类间距离的凸包收缩法

如果不想用Voronoi图,也可以计算每类点到其他所有类点的最小距离d,然后将该类的凸包向内收缩d/2的距离,确保两个凸包边界间至少有0的间隔:

# 计算每类到其他类的最小距离
class_distances <- points %>%
  st_distance(points) %>%
  as.matrix() %>%
  split(rep(seq_len(n_distinct(points$class)), each = nrow(points))) %>%
  lapply(function(x) apply(x[, points$class != unique(points$class)], 2, min)) %>%
  sapply(min)

# 生成原始凸包并按距离收缩
non_overlap_convex_hulls <- points %>%
  group_by(class) %>%
  summarise(geometry = st_convex_hull(st_union(geometry))) %>%
  mutate(
    shrink_dist = class_distances[class] / 2,
    # 向内收缩凸包,避免重叠
    geometry = st_buffer(geometry, dist = -shrink_dist)
  ) %>%
  select(class, geometry)

注意:如果类点本身分布非常密集,收缩后可能导致凸包消失,此时优先选择Voronoi方法。

凹包(Concave Hull)的适用性分析

凹包相比凸包更贴合点集的实际分布,能减少凸包带来的“无效包围空间”,因此在类点分布不交错的场景下,直接生成凹包确实比凸包更不容易出现重叠。但如果类点本身在空间上相互穿插,仅靠凹包依然无法避免重叠。

实际使用中,建议结合前面的区域约束方法:先通过Voronoi或距离划分专属区域,再在区域内生成凹包,这样既能贴合点集形状,又能严格保证无重叠。R中可以用concaveman包生成凹包:

library(concaveman)

# 在Voronoi单元内生成无重叠凹包
non_overlap_concave_hulls <- points %>%
  group_by(class) %>%
  mutate(coords = st_coordinates(geometry)) %>%
  summarise(coords = list(coords)) %>%
  left_join(voronoi_units, by = "class") %>%
  mutate(
    # 生成凹包,concavity参数控制凹陷程度(值越大越接近凸包)
    concave_hull = lapply(coords, concaveman, concavity = 2),
    geometry = st_sfc(lapply(concave_hull, function(x) st_polygon(list(x)))) %>%
      st_intersection(geometry)
  ) %>%
  select(class, geometry)

总结

  1. 直接生成多类凸包必然重叠,因为凸包不考虑类间空间关系;
  2. 无重叠包围的核心是为每类划定专属区域(Voronoi单元是最稳妥的方式),再在区域内生成凸包/凹包;
  3. 凹包更贴合点集,能减少空间浪费,但无法单独解决类点交错导致的重叠问题,需结合区域约束使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 06:15:32