我有这样的数据框:
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
中包含每个变量之外,我还可以选择列表中的元素并使用列表名称过滤数据框吗?
答案 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)
涉及dplyr
,tidyr
和purrr
的一种解决方案可能是:
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