在R中的函数中创建和使用新变量:tidyverse中的NSE编程错误

Dom*_*ski 6 r dplyr nse tidyverse mutate

在阅读并重新阅读了许多"使用dplyr编程"指南之后,我仍然无法找到解决我的特定情况的方法.

据我所知,使用group_by_,mutate_和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))
Run Code Online (Sandbox Code Playgroud)

一些常见的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
Run Code Online (Sandbox Code Playgroud)

我希望这段代码能够函数内部安静地工作.以下是我处理非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))
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,我仍然收到以下消息:

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
Run Code Online (Sandbox Code Playgroud)

有办法解决吗?非常感谢!

编辑:我正在使用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))
}
Run Code Online (Sandbox Code Playgroud)

非常感谢 :)

Mau*_*ore 4

答案不在“使用 dplyr 编程”指南中,因为您的问题更为普遍。尽管您的代码处理非标准评估,但您的案例不需要它。如果删除处理非标准评估的代码,您将减少需要修复的问题数量。

尽管如此,一些重要的问题仍然存在——命名空间的问题。每当您在自己的包的函数内使用来自其他包的函数时,您都会处理命名空间。命名空间不是一个简单的主题,但如果您正在编写包,那么学习一点就会有所收获。我建议您阅读:从 r-pkgs.had.co.nz/namespace.html 中,找到“导入”部分并阅读其简介以及副标题“R 函数”。这将帮助您理解我在下面发布的步骤、代码和注释。

请按照以下步骤解决您的问题:
- 将 dplyr、magrittr 和 tidyr 添加到描述中。
- 将函数称为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"))
Run Code Online (Sandbox Code Playgroud)