首页 > 解决方案 > 当我们为向量的所有元素查找所有匹配索引时,R 中是否有一个函数可以避免使用循环?

问题描述

我有这个 for 循环,它返回向量中每个元素的第一个匹配索引,但它非常慢(nrow(data)> 50 000)

例子:

id1 <- c(1,5,8,10)
id2 <- c(5,8,10,1)

data <- data.frame(id1,id2, idx = 1:length(id1))

结果应该是:

data$new_id
4 1 2 3
data$new_id <- NA
for(i in 1:nrow(data)){
  data$new_id[i] <- which(data$id2 == data$id1[i])
}

我发现这适用于小数据帧,但不幸的是 R 返回“错误:无法分配大小为 22.2 Gb 的向量”

A <- outer(data$id1,data$id2, "==")

data <- data %>%
  mutate(new_id = which(t(A)),
         id0 = 0:(nrow(data)-1),
         new_id = new_id-(nrow(data))*id0)

是否存在其他解决方案来执行此索引?

标签: r

解决方案


我们可以使用match非常快的base R函数。在这里,我们只是匹配数据集的两列,甚至没有尝试将两个数据集放在一起

with(data, match(id1, id2))
#[1] 4 1 2 3

为了加快速度,请使用fmatchfromfastmatch

library(fastmatch)
with(data, fmatch(id1, id2))

基准

set.seed(24)
data1 <- data.frame(id1 = sample(1e7), id2 = sample(1e7))

system.time(with(data1, match(id1, id2)))
#  user  system elapsed 
# 1.635   0.079   1.691 

system.time(with(data1, fmatch(id1, id2)))
#  user  system elapsed 
# 1.155   0.062   1.195 


system.time({
        data2 <- data.table(id = data1$id1)
        data3 <- data.table(id = data1$id2)
         data2[data3, idx := .I, on = .(id)]
   })
#   user  system elapsed 
# 2.306   0.051   2.353 

推荐阅读