根据多列标准搜索data.frame索引-如何加快处理大型数据集?

问题描述 投票:0回答:2

我有一个很大的data.frame(5,000万行),需要找到匹配多列条件的索引。

我制作了一个玩具示例来说明问题。

[我读到here,通过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个小时来运行。必须有一种更简单的方法,任何人都可以给出提示吗?

r performance dataframe search data.table
2个回答
0
投票

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

然后,您可以使用{dplyr}快速执行此操作:

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

0
投票

[如果我理解正确,那么OP希望先通过id过滤其数据集,然后如果在age中找到了name,则返回women(否则将返回NA

下面是不同的data.table方法,它们返回预期的结果

20 40 NA

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

id过滤,与women匹配

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

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

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

,它将NA设置为默认值。

请注意,Cole's方法data.dt[J(cases)][name %in% women]仅返回具有2行的过滤数据集,而不返回预期结果。

id过滤,与women结合

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

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

[加入women,然后加入cases

此方法首先选择namewomen匹配的行(通过联接,然后与cases联接:

setkey(data.dt, id)
data.dt[.(women), on = .(name = V1), nomatch = 0L][cases, age]
© www.soinside.com 2019 - 2024. All rights reserved.