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

如何在dplyr的left_join中标记多对多、一对多、多对一关系

标记数据关联中的三种关系(many-to-many/one-to-many/many-to-one)

要完整区分这三种关系,核心是先统计每个关联ID在两个表中的记录数量,再根据数量组合判断关系类型:

  • one-to-many:左表(df1)中单个ID仅对应1条记录,右表(df2)中对应多条记录
  • many-to-one:左表中单个ID对应多条记录,右表中仅对应1条记录
  • many-to-many:左右表中单个ID都对应多条记录

具体实现步骤如下:

library(dplyr)

df1 <- data.frame(
  id1 = c(1, 1, 3, 4),
  value1 = c("A", "B", "C", "D")
)

df2 <- data.frame(
  id2 = c(1, 1, 3, 3, 4),
  value2 = c("X", "Y", "Z1", "Z2", "W")
)

# 统计每个ID在两个表中的记录数
count_df1 <- df1 %>% group_by(id1) %>% summarise(count_df1 = n(), .groups = "drop")
count_df2 <- df2 %>% group_by(id2) %>% summarise(count_df2 = n(), .groups = "drop")

# 关联数据并标记关系类型
result <- df1 %>%
  left_join(df2, by = c("id1" = "id2")) %>%
  left_join(count_df1, by = "id1") %>%
  left_join(count_df2, by = c("id1" = "id2")) %>%
  mutate(
    tag = case_when(
      count_df1 == 1 & count_df2 > 1 ~ "one-to-many",
      count_df1 > 1 & count_df2 == 1 ~ "many-to-one",
      count_df1 > 1 & count_df2 > 1 ~ "many-to-many",
      TRUE ~ "one-to-one" # 补充one-to-one的边界情况
    )
  ) %>%
  select(-count_df1, -count_df2) # 可选:移除中间计数列

result

运行后输出结果:

# A tibble: 7 × 5
    id1 value1   id2 value2 tag        
  <dbl> <chr>  <dbl> <chr>  <chr>      
1     1 A          1 X      many-to-many
2     1 A          1 Y      many-to-many
3     1 B          1 X      many-to-many
4     1 B          1 Y      many-to-many
5     3 C          3 Z1     many-to-many
6     3 C          3 Z2     many-to-many
7     4 D          4 W      one-to-many

如果需要验证many-to-one的标记效果,可以修改测试数据:

# 构造包含many-to-one关系的测试数据
df1_test <- df1 %>% add_row(id1=5, value1="E") %>% add_row(id1=5, value1="F")
df2_test <- df2 %>% add_row(id2=5, value2="V")

# 重新执行统计和关联逻辑
count_df1_test <- df1_test %>% group_by(id1) %>% summarise(count_df1 = n(), .groups = "drop")
count_df2_test <- df2_test %>% group_by(id2) %>% summarise(count_df2 = n(), .groups = "drop")

result_test <- df1_test %>%
  left_join(df2_test, by = c("id1" = "id2")) %>%
  left_join(count_df1_test, by = "id1") %>%
  left_join(count_df2_test, by = c("id1" = "id2")) %>%
  mutate(
    tag = case_when(
      count_df1 == 1 & count_df2 > 1 ~ "one-to-many",
      count_df1 > 1 & count_df2 == 1 ~ "many-to-one",
      count_df1 > 1 & count_df2 > 1 ~ "many-to-many",
      TRUE ~ "one-to-one"
    )
  ) %>%
  select(-count_df1, -count_df2)

result_test

此时输出会包含many-to-one标签的记录:

# A tibble: 9 × 5
    id1 value1   id2 value2 tag        
  <dbl> <chr>  <dbl> <chr>  <chr>      
1     1 A          1 X      many-to-many
2     1 A          1 Y      many-to-many
3     1 B          1 X      many-to-many
4     1 B          1 Y      many-to-many
5     3 C          3 Z1     many-to-many
6     3 C          3 Z2     many-to-many
7     4 D          4 W      one-to-many
8     5 E          5 V      many-to-one
9     5 F          5 V      many-to-one

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 06:43:11