【问题标题】:R colSums By GroupR colSums 按组
【发布时间】:2019-04-28 21:04:13
【问题描述】:

在以下矩阵数据集中:

       1  2   3   4   5  
1950   7 20  21  15  61  
1951   2 10   6  26  57  
1952  12 27  43  37  34  
1953  14 16  40  47  94  
1954   2 17  62 113 101  
1955   3  4  43  99 148  
1956   2 47  31  85  79  
1957  17  5  38 216 228  
1958  11 20  15  76  68  
1959  16 20  43  30 226  
1960   9 28  28  70 201  
1961   1 31 124  74 137  
1962  12 25  37  41 200  

我一直在尝试按十年计算 colSums,即从 1950 年到 1959 年,然后从 1960 年到 69 年等每一列的总和。

我尝试了 tapply、ddply 等,但无法找到真正可行的方法。

【问题讨论】:

    标签: r plyr


    【解决方案1】:

    首先我们设置用作输入的矩阵。

    Lines <- "1  2   3   4   5  
    1950   7 20  21  15  61  
    1951   2 10   6  26  57  
    1952  12 27  43  37  34  
    1953  14 16  40  47  94  
    1954   2 17  62 113 101  
    1955   3  4  43  99 148  
    1956   2 47  31  85  79  
    1957  17  5  38 216 228  
    1958  11 20  15  76  68  
    1959  16 20  43  30 226  
    1960   9 28  28  70 201  
    1961   1 31 124  74 137  
    1962  12 25  37  41 200  "
    DF <- read.table(text = Lines, check.names = FALSE)
    m <- as.matrix(DF)
    

    现在,我们在下面展示一些替代解决方案。 (1) 似乎是最灵活的,因为我们可以轻松地将 sum 替换为其他函数以获得不同的效果,但 (2) 对于这个特定问题来说是最短的。另请注意,存在一些细微差别。 (1) 产生一个data.frame,而另外两个产生一个矩阵。

    1) aggregate

    decade <- 10 * as.numeric(rownames(m)) %/% 10
    m.ag <- aggregate(m, data.frame(decade), sum)
    

    这给出了这个data.frame:

    > m.ag
      decade  1   2   3   4    5
    1   1950 86 186 342 744 1096
    2   1960 22  84 189 185  538
    

    2) rowsum 这个比较短。它产生一个矩阵结果。

    rowsum(m, decade)
    

    3) split/sapply。这也产生了一个矩阵。如果我们有 DF,我们可以将 as.data.frame(m) 替换为 DF,稍微缩短它。

    t(sapply(split(as.data.frame(m), decade), colSums))
    

    编辑:添加解决方案 (2) 和 (3) 添加了一些说明。

    【讨论】:

    • +1 表示rowsum()。感谢您扩展您的答案以包含这些附加选项。
    【解决方案2】:

    您首先需要定义一个分组变量,然后您可以使用您选择的工具(aggregateddply 等等)。

    > aggregate(x, by=list(trunc(as.numeric(rownames(x))/10)), sum)
      Group.1 X1  X2  X3  X4   X5
    1     195 86 186 342 744 1096
    2     196 22  84 189 185  538
    

    【讨论】:

    • 这正是我所说的“更优雅”的意思。非常好。
    【解决方案3】:

    可能有一个更优雅的基础 R 解决方案,但这是可行的。

    # Construct a nicely named vector with which to split your data.frame
    breaks <- seq(1950, 2000, by=10)
    names <- c("50's", "60's", "70's", "80's", "90's")
    decade <- cut(as.numeric(row.names(df)), 
                  seq(1950, 2000, by=10), labels=names, right=FALSE)
    
    # by() splits df apart, operating on each of its pieces.
    # do.call(rbind, ...) sutures the results back together.
    do.call(rbind, by(df, decade, colSums))
    #      X1  X2  X3  X4   X5
    # 50's 86 186 342 744 1096
    # 60's 22  84 189 185  538
    

    【讨论】:

      【解决方案4】:

      by 是一个选项:

      by(x,10*(as.numeric(rownames(x))%/%10),colSums)
      INDICES: 1950
         1    2    3    4    5 
        86  186  342  744 1096 
      ------------------------------------------------------------ 
      INDICES: 1960
        1   2   3   4   5 
       22  84 189 185 538 
      

      【讨论】:

        猜你喜欢
        • 2021-12-29
        • 2018-02-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-09
        • 1970-01-01
        • 2017-11-22
        相关资源
        最近更新 更多