根据列表值过滤数据框列

时间:2020-03-20 10:29:42

标签: r list dataframe filter

我有这样的数据框:

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中包含每个变量之外,我还可以选择列表中的元素并使用列表名称过滤数据框吗?

4 个答案:

答案 0 :(得分:2)

您建议的内容与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

如果您先指定密钥,则过滤更加简洁:

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

一个基本R 替代方案:

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

答案 1 :(得分:1)

基本的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

答案 2 :(得分:1)

涉及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

答案 3 :(得分:1)

这是使用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