【问题标题】:R ave by columns按列狂欢
【发布时间】:2023-03-16 05:55:01
【问题描述】:

我想在数据框的多列(十位)上使用ave函数:

ave(df[,the_cols], df[,c('site', 'month')], FUN = mean)

问题是ave 在所有the_cols 列上一起运行mean 函数。有什么方法可以分别为每个 the_cols 列运行它吗?

我尝试查看其他功能。 tapplyaggregate 不同,它们每组只返回一行。我需要ave 行为,即返回与原始df 中给出的行数相同的行数。还有一个by 函数,但是使用它会非常笨拙,因为它返回一个复杂的列表结构,必须以某种方式进行转换。

当然存在许多笨拙和丑陋(通过 &do.call、多个 *apply 函数调用等)的解决方案,但有一些真正简单而优雅的解决方案吗?

【问题讨论】:

    标签: r dataframe


    【解决方案1】:

    也许我遗漏了一些东西,但这里的 apply() 方法会很好用,不会丑陋或需要任何丑陋的黑客攻击。一些虚拟数据:

    df <- data.frame(A = rnorm(20), B = rnorm(20), site = gl(5,4), month = gl(10, 2))
    

    有什么问题:

    sapply(df[, c("A","B")], ave, df$site, df$month)
    

    ?如果您真的需要,请通过 data.frame() 将其强制转换为数据框。

    R> sapply(df[, c("A","B")], ave, df$site, df$month)
                A        B
     [1,]  0.0775  0.04845
     [2,]  0.0775  0.04845
     [3,] -1.5563  0.43443
     [4,] -1.5563  0.43443
     [5,]  0.7193  0.01151
     [6,]  0.7193  0.01151
     [7,] -0.9243 -0.28483
     [8,] -0.9243 -0.28483
     [9,]  0.3316  0.14473
    [10,]  0.3316  0.14473
    [11,] -0.2539  0.20384
    [12,] -0.2539  0.20384
    [13,]  0.5558 -0.37239
    [14,]  0.5558 -0.37239
    [15,]  0.1976 -0.22693
    [16,]  0.1976 -0.22693
    [17,]  0.2031  1.11041
    [18,]  0.2031  1.11041
    [19,]  0.3229 -0.53818
    [20,]  0.3229 -0.53818
    

    再把它放在一起,怎么样

    AVE <- function(df, cols, ...) {
      dots <- list(...)
      out <- sapply(df[, cols], ave, ...)
      out <- data.frame(as.data.frame(dots), out)
      names(out) <- c(paste0("Fac", seq_along(dots)), cols)
      out
    }
    
    R> AVE(df, c("A","B"), df$site, df$month)
       Fac1 Fac2       A        B
    1     1    1  0.0775  0.04845
    2     1    1  0.0775  0.04845
    3     1    2 -1.5563  0.43443
    4     1    2 -1.5563  0.43443
    5     2    3  0.7193  0.01151
    6     2    3  0.7193  0.01151
    7     2    4 -0.9243 -0.28483
    8     2    4 -0.9243 -0.28483
    9     3    5  0.3316  0.14473
    10    3    5  0.3316  0.14473
    11    3    6 -0.2539  0.20384
    12    3    6 -0.2539  0.20384
    13    4    7  0.5558 -0.37239
    14    4    7  0.5558 -0.37239
    15    4    8  0.1976 -0.22693
    16    4    8  0.1976 -0.22693
    17    5    9  0.2031  1.11041
    18    5    9  0.2031  1.11041
    19    5   10  0.3229 -0.53818
    20    5   10  0.3229 -0.53818
    

    目前我无法了解与... 合作的细节,但您应该能够为我在这里使用的Fac1 等获得更好的名称。

    我会为你抛出一个替代表示:aggregate(),但使用ave() 函数而不是mean()

    R> aggregate(cbind(A, B) ~ site + month, data = df, ave)
       site month     A.1     A.2      B.1      B.2
    1     1     1  0.0775  0.0775  0.04845  0.04845
    2     1     2 -1.5563 -1.5563  0.43443  0.43443
    3     2     3  0.7193  0.7193  0.01151  0.01151
    4     2     4 -0.9243 -0.9243 -0.28483 -0.28483
    5     3     5  0.3316  0.3316  0.14473  0.14473
    6     3     6 -0.2539 -0.2539  0.20384  0.20384
    7     4     7  0.5558  0.5558 -0.37239 -0.37239
    8     4     8  0.1976  0.1976 -0.22693 -0.22693
    9     5     9  0.2031  0.2031  1.11041  1.11041
    10    5    10  0.3229  0.3229 -0.53818 -0.53818
    

    请注意声明的输出,但如果需要,它很容易重新调整。

    【讨论】:

    • 哇,sapply one-liner 很简单,效果很好,谢谢!!我不会有这个想法在sapply 中运行ave,令人惊叹的codegolf :-) 虽然讨厌你的AVE 函数。既然存在如此美丽的单线,为什么要这样做?
    • 如果你想要 sitemonth 信息并且不得不经常这样做,我会很快写一个这样的包装器来为我做。如果您不需要螺栓固定的因素,只需使用单线。
    • 啊哈,现在我明白了:这只是将网站和月份与结果捆绑在一起......顺便说一句,在你的 AVE 函数中使用 cbind 不是更好吗?我想那names()&lt;- 的东西就不需要了。
    • 感谢您提供替代的aggregate 解决方案。它是否为组内的每条记录创建一列?看起来很讨厌 :) 如果组的记录数不同怎么办?
    • 是的,假设它会弹出一个NA。没查。试试看并反馈...?
    【解决方案2】:

    如果你想有一个 data.frame 回来

    library(plyr)
    ## assuming that the_cols are string
    ## if col index just add the index of site and month
    the_cols <- c("site", "month", the_cols)
    ddply(df, c('site', 'month'), FUN = numcolwise(mean))[,the_cols]
    

    【讨论】:

    • 我总是喜欢只使用基本库,但感谢plyr 解决方案!
    【解决方案3】:

    您可以将bycolMeans 一起使用

    by(df[,the_cols], df[,c('site', 'month')], FUN = colMeans)
    

    你也可以在lapply中使用ave

    res <- lapply(df[,the_cols], function(x) 
                                   ave(x, df[,c('site', 'month')], FUN = mean))
    
    data.frame(res) # create data frame
    

    【讨论】:

    • 正如我在问题中所说,by 不会返回data.frame!需要大量丑陋的代码才能将其恢复到原始结构!查看我的问题
    • @Tomas 函数ave 也不返回数据帧。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-16
    相关资源
    最近更新 更多