R惰性评估ifelse逻辑条件
R lazy evaluation ifelse logical condition
我有以下 data.table
:
dtable <- data.table(column1 = c(1, 2, 3, 5, 6, 7, 8),
column2 = c(1, 1, 1, 5, 5, 6, 8),
column3 = c(7, 8, 9, 0, 9, 2, 3))
我想做类似以下功能的东西,但在参数化函数中:
dtable %>%
dplyr::group_by(column1) %>%
dplyr::summarise(Result = ifelse(column1 == column2, "A", "B"))
为此,我创建了以下函数:
Test <- function(.df, .columnName, .columnToGroup){
res <- .df %>%
# This line is interpreted correctly
dplyr::group_by_(lazyeval::interp(.columnToGroup, .columnToGroup = as.name(.columnToGroup))) %>%
# This line does not interpret the == condition as a logical one
dplyr::summarise_(Result = ifelse((lazyeval::interp(.columnToGroup == .columnName,
.columnToGroup = as.name(.columnToGroup),
.columnName = as.name(.columnName))),
"A", "B"))
return(res)
}
我将非标准求值函数(group_by_
和 summarise_
)与 lazyeval::interp
函数结合使用,但未解释 ==
条件正确的方法,我得到以下异常:
Test(dtable, "column1", "column2")
Error in UseMethod("interp") :
no applicable method for 'interp' applied to an object of class "logical"
我尝试了很多不同的组合(quote
、expr_env
、as.lazy
等),但都没有成功。感谢这个伟大的 Non-standard evaluation guide 我之前能够使用这些 lazyeval
函数来评估算术表达式,但我找不到让它们解释这段代码中的逻辑条件的方法。
如有任何帮助,我们将不胜感激。
有了ifelse
,我们可以试试(在评论中使用@docendodiscimus 使用list
)
Test <- function(.df, .columnName, .columnToGroup){
.df %>%
dplyr::group_by_(.dots = .columnToGroup )%>%
dplyr::summarise_(.dots =
setNames(list(lazyeval::interp(quote(ifelse(colGrp == colName,
"A", "B")), .values = list(colGrp = as.name(.columnToGroup),
colName = as.name(.columnName)))),
"Result"))
}
res2 <- Test(dtable, "column2", "column1")
identical(res1, res2)
#[1] TRUE
其中 'res1' 是
res1 <- dtable %>%
dplyr::group_by(column1) %>%
dplyr::summarise(Result = ifelse(column1 == column2, "A", "B"))
更新
有了 dplyr
的新版本,即 0.6.0
(等待 2017 年 4 月发布),我们也可以在 group_by
和 summarise
中取消引用。 enquo
函数与 base R
中的 substitute
执行类似的工作,通过接收输入参数可以创建一个 quosure
并且它没有被引用(!!
或 UQ
) 在 group_by
和 summarise
内进行评估
Test1 <- function(df, colN, colGrp){
colN <- enquo(colN)
colGrp <- enquo(colGrp)
df %>%
group_by(!!colGrp) %>%
summarise(Result = if_else((!!colGrp) == (!!colN), "A", "B"))
}
res3 <- Test1(dtable, column2, column1)
identical(res2, res3)
#[1] TRUE
我有以下 data.table
:
dtable <- data.table(column1 = c(1, 2, 3, 5, 6, 7, 8),
column2 = c(1, 1, 1, 5, 5, 6, 8),
column3 = c(7, 8, 9, 0, 9, 2, 3))
我想做类似以下功能的东西,但在参数化函数中:
dtable %>%
dplyr::group_by(column1) %>%
dplyr::summarise(Result = ifelse(column1 == column2, "A", "B"))
为此,我创建了以下函数:
Test <- function(.df, .columnName, .columnToGroup){
res <- .df %>%
# This line is interpreted correctly
dplyr::group_by_(lazyeval::interp(.columnToGroup, .columnToGroup = as.name(.columnToGroup))) %>%
# This line does not interpret the == condition as a logical one
dplyr::summarise_(Result = ifelse((lazyeval::interp(.columnToGroup == .columnName,
.columnToGroup = as.name(.columnToGroup),
.columnName = as.name(.columnName))),
"A", "B"))
return(res)
}
我将非标准求值函数(group_by_
和 summarise_
)与 lazyeval::interp
函数结合使用,但未解释 ==
条件正确的方法,我得到以下异常:
Test(dtable, "column1", "column2")
Error in UseMethod("interp") :
no applicable method for 'interp' applied to an object of class "logical"
我尝试了很多不同的组合(quote
、expr_env
、as.lazy
等),但都没有成功。感谢这个伟大的 Non-standard evaluation guide 我之前能够使用这些 lazyeval
函数来评估算术表达式,但我找不到让它们解释这段代码中的逻辑条件的方法。
如有任何帮助,我们将不胜感激。
有了ifelse
,我们可以试试(在评论中使用@docendodiscimus 使用list
)
Test <- function(.df, .columnName, .columnToGroup){
.df %>%
dplyr::group_by_(.dots = .columnToGroup )%>%
dplyr::summarise_(.dots =
setNames(list(lazyeval::interp(quote(ifelse(colGrp == colName,
"A", "B")), .values = list(colGrp = as.name(.columnToGroup),
colName = as.name(.columnName)))),
"Result"))
}
res2 <- Test(dtable, "column2", "column1")
identical(res1, res2)
#[1] TRUE
其中 'res1' 是
res1 <- dtable %>%
dplyr::group_by(column1) %>%
dplyr::summarise(Result = ifelse(column1 == column2, "A", "B"))
更新
有了 dplyr
的新版本,即 0.6.0
(等待 2017 年 4 月发布),我们也可以在 group_by
和 summarise
中取消引用。 enquo
函数与 base R
中的 substitute
执行类似的工作,通过接收输入参数可以创建一个 quosure
并且它没有被引用(!!
或 UQ
) 在 group_by
和 summarise
内进行评估
Test1 <- function(df, colN, colGrp){
colN <- enquo(colN)
colGrp <- enquo(colGrp)
df %>%
group_by(!!colGrp) %>%
summarise(Result = if_else((!!colGrp) == (!!colN), "A", "B"))
}
res3 <- Test1(dtable, column2, column1)
identical(res2, res3)
#[1] TRUE