我经常使用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
拆分为&#34; mini&#34;基于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
与自定义功能一起使用?它只是&#34;内置&#34;函数返回某种类ddply
可以处理的类而不必踢出一个完整的data.frame
,然后只调出我关心的列?
感谢您帮助我&#34;得到它&#34;!
@ 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
(我承认在我第一次发布这个帖子时没有仔细查看它,我只是看到它没有& #39;给我一个错误!):
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
的迷你df会返回df
,其中mean
是value
向量(返回一个值)时取均值的结果。因此,我的输出只是data.frame
三个值,每个id
组一个。我认为mutate
方式会记住&#34;记得&#34;它传递了一个迷你数据帧,然后重复单个输出以匹配它的长度?
无论如何,感谢您对df_ply_5
发表评论;实际上,如果我删除rep()
位并返回mean(x)
,它就会很棒!
答案 0 :(得分:11)
你大部分都是对的。 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,并在
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)
为什么我不能在自定义函数中使用mutate?只是“内置”函数返回某种类,ddply可以处理这些类而不必踢出一个完整的data.frame然后只调出我关心的列吗?
恰恰相反! mutate
和summarize
将数据框作为输入,并将数据帧作为返回值踢出。但是变异和总结是你传递给ddply的函数,而不是意思或其他任何东西。
变异和总结是您在99%的时间内使用ddply
时使用的便利功能。
如果你不使用mutate / summarize,那么你的函数需要获取并返回一个数据框。
如果你确实使用mutate / summarize,那么你不传递它们的函数,你传递它们可以用你的(迷你)数据框评估的表达式。如果它是变异的,则返回应该是要附加到数据的向量(根据需要回收)。如果总结,则返回值应为单个值。您没有传递函数,例如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
),不会混淆哪个函数做什么。