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

R语言中如何高效匹配两个data.frame的行并获取对应id2?

高效匹配两个data.frame的非循环实现方法

需求说明

现有两个data.frame:table1和table2,需要为table1的每一行匹配table2中满足以下条件的行,并提取对应的id2:

  • 两个表的class字段值相等
  • 两个表的type字段值相等
  • table1的number值处于table2的min_number与max_number之间(包含边界值)

原实现采用for循环,但数据量达到百万级时效率极低,因此需要高效的非循环实现方案。

示例数据

table1

table1 <- data.frame(id1 = c(1324, 1111, 2324, 2324, 1111, 1111),
                     class = c(1, 1, 1, 2, 2, 1),
                     type = c("A", "A", "A", "B", "C", "D"),
                     number = c(1, 2.5, 98, 100, 80, 50))

输出:

id1 class type number
1 1324     1    A    1.0
2 1111     1    A    2.5
3 2324     1    A   98.0
4 2324     2    B  100.0
5 1111     2    C   80.0
6 1111     1    D   50.0

table2

table2 <- data.frame(id2 = c(1992, 1987, 1998, 1998, 2000, 2010, 2012),
                     class = c(3, 3, 1, 1, 3, 1, 2),
                     type = c("B", "C", "D", "A", "D", "D", "C"),
                     min_number = c(0, 0, 34, 0, 20, 45, 5),
                     max_number = c(18, 18, 50, 100, 100, 100, 100))

输出:

id2 class type min_number max_number
1 1992     3    B          0         18
2 1987     3    C          0         18
3 1998     1    D         34         50
4 1998     1    A          0        100
5 2000     3    D         20        100
6 2010     1    D         45        100
7 2012     2    C          5        100

原循环实现代码及结果

id2_list <- vector("list")
for(i in 1:nrow(table1)){
  id2_list[[i]] <- table2[which((table2$class == table1$class[i]) 
                         & (table2$type %in% table1$type[i]) 
                         & ((table2$min_number <= table1$number[i]) 
                            & (table2$max_number >= table1$number[i]))), ]$id2
}

输出:

[[1]]
[1] 1998

[[2]]
[1] 1998

[[3]]
[1] 1998

[[4]]
numeric(0)

[[5]]
[1] 2012

[[6]]
[1] 1998 2010

高效非循环实现方案

方案1:使用dplyr包(适合中等规模数据)

利用dplyr的连接与分组汇总功能,避免循环:

library(dplyr)

# 为table1添加行号,确保每一行都能对应结果
table1 <- table1 %>% mutate(row_num = row_number())

# 按class和type连接两个表,过滤符合条件的行,再按行号分组汇总id2为列表
matched_result <- table1 %>%
  left_join(table2, by = c("class", "type")) %>%
  filter(number >= min_number, number <= max_number) %>%
  group_by(row_num) %>%
  summarise(id2 = list(id2), .groups = "drop")

# 补全无匹配的行,将空值替换为numeric(0)
full_result <- table1 %>%
  left_join(matched_result, by = "row_num") %>%
  mutate(id2 = ifelse(is.na(id2), list(numeric(0)), id2))

# 提取最终的id2列表
id2_list <- full_result$id2

方案2:使用data.table包(适合百万级大数据)

data.table在处理大规模数据时性能更优,操作更高效:

library(data.table)

# 转换为data.table格式
setDT(table1)
setDT(table2)

# 为table1添加行号
table1[, row_num := .I]

# 按class和type做连接,过滤符合数值范围的行,再按行号分组汇总id2
matched_result <- table1[table2, on = .(class, type), allow.cartesian = TRUE][
  number >= min_number & number <= max_number,
  .(id2 = list(id2)),
  by = row_num
]

# 补全无匹配的行,替换空值为numeric(0)
full_result <- table1[matched_result, on = .(row_num)]
full_result[is.na(id2), id2 := list(numeric(0))]

# 提取最终的id2列表
id2_list <- full_result$id2

两种方案的输出结果与原循环实现完全一致,且在百万级数据下效率会有数量级的提升。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 14:18:25