我经常使用ddply
,但从历史上讲,它是summarize
(有时是mutate
),只有基本功能(例如mean()
,var1 - var2
等)。我在一个数据集中尝试应用自定义,参与程度更高的功能,并开始尝试研究如何用ddply
做到这一点。我有一个成功的解决方案,但是我不明白为什么它会像这样,而对于更多的“正常”功能却如此。
相关的
这是一个示例数据集:
library(plyr)
df <- data.frame(id = rep(letters[1:3], each = 3),
value = 1:9)
通常,我会像这样使用
ddply
:df_ply_1 <- ddply(df, .(id), mutate, mean = mean(value))
我对此的可视化是
ddply
根据df
的组合组合将id
拆分为“小型”数据帧,然后通过对mean()
中存在的列名称调用df
来添加新列。因此,我尝试实现一个功能扩展了这个想法:# actually, my logical extension of the above was to use:
# ddply(..., mean = function(value) { mean(value) })
df_ply_2 <- ddply(df, .(id), mutate,
mean = function(df) { mean(df$value) })
Error: attempt to replicate an object of type 'closure'
关于自定义函数的所有帮助都没有应用
mutate
,但是这似乎前后矛盾,或者至少让我讨厌,因为与我实现的解决方案类似:df_mean <- function(df) {
temp <- data.frame(mean = rep(mean(df$value), nrow(df)))
temp
}
df_ply_3 <- df
df_ply_3$mean <- ddply(df, .(id), df_mean)$mean
内联,看来我必须这样做:
df_ply_4 <- df
df_ply_4$mean <- ddply(df, .(id), function(x) {
temp <- data.frame(mean = rep(mean(x$value), length(x$value)))
temp})$mean
为什么不能将
mutate
与自定义函数一起使用?仅仅是“内置”函数返回ddply
可以处理的某种类,而必须踢出完整的data.frame
然后仅调出我关心的列吗?感谢您帮助我“获得”它!
@Gregor回答后更新
很棒的答案,我想我明白了。确实,我对
mutate
和summarize
的含义感到困惑...认为它们是ddply
的参数,涉及如何处理结果与实际上是函数本身。因此,感谢您的深刻见解。另外,它确实有助于理解没有
mutate/summarize
,我需要返回data.frame
,这就是我必须对返回的cbind
中的列名进行df
的原因。最后,如果我确实使用
mutate
,那么现在可以返回向量结果并获得正确的结果将非常有帮助。因此,我可以做到这一点,在阅读您的回答后,我现在已经明白了:# I also caught that the code above doesn't do the right thing
# and recycles the single value returned by mean() vs. repeating it like
# I expected. Now that I know it's taking a vector, I know I need to return
# a vector the same length as my mini df
custom_mean <- function(x) {
rep(mean(x), length(x))
}
df_ply_5 <- ddply(df, .(id), mutate,
mean = custom_mean(value))
再次感谢您的深入解答!
根据@Gregor的最新评论更新
嗯出于对
rep(mean(x), length(x))
结果的观察,我使用了df_ply_3
(我第一次发表这篇文章时,并没有仔细观察它,我只是发现它并没有给我带来错误!):df_mean <- function(x) {
data.frame(mean = mean(x$value))
}
df_ply_3 <- df
df_ply_3$mean <- ddply(df, .(id), df_mean)$mean
df_ply_3
id value mean
1 a 1 2
2 a 2 5
3 a 3 8
4 b 4 2
5 b 5 5
6 b 6 8
7 c 7 2
8 c 8 5
9 c 9 8
因此,我基于3个
id
变量重复3次这一事实,认为我的代码实际上是一次意外。因此,实际返回等于summarize
(每个id
值一行),并被回收。如果我像这样更新我的数据框,则对该理论的测试似乎是正确的:df <- data.frame(id = c(rep(letters[1:3], each = 3), "d"),
value = 1:10)
尝试将
df_ply_3
方法与df_mean()
结合使用时出现错误:Error in `$<-.data.frame`(`*tmp*`, "mean", value = c(2, 5, 8, 10)) :
replacement has 4 rows, data has 10
因此,传递给
df_mean
的mini df返回df
,其中mean
是value
向量(返回一个值)取平均值的结果。因此,我的输出只是一个包含三个值的data.frame
,每个id
组一个。我在想mutate
方式“记住”它已传递一个小型数据帧,然后重复单个输出以匹配其长度?无论如何,感谢您对
df_ply_5
的评论;的确,如果我删除rep()
位并仅返回mean(x)
,那么效果很好! 最佳答案
你基本上是对的。 ddply
确实根据石斑鱼将您的数据分解为微型数据帧,并对每个片段都应用了一个函数。
使用ddply
,所有工作都通过数据帧完成,因此.fun
参数必须以一个(小型)数据帧作为输入,并返回一个数据帧作为输出。mutate
和summarize
是适合此要求的函数(它们获取和返回数据帧)。您可以查看他们的个人帮助页面,也可以在ddply
之外的数据框中运行它们,例如
mutate(mtcars, mean.mpg = mean(mpg))
summarize(mtcars, mean.mpg = mean(mpg))
如果您不使用
mutate
或summarize
,也就是说,您仅使用自定义函数,那么您的函数还需要采用一个(小型)数据帧作为参数,并返回一个数据帧。如果使用
mutate
或summarize
做,则传递给ddply
的任何其他函数都不会被ddply
使用,它们只会传递给mutate
或summarize
使用。 mutate
和summarize
使用的函数作用于数据的列,而不作用于整个data.frame。这就是为什么ddply(mtcars, "cyl", mutate, mean.mpg = mean(mpg))
请注意,我们没有将
mutate
传递给函数。我们不说ddply(mtcars, "cyl", mutate, mean)
。我们必须告诉它要表达什么意思。在?mutate
中,...
的描述是“给新列定义的命名参数”,与函数无关。 (mean()
与任何“自定义函数”真的不同吗?)因此,它不适用于匿名函数-或根本不起作用。传递一个表情!您可以预先定义一个自定义函数。
custom_function <- function(x) {mean(x + runif(length(x))}
ddply(mtcars, "cyl", mutate, jittered.mean.mpg = custom_function(mpg))
ddply(mtcars, "cyl", summarize, jittered.mean.mpg = custom_function(mpg))
这很好地扩展了,您可以具有接受多个参数的函数,并且可以为它们提供不同的列作为参数,但是,如果您使用
mutate
或summarize
,则必须给其他函数提供参数;您不只是传递函数。您似乎想要传递
ddply
一个已经“知道”平均值的函数。为此,我认为您不需要使用mutate
或summarize
,但是您可以破解自己的版本。对于类似summarize
的行为,返回带有单个值的data.frame,对于类似于mutate
的行为,返回原始data.frame,并在其上加上额外的值cbind
mean.mpg.mutate = function(df) {
cbind.data.frame(df, mean.mpg = mean(df$mpg))
}
mean.mpg.summarize = function(df) {
data.frame(mean.mpg = mean(df$mpg))
}
ddply(mtcars, "cyl", mean.mpg.mutate)
ddply(mtcars, "cyl", mean.mpg.summarize)
tl; dr
恰恰相反!
mutate
和summarize
将数据帧作为输入,并踢出数据帧作为返回。但是mutt和总结就是您要传递给ddply的函数,而不是指其他任何东西。Mutate和summary是便利功能,您将在
ddply
的99%的时间中使用它们。如果您不使用mutate/summaryize,则您的函数需要获取并返回一个数据帧。
如果您确实使用了mutate/summitize,那么您就不会传递它们的功能,而是传递可以用您的(小型)数据帧求值的表达式。如果是变异的,则返回值应该是要附加到数据的向量(必要时回收)。如果是汇总,则返回值应为单个值。您没有传递像
mean
这样的函数;您传递一个表达式,例如mean(mpg)
。那
dplyr
呢?这是在
dplyr
还是一件大事之前写的。 dplyr
消除了此过程中的许多困惑,因为它实际上将ddply
的嵌套替换为mutate
或summarize
作为带有顺序函数group_by
后跟mutate
或summarize
的参数的嵌套。我的答案的dplyr
版本是library(dplyr)
group_by(mtcars, cyl) %>%
mutate(mean.mpg = mean(mpg))
将新的列创建直接传递给
mutate
(或summarize
)后,对于哪个函数执行什么操作就不会感到困惑。