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

如何用dplyr计算双列表格中所有集合对的重叠系数?

问题描述

我需要计算集合间的重叠系数(overlap coefficient),数据为双列表格,示例数据如下:

df_example <- 
  tibble::tribble(~my_group, ~cities,
                   "foo",   "london",
                   "foo",   "paris", 
                   "foo",   "rome", 
                   "foo",   "tokyo",
                   "foo",   "oslo",
                   "bar",   "paris", 
                   "bar",   "nyc",
                   "bar",   "rome", 
                   "bar",   "munich",
                   "bar",   "warsaw",
                   "bar",   "sf", 
                   "baz",   "milano",
                   "baz",   "oslo",
                   "baz",   "sf",  
                   "baz",   "paris")

在df_example中,my_group的foo、bar、baz各自对应一个集合,cities列是集合成员。我希望生成一个表格,包含所有可能的集合对的:

  • 交集成员数量
  • 对应集合对中较小集合的大小
  • 重叠系数(计算公式:重叠系数 = 共同成员数 / 较小集合大小)

预期输出如下:

## # A tibble: 3 × 4
##   combination n_instersected_members size_of_smaller_set  overlap_coeff
##   <chr>                        <dbl>               <dbl>          <dbl>
## 1 foo*bar                          2                   5           0.4 
## 2 foo*baz                          3                   4           0.75
## 3 bar*baz                          2                   4           0.5 

我尝试过以下dplyr代码,但无法运行,因为dplyr::intersect()需要两个向量:

df_example |>
  group_by(my_group) |>
  summarise(intersected = dplyr::intersect(cities))

请问有没有基于dplyr动词的简便方法实现该需求?


解决方案

可以通过生成不重复集合对+嵌套集合运算的方式,全程用dplyr动词完成需求:

步骤1:整理每个集合的成员与大小

先把每个my_group对应的城市集合、集合大小单独提取出来:

library(dplyr)
library(tidyr)
library(purrr)

group_sets <- df_example |>
  group_by(my_group) |>
  summarise(
    city_set = list(unique(cities)),  # 保存每组的城市集合(去重)
    set_size = n_distinct(cities),   # 计算集合大小
    .groups = "drop"
  )

步骤2:生成所有不重复的集合对

用cross_join生成所有可能的组对,再过滤掉重复的反向组合(比如foo*bar和bar*foo只保留一个):

pairwise_groups <- group_sets |>
  cross_join(group_sets, suffix = c("_x", "_y")) |>
  filter(my_group_x < my_group_y) |>  # 避免重复组合
  mutate(combination = paste(my_group_x, my_group_y, sep = "*"))

步骤3:计算交集、较小集合大小与重叠系数

通过map2_int对每一对集合计算交集长度,再推导所需指标:

result <- pairwise_groups |>
  mutate(
    n_instersected_members = map2_int(city_set_x, city_set_y, ~length(intersect(.x, .y))),
    size_of_smaller_set = pmin(set_size_x, set_size_y),
    overlap_coeff = n_instersected_members / size_of_smaller_set
  ) |>
  select(combination, n_instersected_members, size_of_smaller_set, overlap_coeff)

运行后结果与预期一致:

result
## # A tibble: 3 × 4
##   combination n_instersected_members size_of_smaller_set overlap_coeff
##   <chr>                        <int>               <int>         <dbl>
## 1 bar*baz                          2                   4           0.5
## 2 foo*bar                          2                   5           0.4
## 3 foo*baz                          3                   4           0.75

简化链式调用版

如果想更简洁,可将所有步骤合并为一条链式操作:

df_example |>
  group_by(my_group) |>
  summarise(
    city_set = list(unique(cities)),
    set_size = n_distinct(cities),
    .groups = "drop"
  ) |>
  cross_join(., ., suffix = c("_x", "_y")) |>
  filter(my_group_x < my_group_y) |>
  mutate(
    combination = paste(my_group_x, my_group_y, sep = "*"),
    n_instersected_members = map2_int(city_set_x, city_set_y, ~length(intersect(.x, .y))),
    size_of_smaller_set = pmin(set_size_x, set_size_y),
    overlap_coeff = n_instersected_members / size_of_smaller_set
  ) |>
  select(combination, n_instersected_members, size_of_smaller_set, overlap_coeff)

关键说明

  • list(unique(cities)):将每组城市转为列表形式的集合,方便后续交集运算
  • cross_join + filter(my_group_x < my_group_y):高效生成无重复的集合对
  • map2_int:批量处理每一对集合的交集计算,返回整数结果
  • pmin:直接取两个集合大小的最小值,简化条件判断逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 20:18:18