【问题标题】:Search for data.frame indices according to multiple column criteria - how to speed up for large data sets?根据多列标准搜索 data.frame 索引 - 如何加快大型数据集?
【发布时间】:2019-12-05 23:14:29
【问题描述】:

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

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

我读到 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]}
}

这适用于较小的数据集,但在 case 中有 500K 记录,在 data.df 中有 50M 时,运行需要超过 12 小时。一定有更简单的方法,谁能给个提示?

【问题讨论】:

标签: r performance dataframe search data.table


【解决方案1】:

如果我理解正确,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's 方法 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

这种方法首先选择namewomen 匹配的行(通过连接),然后与cases 右连接,这样每个案例在结果向量中都有对应的条目:

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

讨论

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

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

【讨论】:

  • 您好,感谢您提供全面的答复。我尝试了第一种方法并且它有效(它有多快!)但会检查其他两种方法,看看哪一种最快。
【解决方案2】:

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

然后,您可以使用 {dplyr} 快速完成:

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

【讨论】:

  • 感谢您指出这一点!您是对的,最好将结果保留为列表。您的解决方案应该适用于我正在尝试做的事情,即。确定每年结婚的人,但实际上会有超过 2 人符合条件的奇怪案例,因此 ind 大于 1。
【解决方案3】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-20
    • 2021-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多