r语言 - 根据多个列条件搜索 data.frame 索引 - 如何加快大型数据集的速度?



我有一个很大的data.frame(50M行(,需要找到与多列条件匹配的索引。

我做了一个玩具例子来说明这个问题。

我在这里读到搜索data.tables比data.frames更快,所以我将data.frame转换为data.table对象。

cases<-c(1,3,5)
women<-c("Julia", "Judith", "Juno", "Jane", "Joanna")
data.df<-data.frame("id" = 1:5, "age" = c(20, 30, 40, 50, 60), "name" = c("Joanna","Joe", "Julia", "Juno", "John"))
library(data.table)
data.dt<-as.data.table(data.df)
setkey(data.dt, "id")

我希望结果向量包含通过多列条件的记录的年龄值,在本例中为 20、40、NA。我使用 for 循环进行搜索(这可能是一种愚蠢的方法,任何提示都将不胜感激(

results<-vector()
for (i in 1:length(cases)){
which_id<-cases[i]
ind<-data.dt[id==which_id & name %in% women, which=TRUE]
if(length(ind)==0){results[i]<-NA}
else{results[i]<-data.dt$age[ind]}
}

这将在一个较小的数据集上完成,但是在案例中有500K条记录,在data.df中有50M条记录,这将需要超过12个小时才能运行。一定有更简单的方法,谁能给一个提示?

如果我理解正确,OP 希望首先通过id过滤他的数据集,然后在women中找到name时返回age(否则NA(。

以下是返回预期结果的不同data.table方法

20 40 NA

对于示例案例。但是,生产数据集的性能可能会有所不同。

1.按id过滤,women匹配

setkey(data.dt, id)
data.dt[cases][name %in% women, Age := age][, Age]

这里使用整数匹配,因为name已被 OP 对data.frame()的调用转换为因子。(如果name是字符类型%chin%则可以使用(。

为了确保在没有匹配的情况下返回NA,使用默认NA更新

请注意,Cole 的方法data.dt[J(cases)][name %in% women]只会返回包含 2 行的过滤数据集,而不是预期的结果。

2.按id过滤,与women连接

这与上面类似,但使用连接而不是匹配:

setkey(data.dt, id)
data.dt[cases][.(women), on = .(name = V1), Age := age][, Age]

3. 加入women,然后加入cases

此方法选择name首先匹配women的行(通过连接(,然后与cases右连接,以便每个事例在结果向量中都有其相应的条目:

setkey(data.dt, id)
data.dt[.(women), on = .(name = V1), nomatch = 0L][cases, age]

讨论

OP 指出,速度是 500k 个元素(cases(和 50M 行(data.df(的 50M 行的生产数据集的一个问题。以上哪种方法对于生产数据集最快可能还取决于women中的条目数。

如果没有适当的基准测试,我不愿意推荐其中一种方法。

我假设您希望ind长度为 1 或 0(意味着 ID 都不同(。

然后,您可以使用 {dplyr} 非常快速地完成此操作:

library(dplyr)
results2 <- data.df %>%
slice(match(cases, id)) %>%
mutate(res = ifelse(name %in% women, age, NA)) %>%
pull(res)

也许你可以试试下面的代码

(v<-data.df[cases,])$age[match(v$name,women)>0]

(v<-data.dt[cases,])$age[match(v$name,women)>0]

最新更新