阅读并重新阅读使用dplyr"编写的许多"编程指南,我仍然无法找到解决我的具体案例的方法。
我理解使用group_by_
,mutate_
和#34;字符串友好" tidyverse函数的版本正朝着弃用方向发展,enquo
是可行的方法。
然而,我的情况有所不同,我正在努力寻找一种整洁的方式来解决它。
实际上,我的目标是在函数中创建和操作数据帧。根据其他人创建(变异)新变量,使用它们等等。
但是,无论我怎么努力,我的代码都会出错或在包检查时返回一些警告,例如no visible binding for global variable ...
。
这是一个可重现的例子:
这是我想做的事情:
df <- data.frame(X=c("A", "B", "C", "D", "E"),
Y=c(1, 2, 3, 1, 1))
new_df <- df %>%
group_by(Y) %>%
summarise(N=n()) %>%
mutate(Y=factor(Y, levels=1:5)) %>%
complete(Y, fill=list(N = 0)) %>%
arrange(Y) %>%
rename(newY=Y) %>%
mutate(Y=as.integer(newY))
预期结果的一些常见的dplyr操作应该是:
# A tibble: 5 x 3
newY N Y
<fctr> <dbl> <int>
1 1 3 1
2 2 1 2
3 3 1 3
4 4 0 4
5 5 0 5
我希望这段代码能够在内部一个函数中安静地工作。以下是我处理非NSE问题的最佳尝试:
myfunction <- function(){
df <- data.frame(X=c("A", "B", "C", "D", "E"),
Y=c(1, 2, 3, 1, 1))
new_df <- df %>%
group_by_("Y") %>%
summarise(!!"N":=n()) %>%
mutate(!!"Y":=factor(Y, levels=1:5)) %>%
complete_("Y", fill=list(N = 0)) %>%
arrange_("Y") %>%
rename(!!"newY":="Y") %>%
mutate(!!"Y":=as.integer(newY))
}
不幸的是,我仍然收到以下消息:
myfunction: no visible global function definition for ':='
myfunction: no visible binding for global variable 'Y'
myfunction: no visible binding for global variable 'newY'
Undefined global functions or variables:
:= Y n.Factors n_optimal newY
有办法解决吗?非常感谢!
编辑:我使用的是R 3.4.1,dplyr_0.7.4,tidyr_0.7.2和tidyverse_1.1.1
感谢我已经设法解决的问题,以下是工作解决方案:
myfunction <- function(){
df <- data.frame(X=c("A", "B", "C", "D", "E"),
Y=c(1, 2, 3, 1, 1))
new_df <- df %>%
group_by_("Y") %>%
summarise_("N"=~n()) %>%
mutate_("Y"= ~factor(Y, levels=1:5)) %>%
complete_("Y", fill=list(N = 0)) %>%
arrange_("Y") %>%
rename_("newY"=~Y) %>%
mutate_("Y"=~as.integer(newY))
}
非常感谢:)
答案 0 :(得分:3)
答案并非在&#34;使用dplyr进行编程&#34;指南,因为您的问题更为一般。虽然您的代码处理非标准评估,但您的案例并不需要它。如果删除处理非标准评估的代码,则可以减少需要修复的问题数量。
仍然存在一些重要问题--NAMESPACE的问题。只要您在自己的包中使用其他包中的函数,就可以处理NAMESPACE。 NAMESPACE不是一个简单的话题,但是如果你正在编写软件包,那么学习它会有所收获。我建议你阅读:从r-pkgs.had.co.nz/namespace.html,找到&#34; Imports&#34;并阅读其介绍以及副标题&#34; R功能&#34;。这将有助于您了解我在下面发布的步骤,代码和注释。
按照以下步骤解决问题:
- 将dplyr,magrittr和tidyr添加到DESCRIPTION中
- 将功能称为PACKAGE::FUNCTION()
- 删除所有!!
和:=
,因为在这种情况下您不需要它们
- 从magrittr导入和导出管道
- 从rlang导入.data
- 将全局变量传递给utils :: globalVariables()
- 重建,重新加载,重新检查。
# I make your function shorter to focus on the important details.
myfunction <- function(){
df <- data.frame(
X = c("A", "B", "C", "D", "E"),
Y = c(1, 2, 3, 1, 1)
)
df %>%
dplyr::group_by(.data$Y) %>%
dplyr::summarise(N = n())
}
# Fix check() notes
#' @importFrom magrittr %>%
#' @export
magrittr::`%>%`
#' @importFrom rlang .data
NULL
utils::globalVariables(c(".data", "n"))
答案 1 :(得分:1)
您可以使用rlang::sym()
(或base::as.name()
)将字符转换为符号,所以让我添加一个替代答案。
请注意,我并不是要强迫您丢弃这些已弃用的功能。您可以使用易于理解的内容。 (我相信sym()
更有用,但是)
rlang::sym()
此代码
group_by_("Y") %>%
可以写成
group_by(!! rlang::sym("Y"))
或者您甚至可以事先将符号分配给变量。
col_Y <- rlang::sym("Y")
df %>%
group_by(!! col_Y)
此代码完全正常。
summarise(!!"N":=n())
LHS允许使用字符和符号。所以这也很好:
col_N <- rlang::sym("N")
# ...
summarise(!! col_N := n())
select()
和rename()
具有与mutate()
等其他函数不同的语义;它允许除符号之外的字符。这可能是一个有点高级的话题。您可以在a vignette中找到更详细的说明。
More precisely, the code bellow are both permitted:
rename(new = old)
rename(new = "old")
So, this code is fine.
rename(!! "newY" := "Y")
reprex::reprex_info()
#> Created by the reprex package v0.1.1.9000 on 2017-11-12
library(dplyr, warn.conflicts = FALSE)
library(tidyr)
df <- data.frame(X=c("A", "B", "C", "D", "E"),
Y=c(1, 2, 3, 1, 1))
col_Y <- rlang::sym("Y")
col_N <- rlang::sym("N")
col_newY <- rlang::sym("newY")
df %>%
group_by(!! col_Y) %>%
summarise(!! col_N := n()) %>%
mutate(!! col_Y := factor(!! col_Y, levels=1:5)) %>%
complete(!! col_Y, fill = list(N = 0)) %>%
arrange(!! col_Y) %>%
rename(!! col_newY := !! col_Y) %>%
mutate(!! col_Y := as.integer(!! col_newY))
#> # A tibble: 5 x 3
#> newY N Y
#> <fctr> <dbl> <int>
#> 1 1 3 1
#> 2 2 1 2
#> 3 3 1 3
#> 4 4 0 4
#> 5 5 0 5