【问题标题】:Filter columns based on the list of columns and list of values根据列列表和值列表过滤列
【发布时间】:2021-06-17 03:53:33
【问题描述】:

当具有列列表和相等值时,有没有办法在 R 中过滤(使用 tidyversedata.table)?

一个列表包含要过滤的列,第二个列表包含应分别选择第一个列表中的哪些列的值。


library(tidyverse)

df <- tibble(mtcars)

col1 <- c('mpg', 'am')
val1 <- c(21, 1)

# Pseudo idea of what I need
df %>%
  filter(col1 == val1)

# This is the results that shall be obtained by using col1 and val1

df %>% 
  filter(mpg == 21,
         am == 1)


col2 <- c('mpg', 'am', 'carb', 'vs')
val2 <- c(21, 1, 4, 0)

df %>%
  filter(col2 == val2)

但是,这应该是可概括的,并且只有过滤条件将始终为==,这一点非常重要。

另外,它需要自动化,因此它适用于只有一个元素的列表,例如:

col4 <- c('vs')
val4 <- c(0)

【问题讨论】:

    标签: r dplyr datatable tidyverse


    【解决方案1】:

    在较新版本的dplyr 中,我们还可以使用if_all(相当于all,即它将返回所有复合逻辑表达式都被&amp; 逻辑运算符折叠的行)。 |if_any)。在这种情况下,我们可以有一个 'val's 的named 向量`

    library(dplyr)
    names(val1) <- col1
    df %>%
        filter(if_all(all_of(col1), ~ . == val1[cur_column()]))
    # A tibble: 2 x 11
    #   mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
    #  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
    #1    21     6   160   110   3.9  2.62  16.5     0     1     4     4
    #2    21     6   160   110   3.9  2.88  17.0     0     1     4     4
    

    对于第二种情况

    names(val2) <- col2
    df %>% 
        filter(if_all(all_of(col2), ~ . == val2[cur_column()]))
    # A tibble: 2 x 11
    #    mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
    #  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
    #1    21     6   160   110   3.9  2.62  16.5     0     1     4     4
    #2    21     6   160   110   3.9  2.88  17.0     0     1     4     4 
    

    或者对于单元素向量

    names(val4) <- col4
    df %>% 
       filter(if_all(all_of(col4), ~ . == val4[cur_column()]))
    # A tibble: 18 x 11
    #     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
    #   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
    # 1  21       6  160    110  3.9   2.62  16.5     0     1     4     4
    # 2  21       6  160    110  3.9   2.88  17.0     0     1     4     4
    # 3  18.7     8  360    175  3.15  3.44  17.0     0     0     3     2
    # 4  14.3     8  360    245  3.21  3.57  15.8     0     0     3     4
    # 5  16.4     8  276.   180  3.07  4.07  17.4     0     0     3     3
    # 6  17.3     8  276.   180  3.07  3.73  17.6     0     0     3     3
    # 7  15.2     8  276.   180  3.07  3.78  18       0     0     3     3
    # 8  10.4     8  472    205  2.93  5.25  18.0     0     0     3     4
    # 9  10.4     8  460    215  3     5.42  17.8     0     0     3     4
    #10  14.7     8  440    230  3.23  5.34  17.4     0     0     3     4
    #11  15.5     8  318    150  2.76  3.52  16.9     0     0     3     2
    #12  15.2     8  304    150  3.15  3.44  17.3     0     0     3     2
    #13  13.3     8  350    245  3.73  3.84  15.4     0     0     3     4
    #14  19.2     8  400    175  3.08  3.84  17.0     0     0     3     2
    #15  26       4  120.    91  4.43  2.14  16.7     0     1     5     2
    #16  15.8     8  351    264  4.22  3.17  14.5     0     1     5     4
    #17  19.7     6  145    175  3.62  2.77  15.5     0     1     5     6
    #18  15       8  301    335  3.54  3.57  14.6     0     1     5     8
    

    或者另一种选择是创建一个表达式并使用 parse_expr 解析它

    library(stringr)
    df %>%
       filter(!! rlang::parse_expr(str_c(col1, val1, sep = '==', collapse="&")))
    

    第二种情况也一样

    df %>%
       filter(!! rlang::parse_expr(str_c(col2, val2, sep = '==', collapse="&")))
    
    # A tibble: 2 x 11
    #    mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
    #  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
    #1    21     6   160   110   3.9  2.62  16.5     0     1     4     4
    #2    21     6   160   110   3.9  2.88  17.0     0     1     4     4
    

    或更新后的情况

    df %>%
      filter(!! rlang::parse_expr(str_c(col4, val4, sep = '==', collapse="&")))
    
    # A tibble: 18 x 11
    #     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
    #   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
    # 1  21       6  160    110  3.9   2.62  16.5     0     1     4     4
    # 2  21       6  160    110  3.9   2.88  17.0     0     1     4     4
    # 3  18.7     8  360    175  3.15  3.44  17.0     0     0     3     2
    # 4  14.3     8  360    245  3.21  3.57  15.8     0     0     3     4
    # 5  16.4     8  276.   180  3.07  4.07  17.4     0     0     3     3
    # 6  17.3     8  276.   180  3.07  3.73  17.6     0     0     3     3
    # 7  15.2     8  276.   180  3.07  3.78  18       0     0     3     3
    # 8  10.4     8  472    205  2.93  5.25  18.0     0     0     3     4
    # 9  10.4     8  460    215  3     5.42  17.8     0     0     3     4
    #10  14.7     8  440    230  3.23  5.34  17.4     0     0     3     4
    #11  15.5     8  318    150  2.76  3.52  16.9     0     0     3     2
    #12  15.2     8  304    150  3.15  3.44  17.3     0     0     3     2
    #13  13.3     8  350    245  3.73  3.84  15.4     0     0     3     4
    #14  19.2     8  400    175  3.08  3.84  17.0     0     0     3     2
    #15  26       4  120.    91  4.43  2.14  16.7     0     1     5     2
    #16  15.8     8  351    264  4.22  3.17  14.5     0     1     5     4
    #17  19.7     6  145    175  3.62  2.77  15.5     0     1     5     6
    #18  15       8  301    335  3.54  3.57  14.6     0     1     5     8
    

    或者可以使用map2/reduce。在filter 中,循环遍历'col2'、'val2' 值,根据'col2' 检查数据是否等于相应的'val2' 值reduce list 的逻辑@ 987654339@s 到单个逻辑 vector&amp;filter 的行

    library(purrr)
    df %>%
      filter(map2(col2, val2, ~  cur_data()[[.x]] == .y) %>% reduce(`&`))
    

    或者另一种选择是在select从数据集中感兴趣的列之后使用rowSums创建逻辑表达式

    df %>%
       filter(!rowSums(select(., col2) != val2[col(select(., col2))]))
    

    或使用base R

    subset(df, Reduce(`&`, Map(`==`, df[col2], val2)))
    

    可以创建一个函数来执行此操作

    f1 <- function(dat, colnms, vals) {
    
      dat %>%
         filter(map2(colnms, vals, ~  cur_data()[[.x]] == .y) %>%
          reduce(`&`))
    
    
     }
    

    -测试

    f1(df, col1, val1)
    # A tibble: 2 x 11
        mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
      <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
    1    21     6   160   110   3.9  2.62  16.5     0     1     4     4
    2    21     6   160   110   3.9  2.88  17.0     0     1     4     4
    f1(df, col2, val2)
    # A tibble: 2 x 11
        mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
      <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
    1    21     6   160   110   3.9  2.62  16.5     0     1     4     4
    2    21     6   160   110   3.9  2.88  17.0     0     1     4     4
    f1(df, col4, val4)
    # A tibble: 18 x 11
         mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
       <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
     1  21       6  160    110  3.9   2.62  16.5     0     1     4     4
     2  21       6  160    110  3.9   2.88  17.0     0     1     4     4
     3  18.7     8  360    175  3.15  3.44  17.0     0     0     3     2
     4  14.3     8  360    245  3.21  3.57  15.8     0     0     3     4
     5  16.4     8  276.   180  3.07  4.07  17.4     0     0     3     3
     6  17.3     8  276.   180  3.07  3.73  17.6     0     0     3     3
     7  15.2     8  276.   180  3.07  3.78  18       0     0     3     3
     8  10.4     8  472    205  2.93  5.25  18.0     0     0     3     4
     9  10.4     8  460    215  3     5.42  17.8     0     0     3     4
    10  14.7     8  440    230  3.23  5.34  17.4     0     0     3     4
    11  15.5     8  318    150  2.76  3.52  16.9     0     0     3     2
    12  15.2     8  304    150  3.15  3.44  17.3     0     0     3     2
    13  13.3     8  350    245  3.73  3.84  15.4     0     0     3     4
    14  19.2     8  400    175  3.08  3.84  17.0     0     0     3     2
    15  26       4  120.    91  4.43  2.14  16.7     0     1     5     2
    16  15.8     8  351    264  4.22  3.17  14.5     0     1     5     4
    17  19.7     6  145    175  3.62  2.77  15.5     0     1     5     6
    18  15       8  301    335  3.54  3.57  14.6     0     1     5     8
    

    【讨论】:

    • 谢谢,我还添加了一条评论,因此它也适用于具有一个元素的列表
    • @Petr 这一切都适用于当前的解决方案。你测试了吗
    猜你喜欢
    • 2013-09-11
    • 2020-07-01
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-08
    • 1970-01-01
    • 2021-09-06
    相关资源
    最近更新 更多