根据列列表和值列表过滤列
Filter columns based on the list of columns and list of values
有列列表和相等值时如何在 R 中进行过滤(使用 tidyverse
或 data.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)
在 dplyr
的较新版本中,我们还可以使用 if_all
(相当于 all
即它将 return 所有复合逻辑表达式所在的行由 &
逻辑运算符折叠)。 |
对应的是 if_any
)。在这种情况下,我们可以有一个 named
vector` of 'val's
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
逻辑 vector
的 list
到单个逻辑 vector
与 &
到 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
有列列表和相等值时如何在 R 中进行过滤(使用 tidyverse
或 data.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)
在 dplyr
的较新版本中,我们还可以使用 if_all
(相当于 all
即它将 return 所有复合逻辑表达式所在的行由 &
逻辑运算符折叠)。 |
对应的是 if_any
)。在这种情况下,我们可以有一个 named
vector` of 'val's
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
逻辑 vector
的 list
到单个逻辑 vector
与 &
到 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