【问题标题】:custom function after grouping data.fame分组 data.fame 后的自定义函数
【发布时间】:2014-07-30 09:41:57
【问题描述】:

给定以下data.frame

d <- rep(c("a", "b"), each=5)
l <- rep(1:5, 2) 
v <- 1:10

df       <- data.frame(d=d, l=l, v=v*v)
df
   d l   v
1  a 1   1
2  a 2   4
3  a 3   9
4  a 4  16
5  a 5  25
6  b 1  36
7  b 2  49
8  b 3  64
9  b 4  81
10 b 5 100

现在我想在按 l 分组后添加另一列。额外的列应该包含 v_b - v_a 的值

   d l   v    e
1  a 1   1    35 (36-1)
2  a 2   4    45 (49-4)
3  a 3   9    55 (64-9)
4  a 4  16    65 (81-16)
5  a 5  25    75 (100-25)
6  b 1  36    35 (36-1)
7  b 2  49    45 (49-4)
8  b 3  64    55 (64-9)
9  b 4  81    65 (81-16)
10 b 5 100    75 (100-25)

括号内是如何计算值的方式。

我正在寻找一种使用 dplyr 的方法。所以我从这样的事情开始

df %.% 
 group_by(l) %.%
 mutate(e=myCustomFunction)

但是我应该如何定义 myCustomFunction?我认为 data.frame 的分组会产生另一个(子)data.frame,它是该函数的参数。但这不是……

【问题讨论】:

    标签: r dataframe dplyr


    【解决方案1】:

    我猜这是dplyr 相当于@jlhoward 的data.table 解决方案:

    df %>%
      group_by(l) %>%
      mutate(e = v[d == "b"] - v[d == "a"])
    

    OP 评论后编辑:

    如果你想使用自定义函数,这里有一个可能的方法:

    myfunc <- function(x) {
      with(x, v[d == "b"] - v[d == "a"])
    }
    
    test %>%
      group_by(l) %>%
      do(data.frame(. , e = myfunc(.))) %>%
      arrange(d, l)                   # <- just to get it back in the original order
    

    @hadley 评论后编辑:

    正如 hadley 在下面评论的那样,在这种情况下,最好将函数定义为

    f <- function(v, d) v[d == "b"] - v[d == "a"]
    

    然后在mutate 中使用自定义函数f

    df %>%
      group_by(l) %>%
      mutate(e = f(v, d))  
    

    感谢@hadley 的评论。

    【讨论】:

    • @beginnR, @agstudy 当我想将v[d == "b"] - v[d == "a"] 放入一个函数并仅将e=myfunc(v) 放入mutate 时,这将不起作用。该函数仅获取两个整数(str(v) in myfunc 打印 int [1:2] 1 36)。所以我失去了其他索引。
    • @JerryWho 看到我更新的答案。要在 dplyr 中应用自定义函数,您必须使用 do 运算符。当你这样做时,你使用. 将数据传递给你的自定义函数。
    • 最好先做函数f &lt;- function(v, d) v[d == "b"] - v[d == "a"]再做mutate(e = f(v, d))
    • 感谢您的评论,@hadley。我根据您的建议编辑了我的答案,以向以后可能遇到此问题的任何人说明这一点。 (我只是开始使用 dplyr 链中的自定义函数,我最初的想法是在这种情况下使用 do
    【解决方案2】:

    使用dplyr

    df %.%   
      group_by(l)  %.%
      mutate(e=diff(v))
    
    # d l   v  e
    # 1  a 1   1 35
    # 2  a 2   4 45
    # 3  a 3   9 55
    # 4  a 4  16 65
    # 5  a 5  25 75
    # 6  b 1  36 35
    # 7  b 2  49 45
    # 8  b 3  64 55
    # 9  b 4  81 65
    # 10 b 5 100 75
    

    【讨论】:

    • 我真正的问题有点复杂。所以我不能使用 diff 因为分组后不止两行。有没有办法将自定义函数与 mutate 一起使用?调用这个函数的参数是什么?
    • @JerryWho 你只是将 diff 包装在一个函数中:my_diff &lt;- function(x)diff(x) 然后你用 my_diff 替换 diff
    【解决方案3】:

    这是一种使用数据表的方法。

    library(data.table)
    DT <- as.data.table(df)
    DT[,e := diff(v), by=l]
    

    这些使用diff(...) 的方法假定您的data frame 已按照您的示例进行排序。如果不是,这是一种更可靠的方法来做同样的事情。

    DT[, e := .SD[d == "b", v] - .SD[d == "a", v], by=l]
    

    (或)更直接

    DT[, e := v[d == "b"] - v[d == "a"], by=l]
    

    但是如果您想访问整个数据子集并将其传递给您的自定义函数,那么您可以使用.SD。还要确保您从?data.table 阅读了有关?.SDcols 的信息。

    【讨论】:

    • 太好了。符号 .SD 是我正在寻找的。 dplyr 中有类似的东西吗?我正在使用 plyr,几周前由于速度原因切换到 data.table。然后我找到了 dplyr,并且比 data.table 更喜欢它。所以我希望我可以只使用 dplyr...
    【解决方案4】:

    如果您想考虑非 dplyr 选项

    df$e <- with(df, ave(v, l, FUN=function(x) diff(x)))
    

    会成功的。 ave 函数可用于计算观测值组的值。

    【讨论】:

      猜你喜欢
      • 2011-12-27
      • 2019-09-04
      • 1970-01-01
      • 2019-03-14
      • 1970-01-01
      • 2016-06-29
      • 2019-07-15
      • 2012-03-20
      • 1970-01-01
      相关资源
      最近更新 更多