r - Tidyeval 在自己的函数中在自己的函数中使用管道
问题描述
所以我正在尝试制作一个包(我没有在下面包含我的 roxygen2 标头):
我有这个功能:
date_from_text <- function(df, x){
x <- rlang::enquo(x)
name <- rlang::quo_name(x)
df %>%
dplyr::mutate(!!name := lubridate::ymd_hms(!!x))
}
当 datetime 列具有正确的类时,我使用它来提取所有组件。
date_columns <- function(df, x){
x <- rlang::enquo(x)
df %>%
dplyr::mutate(year=lubridate::year(!!x),
ydag=lubridate::yday(!!x),
weekday=lubridate::wday(!!x, label=FALSE),
hour = lubridate::hour(!!x),
hour_min= hms::as.hms(lubridate::force_tz(!!x)),
week_num = lubridate::week(!!x),
month = lubridate::month(!!x),
date = lubridate::date(!!x))
}
我不希望将date_from_text
函数包含在函数中,NAMESPACE
并且我想以某种方式将它包含在date_columns
函数中。例如检查时间戳是否具有正确的类,如果没有,则更改类..然后创建所有日期时间组件。
我不知道如何在另一个函数中调用第一个函数。
测试数据:
df <- structure(list(time = c("2018-01-30 20:08:18", "2018-02-01 21:01:25",
"2018-01-31 23:25:12", "2018-01-28 23:45:34", "2018-01-31 12:00:55",
"2018-02-04 09:15:31", "2018-01-27 21:08:02", "2018-02-08 01:50:31",
"2018-02-01 03:15:43", "2018-02-04 01:04:52"), type = c("A",
"D", "B", "B", "B", "D", "C", "C", "C", "A")), .Names = c("time",
"type"), row.names = c(NA, -10L), class = c("tbl_df", "tbl",
"data.frame"))
更新:所以我现在已经包含date_from_text
在date_columns
date_columns <- function(df, x){
x <- rlang::enquo(x)
out <- df %>%
date_from_text(!!x) %>%
dplyr::mutate(year=lubridate::year(!!x),
ydag=lubridate::yday(!!x),
weekday=lubridate::wday(!!x, label=FALSE),
hour = lubridate::hour(!!x),
hour_min= hms::as.hms(lubridate::force_tz(!!x)),
week_num = lubridate::week(!!x),
month = lubridate::month(!!x),
date = lubridate::date(!!x))
out
}
所以我不明白为什么我必须在!!x
里面再次使用date_columns
?它已经包含在date_from_text
. 我正在调用该函数而不是创建它...
解决方案
正如评论和聊天中所解决的那样,问题既不是关于包开发和命名空间,也不是关于管道。问题是如何在可能嵌套的包装函数中使用tidyeval 。
答案是用户传递给函数的表达式需要被引用和不被引用,就像date_from_text()
下面的 via enquo(x)
and一样!!x
。
date_from_text <- function(df, x) {
x <- rlang::enquo(x) # quote via enquo()
name <- rlang::quo_name(x)
dplyr::mutate(df, !!name := lubridate::ymd_hms(!!x)) # unquote via !!
}
然后,表达式可以以“交互”模式传递给此类函数,就像 dplyr 函数一样:
date_from_text(df, time)
select(df, time)
请记住,函数内部的函数不接受表达式,而是带引号和不带引号的表达式,就像在上面的mutate()
调用中enquo(x)
一样!!x
。
这意味着,在date_from_text()
下面,呼叫date_from_text()
和mutate()
需要接收!!x
。
date_columns <- function(df, x) {
x <- rlang::enquo(x)
out <- date_from_text(df, !!x)
out <- dplyr::mutate(out, year = lubridate::year(!!x))
return(out)
}
除此之外,在包开发中,您可以使用所有功能,无论它们是否被导出(就像我对date_from_text()
inside所做的那样date_columns()
)。导出的函数需要文档化,通过library(pkg)
or安装后才能使用pkg::fun()
,而未导出的函数只能通过 安装后使用pkg:::fun()
。
我修改了@David 的函数以专注于相关部分。
推荐阅读
- php - WooCommerce 根据购买的产品 ID 和数量删除运输方式
- python - 标准化特征以计算方差膨胀因子
- docker - 用于网站的单个 Nginx Docker 与多个 Nginx Docker
- azure-managed-app - 如何使用新的包版本更新现有的 Azure 托管应用程序?
- javascript - 如何使用 vanilla JavaScript 在列表中获取 span 的值?
- java - 将文件保存在谷歌驱动器上
- android - 从 expo 客户端构建应用程序 apk 时获取“keystore.keyAlias”不允许为空错误
- python - 确定一个列表中的元素是否小于另一个列表中的元素
- javascript - Is there a way to copy validation from one input to another with JavaScript?
- .htaccess - 如何对主域强制执行 https 连接,同时对子域强制执行 http?