【问题标题】:R - dplyr - filter top_n rows based on multiple conditionsR - dplyr - 根据多个条件过滤 top_n 行
【发布时间】:2018-07-10 02:32:55
【问题描述】:

嗨,这是我的第一篇文章,

我希望它是正确且可重现的。

我想知道是否有比我下面的方法更优雅的解决方案

我有一个数据框,想使用条件过滤器并提取满足这些条件的行。

作为输出,我希望 top_n 行满足条件标准(不同列的 top_n 输出的不同条件),同时保留所有其他列。

示例数据框:

 set.seed(123)
  df1 <- data.frame(
  A = as.numeric(1:10),
  B = sample(seq(as.Date('2000/01/01'), as.Date('2018/01/01'), by="day"), size=10),
  C = as.numeric(sample(20:90, size = 10)),
  D = sample(c("yes", "no"), size=10, replace = TRUE),
  E = as.numeric(sample(1000:2000, size = 10))
)


df1 #check output

> df1 #check output
    A          B  C   D    E
1   1 2005-03-06 87  no 1963
2   2 2014-03-11 51  no 1902
3   3 2007-05-12 66  no 1690
4   4 2015-11-22 58  no 1793
5   5 2016-12-02 26  no 1024
6   6 2000-10-26 79  no 1475
7   7 2009-07-01 35  no 1754
8   8 2016-01-19 22  no 1215
9   9 2009-11-30 40 yes 1315
10 10 2008-03-17 85 yes 1229

我想用于过滤的条件:

A) 如果 E 列介于 1000 和 1500 之间,则返回 A 列加权的前 2 行

B) 如果 E 列介于 1000 和 2000 之间,则返回在 B 列上加权的前 2 行

C) 如果 E 列介于 1000 和 1400 之间,则返回 C 列加权的前 2 行

我想出了以下解决方案,但它很麻烦,我想知道是否有更好的方法。

library("dplyr")
library("tidyr")
A<- df1 %>% dplyr::filter(E >= 1000 & E <= 1500) %>% top_n( n = 2, wt = A)  %>% arrange(-A) %>% mutate(condition = "-cond_A")
B<- df1 %>% dplyr::filter(E >= 1000 & E <= 2000) %>% top_n( n = 2, wt = B) %>% arrange(B) %>% mutate(condition = "cond_B")
C<- df1 %>% dplyr::filter(E >= 1000 & E <= 1400) %>% top_n( n = 2, wt = C) %>% arrange(-C) %>% mutate(condition = "-cond_C")

我想要的输出如下:

spread(as.data.frame(distinct(bind_rows(A,B,C))),condition, condition)

   A          B  C   D    E -cond_A -cond_C cond_B
1  5 2016-12-02 26  no 1024    <NA>    <NA> cond_B
2  8 2016-01-19 22  no 1215    <NA>    <NA> cond_B
3  9 2009-11-30 40 yes 1315 -cond_A -cond_C   <NA>
4 10 2008-03-17 85 yes 1229 -cond_A -cond_C   <NA>

如果你能告诉我一个更好的方法,那就太好了!

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    我们可以使用purrr 中的map2 来循环遍历更改的&lt;= 条件以及采用列名的wt 参数(基于OP 的代码)

    library(purrr)
    library(dplyr)
    library(tidyr)
    map2(c(1500, 2000, 1400), names(df1)[1:3],
              ~ df1 %>%
                     filter(E >= 1000 & E <= .x) %>%
                     top_n(n=2, wt = !! rlang::sym(.y)) %>% 
                     arrange_at(.y, funs(desc(.))) %>%
                     mutate(condition = paste0("-cond", .y)))  %>%
                     bind_rows %>% 
                     distinct %>% 
                     spread(condition, condition) 
    #   A          B  C   D    E -condA -condB -condC
    #1  5 2016-12-02 26  no 1024   <NA> -condB   <NA>
    #2  8 2016-01-19 22  no 1215   <NA> -condB   <NA>
    #3  9 2009-11-30 40 yes 1315 -condA   <NA> -condC
    #4 10 2008-03-17 85 yes 1229 -condA   <NA> -condC
    

    【讨论】:

    • 谢谢,阿克伦!这看起来很整洁,我需要了解更多关于 map2 的信息。另外,你能解释一下 top_n(n=2, wt = !! rlang::sym(.y)) 行吗?
    • 另外,如果下限 (1000) 并不总是相同,是否可以修改?例如。如果我想要 1000-1500 和 1200-2000 和 1300-1400?
    • @Moe 看来你想通了
    【解决方案2】:

    太好了,非常感谢!

    在我的 cmets 中,我问你是否可以为 map2 提供更多参数,我意识到 pmap 可以做到这一点。

    pmap(list(c(1500, 2000, 1400), c(1000, 1700, 1300), names(df1)[1:3]),
         ~ df1 %>%
           filter(E >= ..2 & E <= ..1) %>%
           top_n(n=2, wt = !! rlang::sym(..3)) %>% 
           arrange_at(..3, funs(desc(.))) %>%
           mutate(condition = paste0("-cond", ..3)))  %>%
      bind_rows %>% 
      distinct %>% 
      spread(condition, condition) 
    

    【讨论】:

      猜你喜欢
      • 2021-07-06
      • 2023-03-13
      • 1970-01-01
      • 2013-09-06
      • 1970-01-01
      • 2020-12-26
      • 1970-01-01
      • 2015-01-29
      • 2018-04-13
      相关资源
      最近更新 更多