以下是一些基准测试结果:
A = crossing(idx=1:1e3, asdf=seq(1:rpois(1,50)))
B = tibble(idx=sample(1:1e3, replace=TRUE), yet_more_stuff='whatever')
第一个想法是按照您的建议使用split,保持split.A 和split.B 的顺序相同。您可以使用map2 来遍历匹配的列表:
myfun <- function(A,B) {
split.A <- split(A, A$idx)
splitsort.A <- split.A[order(names(split.A))]
splitsort.B <- map(names(splitsort.A), ~B[as.character(B$idx) == .x,])
ans <- map2(splitsort.A, splitsort.B, ~unique(.x$idx) == unique(.y$idx))
return(ans)
}
这是您当前使用的方法,使用dplyr::filter
OP <- function(A,B) {
ans <- map(unique(A$idx), ~unique(filter(A, idx==.x)$idx) == unique(filter(B, idx==.x)$idx))
return(ans)
}
这是相同的逻辑,但避免了dplyr::filter,与基本 R 子集相比更慢
OP2 <- function(A,B) {
ans <- map(unique(A$idx), ~unique(A[A$idx==.x,]$idx) == unique(B[B$idx==.x,]$idx))
return(ans)
}
这使用了@JakeThompson 的方法(它似乎是当前方法中的赢家)
JT <- function(A,B) {
nest.A <- A %>% group_by(idx) %>% nest()
nest.B <- B %>% group_by(idx) %>% nest()
ans <- full_join(nest.A, nest.B, by="idx")
}
一些验证以确保某些函数的结果有意义
identical(OP(A,B), OP2(A,B))
# TRUE
E <- myfun(A,B)
any(E==FALSE)
# NA
F <- myfun(A,B)
any(F==FALSE)
# NA
identical(sum(E==TRUE, na.rm=TRUE), sum(F==TRUE, na.rm=TRUE))
# TRUE
基准测试结果
library(microbenchmark)
microbenchmark(myfun(A,B), OP(A,B), OP2(A,B), JT(A,B), times=2L)
# Unit: seconds
# expr min lq mean median uq max neval
# myfun(A, B) 3.164046 3.164046 3.254588 3.254588 3.345129 3.345129 2
# OP(A, B) 14.926431 14.926431 15.053662 15.053662 15.180893 15.180893 2
# OP2(A, B) 3.202414 3.202414 3.728423 3.728423 4.254432 4.254432 2
# JT(A, B) 1.330278 1.330278 1.378241 1.378241 1.426203 1.426203 2