选择至少具有一个匹配条件的分组行

wat*_*wer 0 r dplyr

我想选择至少包含我感兴趣的元素之一的所有分组。我可以通过创建中间数组来做到这一点,但我正在寻找更简单、更快的东西。这是因为我的实际数据集有超过 1M 行(和 20 列),所以我不确定是否有足够的内存来创建中间数组。更重要的是,下面对我的原始文件的方法需要花费很多时间。

这是我的代码和数据:

a) 数据

dput(Data_File)
structure(list(Group_ID = c(123, 123, 123, 123, 234, 345, 444, 
444), Product_Name = c("ABCD", "EFGH", "XYZ1", "Z123", "ABCD", 
"EFGH", "ABCD", "ABCD"), Qty = c(2, 3, 4, 5, 6, 7, 8, 9)), .Names = c("Group_ID", 
"Product_Name", "Qty"), row.names = c(NA, 8L), class = "data.frame")
Run Code Online (Sandbox Code Playgroud)

b) 代码:我想选择Group_ID至少有一个Product_Name = ABCD

#Find out transactions
    Data_T <- Data_File %>% 
      group_by(Group_ID) %>%
      dplyr::filter(Product_Name == "ABCD") %>%
      select(Group_ID) %>%
      distinct()

    #Now filter them
    Filtered_T <- Data_File %>% 
      group_by(Group_ID) %>%
      dplyr::filter(Group_ID %in% Data_T$Group_ID)
Run Code Online (Sandbox Code Playgroud)

c) 预期输出为

  Group_ID Product_Name   Qty
     <dbl>        <chr> <dbl>
      123         ABCD     2
      123         EFGH     3
      123         XYZ1     4
      123         Z123     5
      234         ABCD     6
      444         ABCD     8
      444         ABCD     9
Run Code Online (Sandbox Code Playgroud)

我现在已经为此苦苦挣扎了3个多小时。我查看了自动建议的线程 SO:从所有条件中选择至少有两个条件的行,但我的问题非常不同。

Gre*_*gor 5

我会这样做:

Data_File %>% group_by(Group_ID) %>%
    filter(any(Product_Name %in% "ABCD"))
# Source: local data frame [7 x 3]
# Groups: Group_ID [3]
# 
#   Group_ID Product_Name   Qty
#      <dbl>        <chr> <dbl>
# 1      123         ABCD     2
# 2      123         EFGH     3
# 3      123         XYZ1     4
# 4      123         Z123     5
# 5      234         ABCD     6
# 6      444         ABCD     8
# 7      444         ABCD     9
Run Code Online (Sandbox Code Playgroud)

说明:如果有任何行(组内)符合条件,any()则返回。TRUE然后,长度为 1 的结果将被回收到组的完整长度,并且整个组将被保留。您也可以使用sum(Product_name %in% "ABCD") > 0as 条件来执行此操作,但 any 读起来非常好。sum如果您想要更复杂的条件(例如 3 个或更多匹配的产品名称),请使用替代方案。

我更喜欢%in%这样==的事情,因为它具有更好的行为,NA并且如果您想按组检查多个产品中的任何一个,它很容易扩展。


如果速度和效率是一个问题,data.table会更快。我会这样做,它依赖于键控连接进行过滤并且不使用非 data.table 操作,因此它应该非常快:

library(data.table)
df = as.data.table(df)
setkey(df)
groups = unique(subset(df, Product_Name %in% "ABCD", Group_ID))
df[groups, nomatch = 0]
#    Group_ID Product_Name Qty
# 1:      123         ABCD   2
# 2:      123         EFGH   3
# 3:      123         XYZ1   4
# 4:      123         Z123   5
# 5:      234         ABCD   6
# 6:      444         ABCD   8
# 7:      444         ABCD   9
Run Code Online (Sandbox Code Playgroud)