假设我有这个载体
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方式?
答案 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