如何在R中对向量的分组元素求和

时间:2012-02-21 14:14:18

标签: r

假设我有这个载体

v <- c(1:100) 

我希望得到这个:

b[1] = sum (v[c(1:10)])
b[2] = sum (v[c(11:20)])
...
...

我可以做一个循环来解决这个问题,但我很确定有一个“R方式”应该是这样的:

b <- groupedSum(v, 10) 

其中b将是一个向量,其中每组10个相加 什么是R方式?

5 个答案:

答案 0 :(得分:6)

> tapply( v, (seq_along(v)-1) %/% 10, sum)
  0   1   2   3   4   5   6   7   8   9 
 55 155 255 355 455 555 655 755 855 955

如果那里有NA,你可能需要在sum后的参数列表中添加na.rm = TRUE。

评论:我认为Tyler的方法更完整,因为它提供了更好的文档。它需要解决cut()函数的变幻莫测,我一直觉得它有错误的默认值。为了创建一个捕获1:100全部的分组,他需要使用101元素向量。但这不是泰勒的错。发给他任何进一步的投票,他的回答更好。

如果gsk可以使用副对象而不会遇到类困难,那么他是一个比我更好的人。输出看起来像一个列表,但它确实是不同的。用他的例子:

> is.list(by(v,idx,sum))
[1] FALSE
> is.matrix(by(v,idx,sum))
[1] FALSE
> is.vector(by(v,idx,sum))
[1] FALSE

我认为by-objects有点像命名向量,有点像矩阵,但是继承矩阵类的失败总是让我感到困惑。

答案 1 :(得分:3)

第1步:为群组制作索引:

N <- 50
size <- 10 # Size of a group
v <- seq(N)
idx <- as.factor(rep(seq(N/size),each=size))

步骤2:使用任意数量的矢量化工具(by,plyr等)对各组进行求和:

by(v,idx,sum)

第3步:获利

idx: 1
[1] 55
--------------------------------------------------------------------------------- 
idx: 2
[1] 155
--------------------------------------------------------------------------------- 
idx: 3
[1] 255
--------------------------------------------------------------------------------- 
idx: 4
[1] 355
--------------------------------------------------------------------------------- 
idx: 5
[1] 455

答案 2 :(得分:2)

已经有两种好方法了。我建议使用cut来为你提供输出范围:

v <- c(1:100) 
dat <- data.frame(v=v, cat = cut(v, seq(0, 100, by=10)))
aggregate(v~cat, data=dat, sum)

<强>产量:

        cat   v
1    (0,10]  55
2   (10,20] 155
3   (20,30] 255
4   (30,40] 355
5   (40,50] 455
6   (50,60] 555
7   (60,70] 655
8   (70,80] 755
9   (80,90] 855
10 (90,100] 955

答案 3 :(得分:1)

对于较大的数据集,更快的方法(比上述方法快20-300倍)是作为矩阵转换然后使用colSums。

> colSums( matrix( v, nrow = 10, ncol = 10 ))
 [1]  55 155 255 355 455 555 655 755 855 955

考虑更大的数据集

> n_per_group = 1e3
> n_groups    = 1e3;  
> v = 1:(n_per_group * n_groups)

使用矩阵方法需要5ms

> start = Sys.time();
> r1 =colSums( matrix( v, nrow = n_per_group, ncol = n_groups ))
> end = Sys.time()
> end-start
Time difference of 0.005604982 secs

使用tapply方法需要601ms

> start = Sys.time();
> r2 = as.numeric( tapply( v, (seq_along( v ) - 1) %/% n_per_group, sum ) )
> end = Sys.time()
> end-start
Time difference of 0.6015229 secs
> all.equal( r1, r2)
 [1] TRUE

使用by方法需要103ms

> start = Sys.time();
> idx = as.factor( rep( seq( n_groups ), each = n_per_group ) )
> r3 = as.numeric(by(v,idx,sum))
> end = Sys.time() 
> end-start
Time difference of 0.1034958 secs
> all.equal( r1, r3)
 [1] TRUE

使用dataframe方法需要1675ms

> start = Sys.time();
> dat <- data.frame(v=v, cat = cut(v, seq(0, n_per_group * n_groups, by= n_per_group )))
> r4 = aggregate(v~cat, data=dat, sum)$v
> end = Sys.time()
> end-start
Time difference of 1.675465 secs
> all.equal( r1, r4)
[1] TRUE

并使用备用矩阵方法需要334ms

> library( Matrix )
> start = Sys.time();
> f     = gl( n_groups, n_per_group )
> r5    = as( f, "sparseMatrix" ) %*% v
> r5    = as.numeric( r5[ , 1 ] )
> end   = Sys.time()
> end-start
Time difference of 0.334847 secs
> all.equal( r1, r5)
[1] TRUE

答案 4 :(得分:0)

此解决方案需要Matrix库。

v <- seq(100)# example data
f <- gl(10,10)# generate factor for grouping
v_sums <- as(f,"sparseMatrix") %*% v