在 dplyr 中使用 "get"
Use of "get" in dplyr
背景是我有一些遗留代码在几个地方使用 plyr,直到几天前,plyr 还没有更新以使其与 R 3.5 一起使用。我认为这是对 plyr 支持减少的一个信号,因此我正在研究将 plyr 命令更改为 dplyr。遗留代码中的 ddply 命令涉及一些 "get" 命令来引用其名称包含在变量中的列。直接翻译将涉及以下类型的代码(一个人为的例子,但它说明了这一点)。它似乎有效,并使其最接近原始代码,但是这样做有什么陷阱吗?我的印象是这不是制造商认可的使用 dplyr 编程的方式!
示例代码:
library("dplyr")
testFunction <- function(dataset, groupcol, varcol){
summaryTable <- dataset %>%
group_by(get(groupcol)) %>%
summarise(mean_var = mean(get(varcol)),
sd_var = sd(get(varcol)))
return(summaryTable)
}
testGroup <- "cyl"
testVar <- "mpg"
testFunction(mtcars, testGroup, testVar)
作为恐龙,我很想从 plyr 转换回 base-R(看不到 "get"s),例如类似于:
fossilFunction <- function(dataset, groupcol, varcol){
z <- by(dataset, dataset[ , testGroup], function(x){
c(mean_var = mean(x[ , varcol]),
sd_var = sd(x[ , varcol]))
})
z <- do.call(rbind, z)
data.frame(rownames(z), z, row.names = NULL)
}
testGroup <- "cyl"
testVar <- "mpg"
fossilFunction(mtcars, testGroup, testVar)
在这种情况下,速度不是问题。但是,必须努力向前看,而不是向后看...
我们可以使用 sym
将其转换为 symbol
如果我们传递一个字符串变量然后用 !!
求值
testFunction <- function(dataset, groupcol, varcol){
varcol <- rlang::sym(varcol)
dataset %>%
group_by(!! rlang::sym(groupcol)) %>%
summarise(mean_var = mean(!! varcol),
sd_var = sd(!! varcol))
}
testFunction(mtcars, testGroup, testVar)
# A tibble: 3 x 3
# cyl mean_var sd_var
# <dbl> <dbl> <dbl>
#1 4 26.7 4.51
#2 6 19.7 1.45
#3 8 15.1 2.56
或者不使用rlang
,我们也可以将字符串传入group_by_at
和summarise_at
testFunction <- function(dataset, groupcol, varcol){
dataset %>%
group_by_at(groupcol)%>%
summarise_at(vars(varcol), funs(mean, sd))
}
testFunction(mtcars, testGroup, testVar)
dplyr
的最新版本允许使用 bang-bang 运算符 (!!
) 将变量插入到函数调用中。应避免使用 get()
函数。您可以通过以下方式修复您的功能
testFunction <- function(dataset, groupcol, varcol){
groupcol <- as.name(groupcol)
varcol <- as.name(varcol)
summaryTable <- dataset %>%
group_by(!!groupcol) %>%
summarise(mean_var = mean(!!varcol),
sd_var = sd(!!varcol))
return(summaryTable)
}
testGroup <- "cyl"
testVar <- "mpg"
testFunction(mtcars, testGroup, testVar)
有关详细信息,请参阅 programming with dplyr vignette。
就我个人而言,我反对这里的一些正统观念,我只是在某些情况下使用 get
:
testFunction <- function(dataset, groupcol, varcol){
dataset %>%
group_by(get(groupcol)) %>%
summarise(mean_var = mean(get(varcol)),
sd_var = sd(get(varcol)))
}
或者,我在 .
或 .data
对象上使用双括号 [[
:
testFunction <- function(dataset, groupcol, varcol){
dataset %>%
group_by(.data[[groupcol]]) %>%
summarise(mean_var = mean(.data[[varcol]]),
sd_var = sd(.data[[varcol]]))
}
我发现 get(x)
比 !!as.name(x)
或 !!rlang::sym(x)
更简单直观多年来,base
命名空间中的内置函数可能会成为我在接下来几年中求助的对象。
背景是我有一些遗留代码在几个地方使用 plyr,直到几天前,plyr 还没有更新以使其与 R 3.5 一起使用。我认为这是对 plyr 支持减少的一个信号,因此我正在研究将 plyr 命令更改为 dplyr。遗留代码中的 ddply 命令涉及一些 "get" 命令来引用其名称包含在变量中的列。直接翻译将涉及以下类型的代码(一个人为的例子,但它说明了这一点)。它似乎有效,并使其最接近原始代码,但是这样做有什么陷阱吗?我的印象是这不是制造商认可的使用 dplyr 编程的方式!
示例代码:
library("dplyr")
testFunction <- function(dataset, groupcol, varcol){
summaryTable <- dataset %>%
group_by(get(groupcol)) %>%
summarise(mean_var = mean(get(varcol)),
sd_var = sd(get(varcol)))
return(summaryTable)
}
testGroup <- "cyl"
testVar <- "mpg"
testFunction(mtcars, testGroup, testVar)
作为恐龙,我很想从 plyr 转换回 base-R(看不到 "get"s),例如类似于:
fossilFunction <- function(dataset, groupcol, varcol){
z <- by(dataset, dataset[ , testGroup], function(x){
c(mean_var = mean(x[ , varcol]),
sd_var = sd(x[ , varcol]))
})
z <- do.call(rbind, z)
data.frame(rownames(z), z, row.names = NULL)
}
testGroup <- "cyl"
testVar <- "mpg"
fossilFunction(mtcars, testGroup, testVar)
在这种情况下,速度不是问题。但是,必须努力向前看,而不是向后看...
我们可以使用 sym
将其转换为 symbol
如果我们传递一个字符串变量然后用 !!
testFunction <- function(dataset, groupcol, varcol){
varcol <- rlang::sym(varcol)
dataset %>%
group_by(!! rlang::sym(groupcol)) %>%
summarise(mean_var = mean(!! varcol),
sd_var = sd(!! varcol))
}
testFunction(mtcars, testGroup, testVar)
# A tibble: 3 x 3
# cyl mean_var sd_var
# <dbl> <dbl> <dbl>
#1 4 26.7 4.51
#2 6 19.7 1.45
#3 8 15.1 2.56
或者不使用rlang
,我们也可以将字符串传入group_by_at
和summarise_at
testFunction <- function(dataset, groupcol, varcol){
dataset %>%
group_by_at(groupcol)%>%
summarise_at(vars(varcol), funs(mean, sd))
}
testFunction(mtcars, testGroup, testVar)
dplyr
的最新版本允许使用 bang-bang 运算符 (!!
) 将变量插入到函数调用中。应避免使用 get()
函数。您可以通过以下方式修复您的功能
testFunction <- function(dataset, groupcol, varcol){
groupcol <- as.name(groupcol)
varcol <- as.name(varcol)
summaryTable <- dataset %>%
group_by(!!groupcol) %>%
summarise(mean_var = mean(!!varcol),
sd_var = sd(!!varcol))
return(summaryTable)
}
testGroup <- "cyl"
testVar <- "mpg"
testFunction(mtcars, testGroup, testVar)
有关详细信息,请参阅 programming with dplyr vignette。
就我个人而言,我反对这里的一些正统观念,我只是在某些情况下使用 get
:
testFunction <- function(dataset, groupcol, varcol){
dataset %>%
group_by(get(groupcol)) %>%
summarise(mean_var = mean(get(varcol)),
sd_var = sd(get(varcol)))
}
或者,我在 .
或 .data
对象上使用双括号 [[
:
testFunction <- function(dataset, groupcol, varcol){
dataset %>%
group_by(.data[[groupcol]]) %>%
summarise(mean_var = mean(.data[[varcol]]),
sd_var = sd(.data[[varcol]]))
}
我发现 get(x)
比 !!as.name(x)
或 !!rlang::sym(x)
更简单直观多年来,base
命名空间中的内置函数可能会成为我在接下来几年中求助的对象。