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

时间:2016-11-06 04:30:41

标签: 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")

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)

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

我现在已经挣扎了3个多小时。我通过SO Select rows with at least two conditions from all conditions查看了自动建议的帖子,但我的问题非常不同。

1 个答案:

答案 0 :(得分:3)

我会这样做:

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

说明:如果有任何符合条件的行(在组内),any()将返回TRUE。然后将长度为1的结果再循环到组的整个长度,并保留整个组。您也可以使用sum(Product_name %in% "ABCD") > 0作为条件,但任何读取非常好。如果您想要更复杂的条件,请使用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