我有一个数据框,像这样:
dataF <- data.frame(YEAR = 1996, MONTH = 10, LOCATION = "RIVER",stringsAsFactors = F)
我传递给一个函数,我想在其中创建一个如下所示的表达式:
YEAR == 1966 & MONTH == 10 & LOCATION == "RIVER"
然后我将在以下语句中传递给 dplyr::filter
dataSet %>% dplyr::filter(YEAR == 1966 & MONTH == 10 & LOCATION == "RIVER")
当然,我希望这个函数是通用的,所以我可以传递任何具有不同列标签的数据框。此数据框dataF
只是一个示例
在我的函数中,我已经能够制作表达式列表 其中每个元素都在循环中计算
cats <- names(dataF)
expres <- list()
for (i in 1:length(cats)) {
expres[[i]] <- rlang::expr(!!(rlang::sym(cats[i])) == !!(dataF[[cats[i]]]))
}
但是我无法弄清楚如何将它们全部组合成一个表达式。
一种选择是gather
、paste
并创建表达式
library(dplyr)
library(tidyr)
library(magrittr)
library(stringr)
out <- gather(dataF) %>%
mutate(value = sprintf('"%s"', value)) %>%
unite(key, key, value, sep='==') %>%
summarise(key = str_c(key, collapse=' & ')) %>%
pull(key) %>%
parse(text = .) %>%
extract2(1)
out
#YEAR == "1996" & MONTH == "10" & LOCATION == "RIVER"
str(out)
#language YEAR == "1996" & MONTH == "10" & LOCATION == "RIVER"
或使用imap
library(purrr)
out2 <- imap(dataF, ~ deparse(rlang::expr(!!(rlang::sym(.y)) == !!.x ) )) %>%
reduce(~ str_c(.x,.y, sep=" & ")) %>%
parse(text = .) %>%
extract2(1)
out2
#YEAR == 1996 & MONTH == 10 & LOCATION == "RIVER"
str(out2)
#language YEAR == 1996 & MONTH == 10 & LOCATION == "RIVER"
也可以在不经过expr
路线的情况下完成
imap(dataF, ~ if(is.character(.x)) sprintf('%s == "%s"', .y, .x)
else sprintf('%s == %s', .y, .x)) %>%
reduce(str_c,sep =" & ") %>%
parse(text = .) %>%
extract2(1)
#YEAR == 1996 & MONTH == 10 & LOCATION == "RIVER"
这是一个基本的 R 解决方案。它使用Reduce
来形成表达式的字符串,然后将其强制转换为具有str2lang
的语言对象。
f <- function(x, y) {
i <- sapply(y, is.character)
y[i] <- paste0("'", y[i], "'")
paste(x, y, sep = ' == ', collapse = ' & ')
}
expr <- Reduce(f, list(names(dataF), unname(as.list(dataF))))
str2lang(expr)
#YEAR == 1996 & MONTH == 10 & LOCATION == "RIVER"
str(str2lang(expr))
# language YEAR == 1996 & MONTH == 10 & LOCATION == "RIVER"
该问题要求一个执行上述操作的函数。
df2lang <- function(DF){
f <- function(x, y) {
i <- sapply(y, is.character)
y[i] <- paste0("'", y[i], "'")
paste(x, y, sep = ' == ', collapse = ' & ')
}
expr <- Reduce(f, list(names(DF), unname(as.list(DF))))
str2lang(expr)
}
df2lang(dataF)
#YEAR == 1996 & MONTH == 10 & LOCATION == "RIVER"
dataF2 <- data.frame(This = 1996, That = "A", x = "RIVER",stringsAsFactors = F)
df2lang(dataF2)
#This == 1996 & That == "A" & x == "RIVER"