【问题标题】:Matrix Averaging of duplicate Rows重复行的矩阵平均
【发布时间】:2014-11-24 19:06:47
【问题描述】:

我有一个包含 2 列的 cvs 文件(例如,请参见下面的矩阵 1)。我想创建一个程序来为第一列中的所有重复数字平均矩阵的第二列。因此,例如在下面的矩阵中,第一列中有两行“2”。这些行将被平均为一列 ((356+456)/2 = 406) 等。因此最终的矩阵将像底部的矩阵 2。关于如何做到这一点的任何想法?

矩阵 1

mat1 <- structure(c(1, 2, 2, 3, 4, 4, 4, 5, 234, 356, 456, 745, 568, 
            998, 876, 895), .Dim = c(8L, 2L))
mat1
     [,1] [,2]
[1,]    1  234
[2,]    2  356
[3,]    2  456
[4,]    3  745
[5,]    4  568
[6,]    4  998
[7,]    4  876
[8,]    5  895

矩阵 2

mat2 <- structure(c(1, 2, 3, 4, 5, 234, 406, 745, 814, 895), .Dim = c(5L, 2L))
mat2
     [,1] [,2]
[1,]    1  234
[2,]    2  406
[3,]    3  745
[4,]    4  814
[5,]    5  895

【问题讨论】:

  • 第一列总是按数字顺序排列吗?

标签: r


【解决方案1】:

仅使用基础 R:

> x <- tapply(mat1[,2], mat1[,1], mean)
> matrix(c(as.integer(names(x)), x), ncol = 2)

【讨论】:

    【解决方案2】:

    怎么样

    as.matrix(aggregate(mat1[,2],by = list(mat1[,1]),FUN = mean))
    

    【讨论】:

    • 不会返回矩阵
    • @David as.matrix(aggregate(mat1,by = list(mat1[,1]),FUN = mean))
    • 如果你不想要聚合as.matrix(aggregate(mat1,by = list(mat1[,1]),FUN = mean))[,-1]创建的列
    • 为什么不只是as.matrix(aggregate(mat1[, 2] ~ mat1[, 1], FUN = mean))?你需要额外的变量做什么?
    • 你的建议是几乎相同的不同写法。我没有提供公式,而是使用了 by 参数,您也可以使用 as.matrix(aggregate(mat1[,2],by = list(mat1[,1]),FUN = mean))
    【解决方案3】:

    最基本的方法是使用tapply

    tapply(mat1[,2], mat1[,1], mean)
    

    【讨论】:

    • 那也不会返回矩阵
    • @DavidArenburg 真的。我不确定 OP 是否最好使用矩阵 - 我的印象是这只是他知道可以存储他需要的第一个数据类型。以我的经验,在许多情况下,矩阵并不是最好的数据类型。因此,我故意给出了一个替代方案。我正要对此发表评论,但后来我的电话响了,我分心了......
    • @DavidArenburg,您正在编写这些 cmets,就好像 as.matrix 是一个晦涩难懂且难以应用的函数。
    • @AnandaMatho 没有。我编写这些 cmets 是为了指导人们尝试匹配 OP 所需的输出,而不仅仅是转储代码。 as.matrix你很容易申请,但是R初学者可能不熟悉这个功能,你考虑过吗?
    • @DavidArenburg,我们为什么要需要这样做?问题只是关于聚合。通过将自己限制在 OP 期望的范围内,我们只是为这个人提供免费劳动力,并提供可能只对这个人有用的解决方案。如果提供的答案被证明具有更广泛的适用性(同时解决了 90% 以上的 OP 问题),那么这在 SO 中似乎不是更有用的答案吗?您不会直接从 CSV 转到 R 中没有 dimnames 的矩阵,因此甚至怀疑 OPs reproducible 数据是否是 representative 数据。
    【解决方案4】:

    如果第一列总是按数字顺序,你可以试试

    cbind(unique(mat1[,1]), rowsum(mat1[,2], mat1[,1]) %/% matrix(table(mat1[,1])))
    #      [,1] [,2]
    # [1,]    1  234
    # [2,]    2  406
    # [3,]    3  745
    # [4,]    4  814
    # [5,]    5  895
    

    已知rowsumaggregatetapply 更有效。但是,存在明显的局限性。如果有一个 rowmean 函数用于分组矩阵计算,那就太好了。

    另一种基于 R 的可能性是

    s <- unname(split(mat1[,2], mat1[,1]))
    cbind(unique(mat1[,1]), vapply(s, mean, 1))
    #      [,1] [,2]
    # [1,]    1  234
    # [2,]    2  406
    # [3,]    3  745
    # [4,]    4  814
    # [5,]    5  895
    

    这三个更安全的解决方案是转换为数据框。这里我使用dplyr 来提高效率。

    library(dplyr)
    df <- group_by(as.data.frame(mat1), V1) %>% summarise(mean(V2))
    as.matrix(unname(df))
    #      [,1] [,2]
    # [1,]    1  234
    # [2,]    2  406
    # [3,]    3  745
    # [4,]    4  814
    # [5,]    5  895
    

    【讨论】:

    • 谢谢,转换成数据框也很好用
    【解决方案5】:

    @LeoRJorge 的回答是所需输出的 ​​98%,只需要不命名(如果确实需要的话):

    unname(as.matrix(aggregate(mat1[,2], list(mat1[,1]), mean)))
    
         [,1] [,2]
    [1,]    1  234
    [2,]    2  406
    [3,]    3  745
    [4,]    4  814
    [5,]    5  895
    

    【讨论】:

    • 因此,与其发布 2% 的答案,不如建议对答案进行编辑,让您获得 98% 的成功......
    • 不幸的是,我还没有足够的声誉来发布 cmets(除了我自己的答案),否则我会这样做。随意找到我的一些你认为有帮助的答案,如果你愿意,可以投票给他们。谢谢。
    • 我想知道在什么情况下不希望有名字。但如果是这种情况,取消命名应该没有问题。
    猜你喜欢
    • 2018-04-28
    • 1970-01-01
    • 1970-01-01
    • 2013-05-06
    • 2020-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-21
    相关资源
    最近更新 更多