【问题标题】:Get all rows fulfilling a condition by group with R data.table使用 R data.table 按组获取满足条件的所有行
【发布时间】:2017-06-27 14:35:36
【问题描述】:

假设我们有这个玩具 data.table

prueba  <- data.table(id=c(1,1,1,1,2,2,3,3,4), kk=c("FA", "N","N","N",NA,"FA","N", "FA", "N"), rrr=1:9)

id kk rrr
1 FA   1
1  N   2
1  N   3
1  N   4
2 NA   5
2 FA   6
3  N   7
3 FA   8
4  N   9

如果该 id 在 kk 列上包含任何“FA”值,我们希望检索与给定“id”相关的所有行。

我必须这样做:

prueba[id %in% prueba[,any(kk=="FA", na.rm=T),
   by=id]$id[prueba[,any(kk=="FA", na.rm=T),by=id]$V1],]

id kk rrr
1 FA   1
1  N   2
1  N   3
1  N   4
2 NA   5
2 FA   6
3  N   7
3 FA   8

(我们得到所有 id=1,2 和 3 的行)。

但我觉得太长了,没有优化。

如何使用 data.table 轻松完成?

【问题讨论】:

  • 通过连接,您可以使用 prueba[prueba[kk == "FA", .(id)], on="id"] 或使用 unique,如果每个 ID 有多个 FA 实例:prueba[unique(prueba[kk == "FA", .(id)]), on="id"]
  • 你也可以使用prueba[, if(any(kk == "FA")) .SD, by= id]
  • prueba[id %in% unique(prueba[kk == "FA", id])] 也可以。
  • @docendodiscimus 我发现您的解决方案是最简单的。如果您将其发布为答案,我会选择它。
  • @skan,请随时自行发布,也许与 cmets 中的其他建议一起发布

标签: r data.table


【解决方案1】:

我不确定是否优化,但已清理并使用 dplyr:

library(dplyr)
prueba %>% 
    group_by(id) %>% 
    filter('FA'%in%kk)

# A tibble: 8 x 3
# Groups:   id [3]
     id    kk   rrr
  <dbl> <chr> <int>
1     1    FA     1
2     1     N     2
3     1     N     3
4     1     N     4
5     2  <NA>     5
6     2    FA     6
7     3     N     7
8     3    FA     8

【讨论】:

  • dplyr::flter 根据我的经验应该很快
  • 我认为它应该很快。但我从来没有参与过速度/优化对话,因为我的数据几乎从不需要关注。所以我不会提出我无法支持的论点。
  • 问题是关于data.table,而不是dplyr
  • 是的,不知何故我错过了。我的意思是,我注意到 data.table 已被用于构建和改变数据,但我没有注意到标题中的标签或它。而且我喝了很多咖啡。我想我会删除这个。
【解决方案2】:

对于 data.table 案例,我会将您的代码简化为:

prueba  <- data.table(id=c(1,1,1,1,2,2,3,3,4), kk=c("FA", "N","N","N",NA,"FA","N", "FA", "N"), rrr=1:9)  

prueba[id %in% unique(prueba[kk=="FA",id])]

输出是:

   id kk rrr
1:  1 FA   1
2:  1  N   2
3:  1  N   3
4:  1  N   4
5:  2 NA   5
6:  2 FA   6
7:  3  N   7
8:  3 FA   8 

【讨论】:

    【解决方案3】:

    我一直在尝试使用微基准测试的不同解决方案:

    prueba  <- data.table(id=rep(c(1,1,1,1,2,2,3,3,4),1000000), kk=rep(c("FA", "N","N","N",NA,"FA","N", "FA", "N"),1000000), rrr=rep(1:9),1000000)
    
    prueba[, if(any(kk == "FA")) .SD, by= id]               # docendo
    prueba[id %in% unique(prueba[kk == "FA", id])]          # lmo
    prueba[id %in% prueba[, .I[kk == "FA"], by = id]$id,]   # eddi
    prueba[id %in% prueba[,any(kk=="FA", na.rm=T),by=id]
       $id[prueba[,any(kk=="FA", na.rm=T),by=id]$V1],]      # skan
    prueba %>%   group_by(id) %>%   filter('FA'%in%kk)      # Andrew
    prueba[prueba[kk == "FA", .(id)], on="id"]              # lmo
    

    .

    min       lq       mean     median       uq     max    name
    2.206436 2.211022 2.258038 2.215607 2.283839 2.352071   docendo
    1.456590 1.472334 1.596654 1.488077 1.666687 1.845296   lmo
    2.767113 2.869260 2.953024 2.971408 3.045980 3.120552   eddi
    3.431671 3.437914 3.451760 3.444157 3.461804 3.479451   skan
    2.088516 2.247807 2.313196 2.407098 2.425535 2.443973   Andrew
    

    lmo 的最后一个解决方案不起作用,它说:

    在 vecseq(f__, len__, if (allow.cartesian || notjoin || !anyDuplicated(f__, : 连接结果超过 2^31 行 (内部 vecseq 达到物理极限)。很可能指定错误 加入。检查 i 中的重复键值,每个键值都连接到 x 中的同一组一遍又一遍。如果没关系,请尝试通过=.EACHI 来 为每个组运行 j 以避免大量分配。

    我希望在方法之间看到更大的差异。也许使用不同的数据集。 迄今为止最快的方法似乎是:

    prueba[id %in% unique(prueba[kk == "FA", id])] 
    

    我想使用 .I、.GRP 或此类函数必须有更好的选择。

    【讨论】:

      猜你喜欢
      • 2016-12-04
      • 2021-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多