【问题标题】:Filter data frame matching all values of a vector过滤匹配向量所有值的数据框
【发布时间】:2017-08-09 18:43:25
【问题描述】:

我想通过包含IDs 来过滤数据框IDs,其中包含与testVector所有 值匹配的Hour 行。 p>

ID <- c('A','A','A','A','A','B','B','B','B','C','C')
Hour <- c('0','2','5','6','9','0','2','5','6','0','2')

x <- data.frame(ID, Hour)
x
   ID Hour
1   A    0
2   A    2
3   A    5
4   A    6
5   A    9
6   B    0
7   B    2
8   B    5
9   B    6
10  C    0
11  C    2

testVector <- c('0','2','5')

该解决方案应产生以下数据框:

x
       ID Hour
    1   A    0
    2   A    2
    3   A    5
    4   A    6
    5   A    9
    6   B    0
    7   B    2
    8   B    5
    9   B    6

ID C 的所有值都被删除,因为它缺少 Hour 5。请注意,我想保留与 IDs 匹配的 Hour 的所有值 testVector

dplyr 解决方案是理想的,但欢迎任何解决方案。

基于 SO 上的其他相关问题,我猜我需要 %in%all 的某种组合,但我无法完全弄清楚。

【问题讨论】:

    标签: r


    【解决方案1】:

    %in%all 的组合听起来很有希望,在基础 R 中,您可以如下利用它们:

    to_keep = sapply(lapply(split(x,x$ID),function(x) {unique(x$Hour)}), 
                                                  function(x) {all(testVector %in% x)})
    x = x[x$ID %in% names(to_keep)[to_keep],]
    

    或类似,但根据 d.b. 跳过不必要的 lapply 和更有效。在 cmets 中:

    temp = sapply(split(x, x$ID), function(a) all(testVector %in% a$Hour))
    x[temp[match(x$ID, names(temp))],]
    

    输出:

      ID Hour
    1  A    0
    2  A    2
    3  A    5
    4  A    6
    5  A    9
    6  B    0
    7  B    2
    8  B    5
    9  B    6
    

    希望这会有所帮助!

    【讨论】:

    • 还有temp = sapply(split(x, x$ID), function(a) all(testVector %in% a$Hour)); x[temp[match(x$ID, names(temp))],]
    • 谢谢!您能否向我解释一下您的代码是如何工作的?特别是,我不明白嵌套的 lapply/sapply 是如何工作的。
    • @holastello,我将解释 d.b. 的版本:首先,我们根据 x$ID 列将数据帧分组。然后,我们用 sapply 遍历该列表,并使用function(a) 之后的函数来测试 testVector 中的所有元素是否也在 a$Hour 中。我希望能解释它,如果不让我知道!在我的解决方案中,我首先使用了另一个 lapply 来获取唯一值,但这是不必要的。
    • @d.b.这是一个更清洁的解决方案,谢谢分享!我把它添加到我的答案中,如果你同意的话。这就是为什么我喜欢堆栈溢出,这是向他人学习的好地方。
    【解决方案2】:

    这是另一个无需离开管道的dplyr 解决方案:

    ID <- c('A','A','A','A','A','B','B','B','B','C','C')
    Hour <- c('0','2','5','6','9','0','2','5','6','0','2')
    
    x <- data.frame(ID, Hour)
    
    testVector <- c('0','2','5')
    
    x %>%
      group_by(ID) %>%
      mutate(contains = Hour %in% testVector) %>%
      summarise(all = sum(contains)) %>%
      filter(all > 2) %>%
      select(-all) %>%
      inner_join(x)
    
    ##       ID   Hour
    ##   <fctr> <fctr>
    ## 1      A      0
    ## 2      A      2
    ## 3      A      5
    ## 4      A      6
    ## 5      A      9
    ## 6      B      0
    ## 7      B      2
    ## 8      B      5
    ## 9      B      6
    

    【讨论】:

    • 我很困惑。为什么不x %&gt;% group_by(ID) %&gt;% filter(all(testVector %in% Hour))
    • @Frank 是的,简单多了!
    【解决方案3】:

    这是一个使用来自base Rtable 的选项

    i1 <- !rowSums(table(x)[, testVector]==0)
    subset(x, ID %in% names(i1)[i1])
    #   ID Hour
    #1  A    0
    #2  A    2
    #3  A    5
    #4  A    6
    #5  A    9
    #6  B    0
    #7  B    2
    #8  B    5
    #9  B    6
    

    或者这可以通过data.table来完成

    library(data.table)
    setDT(x)[, .SD[all(testVector %in% Hour)], ID]
    #    ID Hour
    #1:  A    0
    #2:  A    2
    #3:  A    5
    #4:  A    6
    #5:  A    9
    #6:  B    0
    #7:  B    2
    #8:  B    5
    #9:  B    6
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-29
      • 2011-11-21
      • 2022-01-22
      • 1970-01-01
      • 2020-07-30
      • 1970-01-01
      • 1970-01-01
      • 2018-02-07
      相关资源
      最近更新 更多