使用ddply + mutate和自定义函数?

时间:2014-11-14 17:00:00

标签: r plyr

我经常使用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))

我对此的可视化是ddplydf拆分为&#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回答后更新

很棒的答案,我想我现在明白了。我确实对mutatesummarize的含义感到困惑......认为他们是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,其中meanvalue向量(返回一个值)时取均值的结果。因此,我的输出只是data.frame三个值,每个id组一个。我认为mutate方式会记住&#34;记得&#34;它传递了一个迷你数据帧,然后重复单个输出以匹配它的长度?

无论如何,感谢您对df_ply_5发表评论;实际上,如果我删除rep()位并返回mean(x),它就会很棒!

1 个答案:

答案 0 :(得分:11)

你大部分都是对的。 ddply确实会根据石斑鱼将数据分解为迷你数据框,并对每个部分应用一个函数。

使用ddply,所有工作都是使用数据框完成的,因此.fun参数必须将(迷你)数据框作为输入并返回数据框作为输入输出

mutatesummarize是适合此帐单的函数(它们接收并返回数据框)。您可以查看其各自的帮助页面,或在ddply之外的数据框上运行它们,例如。

mutate(mtcars, mean.mpg = mean(mpg))
summarize(mtcars, mean.mpg = mean(mpg))

如果您使用mutatesummarize,即使用自定义功能,那么您的功能也需要将(迷你)数据帧作为参数,并返回一个数据帧。

如果您执行使用mutatesummarizeddply不会使用您传递给ddply的任何其他功能,重新传递给mutatesummarize使用。 mutatesummarize使用的函数作用于数据列,而不是整个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))

这很好,您可以使用带有多个参数的函数,并且可以为它们提供不同的列作为参数,但如果您使用mutatesummarize,则必须提供其他函数参数;你不只是传递这些功能。

您似乎想要传递ddply一个已经“知道”哪个列的函数。为此,我认为您需要使用mutatesummarize,但您可以破解自己的版本。对于类似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;博士

  

为什么我不能在自定义函数中使用mutate?只是“内置”函数返回某种类,ddply可以处理这些类而不必踢出一个完整的data.frame然后只调出我关心的列吗?

恰恰相反! mutatesummarize将数据框作为输入,并将数据帧作为返回值踢出。但是变异和总结你传递给ddply的函数,而不是意思或其他任何东西。

变异和总结是您在99%的时间内使用ddply时使用的便利功能。

如果你不使用mutate / summarize,那么你的函数需要获取并返回一个数据框。

如果你确实使用mutate / summarize,那么你不传递它们的函数,你传递它们可以用你的(迷你)数据框评估的表达式。如果它是变异的,则返回应该是要附加到数据的向量(根据需要回收)。如果总结,则返回值应为单个值。您没有传递函数,例如mean;你传递了一个表达式,比如mean(mpg)


dplyr怎么样?

这是在dplyr之前编写的,或者至少是一件大事。 dplyr从这个过程中消除了很多混淆,因为它实际上取代了ddplymutatesummarize的嵌套作为参数与顺序函数group_by后跟mutatesummarize。我的答案的dplyr版本将是

library(dplyr)
group_by(mtcars, cyl) %>%
    mutate(mean.mpg = mean(mpg))

将新列创建直接传递给mutate(或summarize),不会混淆哪个函数做什么。