【问题标题】:Filter data frame columns based on list values根据列表值过滤数据框列
【发布时间】:2020-07-01 11:40:48
【问题描述】:

我有一个这样的数据框:

df <- data.frame(var1 = c(1,1,3,4,5,6,7,8,9),
       var2 = c(11,11,33,44,55,66,77,88,99),
       var3 = c(111,111,333,444,555,666,777,888,999),
       var4 = c(1111,1111,3333,4444,5555,6666,7777,8888,9999))
> df
  var1 var2 var3 var4
1    1   11  111 1111
2    1   11  111 1111
3    3   33  333 3333
4    4   44  444 4444
5    5   55  555 5555
6    6   66  666 6666
7    7   77  777 7777
8    8   88  888 8888
9    9   99  999 9999

我想根据存储在列表中的多个列值过滤特定行。

例如:

my_list <- list(var1 = 1,
     var2 = 11,
     var3 = 111)
filtered_df <- df %>% filter(var1 == my_list$var1[[1]],
              var2 == my_list$var2[[1]],
              var3 == my_list$var3[[1]])
> filtered_df
  var1 var2 var3 var4
1    1   11  111 1111
2    1   11  111 1111

我可以选择列表中的元素并使用列表名称过滤数据框,而不是包含 filter 中的每个变量吗?

【问题讨论】:

  • 啊,如果所有问题都像这样结构良好且对帮助者友好!

标签: r list dataframe filter


【解决方案1】:

您的建议与data.table中的自然方式非常相似:

library(data.table)
setDT(df)
df[my_list, on = .(var1, var2, var3)]

   var1 var2 var3 var4
1:    1   11  111 1111
2:    1   11  111 1111

如果你先指定你的key,过滤会更简洁:

setkey(df, var1, var2, var3)
df[my_list]

一个 base R 替代:

df[rowSums(df[1:3] == my_list) == 3L, ]

【讨论】:

    【解决方案2】:

    这是使用rlang::parse_expr() 的替代方法:

    library(dplyr)
    library(rlang)
    
    df %>%
      filter(!!parse_expr(paste(names(my_list), my_list, sep = "==", collapse = "&")))
    
      var1 var2 var3 var4
    1    1   11  111 1111
    2    1   11  111 1111
    

    【讨论】:

    • 感谢您的回答。只是一个快速跟进的问题。如何强制 parse_expr 包含特殊字符,例如“_”。例如,如果我的 df 中的第一行现在是:var1 = "1_1", var2 = 11, var3 = 111, var4 = 1111my_list = list(var1 = "1_1", var 2 = 11, var3 = 111)
    【解决方案3】:

    涉及dplyrtidyrpurrr 的解决方案可能是:

    map_dfr(.x = imap(my_list, setNames), 
            ~ enframe(.x) %>%
             inner_join(df %>%
                         rowid_to_column() %>%
                         pivot_longer(-rowid))) %>%
     group_by(rowid) %>%
     filter(n() == length(my_list)) %>%
     slice(1) %>%
     inner_join(df %>%
                 rowid_to_column(), by = c("rowid" = "rowid")) %>%
     ungroup() %>%
     select(starts_with("var"))
    
       var1  var2  var3  var4
      <dbl> <dbl> <dbl> <dbl>
    1     1    11   111  1111
    2     1    11   111  1111
    

    【讨论】:

    • 感谢您的解决方案。这很有教育意义,但有些复杂。
    【解决方案4】:

    一个基本的 R 解决方案是这样的:

    首先,您将列表中的值粘贴在一起,并用交替标记 | 折叠它们:

    my_list_1 <- paste0(unlist(my_list), collapse = "|")
    my_list_1
    [1] "1|11|111"
    

    然后,使用此替换字符串 my_list_1 以及使用 apply 将数据框的行粘贴在一起,您将数据框子集到与 my_list_1 匹配的那些行上:

    df[which(grepl(my_list_1, apply(df, 1, paste0, collapse = " "))),]
      var1 var2 var3 var4
    1    1   11  111 1111
    2    1   11  111 1111
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-22
      • 2023-03-22
      • 1970-01-01
      相关资源
      最近更新 更多