使 plyr::ddply 代码与 dplyr 等效自定义函数兼容
Make plyr::ddply code compatible with dplyr-equivalent custom function
我正在尝试调整一个长函数 (rcompanion::groupwiseMean
) 以在其代码中使用 dplyr
而不是 plyr::ddply
以避免依赖现已弃用的 plyr
包.
我想定义一个自定义的 ddply2
函数,采用与原始 plyr
函数相同的参数,但在后台使用 dplyr
。好处是只在现有 long function/script 的顶部重新定义函数一次,而不更改任何其他内容。到目前为止,我的尝试都失败了。下面演示。
我一直在使用这个资源:plyr::ddply equivalent in dplyr
原始plyr:ddplyr
调用
data <- mtcars
var <- "mpg"
group <- c("cyl", "am")
# Original plyr:ddply-fed function:
fun.y <- function(x, idx) { length(x[, idx]) }
# Original plyr:ddply call:
plyr::ddply(.data = data, .variables = group, var, .fun = fun.y)
#> cyl am V1
#> 1 4 0 3
#> 2 4 1 8
#> 3 6 0 4
#> 4 6 1 3
#> 5 8 0 12
#> 6 8 1 2
这是我无法重写的函数
fun.y <- function(x, idx) { length(x[, idx]) }
但这只是一个例子。以下是我需要使用的其他一些功能 ddply2
:
fun.z <- function(x, idx) { as.numeric(mean(x[, idx], trim = trim, na.rm = na.rm)) }
fun.w <- function(x, idx) {
mean(boot(x[, idx], function(y, j) mean(y[j], trim = trim,
na.rm = na.rm), R = R, ...)$t[, 1])
}
现在让我们继续进行所需的 ddply2
调用,我可以随意修改它。但是它必须采用与 plyr::ddply
.
相同的参数
尝试将 plyr:ddply
重写为 dpply2
library(dplyr)
ddply2 <- function(.data, .variables, var, .fun) {
.data %>%
group_by(across({{.variables}})) %>%
do(.fun(., {{var}}))
}
ddply2(.data = data, .variables = group, var, .fun = fun.y)
# Error in `do()`:
# ! Results 1, 2, 3, 4, 5, 6 must be data frames, not integer.
编辑
同样,我无法重写 fun.y
、fun.z
或 fun.w
,只能重写 ddply2
。因此基于 summarize()
或 count()
的解决方案将不起作用,因为它们不能推广到其他功能。 plyr:ddplyr
不需要 summarize()
或 count()
,就是这个意思。
经过一些讨论,我现在明白了,我们需要的是使用 dplyr 而不是 plyr 重写这个函数,这样对于下面输入部分中列出的输入,它会给出相同的结果。
dd <- function(data, group, var, fun)
plyr::ddply(.data = data, .variables = group, var, .fun = fun)
为此,新函数可以将 group_by 与汇总或 group_modify 结合使用。下面的 dd1 使用第一个,dd2 使用第二个。使用您喜欢的任何一个。
请注意,fun.z 的编写方式假定一个数据帧而不是一个 tibble(因为数据帧 return 如果只有一列则为向量,而 tibble returns另一个 tibble) 所以我们使用 as.data.frame 来确保这一点。同样 plyr returns 是一个数据帧,在 dd1 和 dd2 的末尾,我们将生成的 tibble 转换为数据帧以确保结果相同。
dd1 <- function(data, group, var, fun)
data %>%
group_by(across(all_of(group))) %>%
summarize(V1 = fun(as.data.frame(cur_data()), var), .groups = "drop") %>%
as.data.frame
dd2 <- function(data, group, var, fun)
data %>%
group_by(across(all_of(group))) %>%
group_modify(~ { data.frame(V1 = fun(as.data.frame(.), var)) }) %>%
ungroup %>%
as.data.frame
现在测试一下
# inputs - start #
data <- mtcars
trim <- 0
na.rm <- FALSE
var <- "mpg"
group <- c("cyl", "am")
fun.z <- function(x, idx) {
as.numeric(mean(x[, idx], trim = trim, na.rm = na.rm))
}
# inputs - end #
library(dplyr)
dd.out <- dd(data, group, var, fun.z) # plyr
dd1.out <- dd1(data, group, var, fun.z)
dd2.out <- dd2(data, group, var, fun.z)
identical(dd1.out, dd.out)
## [1] TRUE
identical(dd2.out, dd.out)
## [1] TRUE
我正在尝试调整一个长函数 (rcompanion::groupwiseMean
) 以在其代码中使用 dplyr
而不是 plyr::ddply
以避免依赖现已弃用的 plyr
包.
我想定义一个自定义的 ddply2
函数,采用与原始 plyr
函数相同的参数,但在后台使用 dplyr
。好处是只在现有 long function/script 的顶部重新定义函数一次,而不更改任何其他内容。到目前为止,我的尝试都失败了。下面演示。
我一直在使用这个资源:plyr::ddply equivalent in dplyr
原始plyr:ddplyr
调用
data <- mtcars
var <- "mpg"
group <- c("cyl", "am")
# Original plyr:ddply-fed function:
fun.y <- function(x, idx) { length(x[, idx]) }
# Original plyr:ddply call:
plyr::ddply(.data = data, .variables = group, var, .fun = fun.y)
#> cyl am V1
#> 1 4 0 3
#> 2 4 1 8
#> 3 6 0 4
#> 4 6 1 3
#> 5 8 0 12
#> 6 8 1 2
这是我无法重写的函数
fun.y <- function(x, idx) { length(x[, idx]) }
但这只是一个例子。以下是我需要使用的其他一些功能 ddply2
:
fun.z <- function(x, idx) { as.numeric(mean(x[, idx], trim = trim, na.rm = na.rm)) }
fun.w <- function(x, idx) {
mean(boot(x[, idx], function(y, j) mean(y[j], trim = trim,
na.rm = na.rm), R = R, ...)$t[, 1])
}
现在让我们继续进行所需的 ddply2
调用,我可以随意修改它。但是它必须采用与 plyr::ddply
.
尝试将 plyr:ddply
重写为 dpply2
library(dplyr)
ddply2 <- function(.data, .variables, var, .fun) {
.data %>%
group_by(across({{.variables}})) %>%
do(.fun(., {{var}}))
}
ddply2(.data = data, .variables = group, var, .fun = fun.y)
# Error in `do()`:
# ! Results 1, 2, 3, 4, 5, 6 must be data frames, not integer.
编辑
同样,我无法重写 fun.y
、fun.z
或 fun.w
,只能重写 ddply2
。因此基于 summarize()
或 count()
的解决方案将不起作用,因为它们不能推广到其他功能。 plyr:ddplyr
不需要 summarize()
或 count()
,就是这个意思。
经过一些讨论,我现在明白了,我们需要的是使用 dplyr 而不是 plyr 重写这个函数,这样对于下面输入部分中列出的输入,它会给出相同的结果。
dd <- function(data, group, var, fun)
plyr::ddply(.data = data, .variables = group, var, .fun = fun)
为此,新函数可以将 group_by 与汇总或 group_modify 结合使用。下面的 dd1 使用第一个,dd2 使用第二个。使用您喜欢的任何一个。
请注意,fun.z 的编写方式假定一个数据帧而不是一个 tibble(因为数据帧 return 如果只有一列则为向量,而 tibble returns另一个 tibble) 所以我们使用 as.data.frame 来确保这一点。同样 plyr returns 是一个数据帧,在 dd1 和 dd2 的末尾,我们将生成的 tibble 转换为数据帧以确保结果相同。
dd1 <- function(data, group, var, fun)
data %>%
group_by(across(all_of(group))) %>%
summarize(V1 = fun(as.data.frame(cur_data()), var), .groups = "drop") %>%
as.data.frame
dd2 <- function(data, group, var, fun)
data %>%
group_by(across(all_of(group))) %>%
group_modify(~ { data.frame(V1 = fun(as.data.frame(.), var)) }) %>%
ungroup %>%
as.data.frame
现在测试一下
# inputs - start #
data <- mtcars
trim <- 0
na.rm <- FALSE
var <- "mpg"
group <- c("cyl", "am")
fun.z <- function(x, idx) {
as.numeric(mean(x[, idx], trim = trim, na.rm = na.rm))
}
# inputs - end #
library(dplyr)
dd.out <- dd(data, group, var, fun.z) # plyr
dd1.out <- dd1(data, group, var, fun.z)
dd2.out <- dd2(data, group, var, fun.z)
identical(dd1.out, dd.out)
## [1] TRUE
identical(dd2.out, dd.out)
## [1] TRUE