按组计算R中列的总和

7
在下面的矩阵数据集中:
       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等方法,但无法找到实际可行的解决方案。

4个回答

14

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

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)生成一个数据框而另外两个生成矩阵。 1)aggregate
decade <- 10 * as.numeric(rownames(m)) %/% 10
m.ag <- aggregate(m, data.frame(decade), sum)

这将得到这个数据框:

> 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,我们可以用DF来替换as.data.frame(m),从而稍微缩短一下代码。

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

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


1
感谢您扩展您的答案以包括这些附加选项。rowsum() 加 1 分。 - Josh O'Brien

6

首先,您需要定义一个分组变量,然后您可以使用您选择的工具(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

这正是我所说的“更加优美”的意思。非常不错。 - Josh O'Brien

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

2

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 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接