ベクトルがあり、すべてのn
数を合計して、結果を返す必要があります。これは、現在私が計画している方法です。これを行うためのより良い方法はありますか?
v = 1:100
n = 10
sidx = seq.int(from=1, to=length(v), by=n)
eidx = c((sidx-1)[2:length(sidx)], length(v))
thesum = sapply(1:length(sidx), function(i) sum(v[sidx[i]:eidx[i]]))
これは与える:
thesum
[1] 55 155 255 355 455 555 655 755 855 955
unname(tapply(v, (seq_along(v)-1) %/% n, sum))
# [1] 55 155 255 355 455 555 655 755 855 955
合計したい場合n個の連続した数字ごとcolSums
を使用します
合計する場合n番目ごと数値はrowSums
を使用します
joshのコメントによると、これはn
がlength(v)
を適切に分割した場合にのみ機能します。
rowSums(matrix(v, nrow=n))
[1] 460 470 480 490 500 510 520 530 540 550
colSums(matrix(v, nrow=n))
[1] 55 155 255 355 455 555 655 755 855 955
古いバージョンは機能しません。ここでは、rep
を使用してグループ化係数を作成する新しいオーナーです。 cut
を使用する必要はありません:
n <- 5
vv <- sample(1:1000,100)
seqs <- seq_along(vv)
tapply(vv,rep(seqs,each=n)[seqs],FUN=sum)
tapply
を使用できます
tapply(1:100,cut(1:100,10),FUN=sum)
またはリストを取得するには
by(1:100,cut(1:100,10),FUN=sum)
[〜#〜]編集[〜#〜]
1:92
がある場合は、カットを次のように置き換えることができます。
cut(1:92,seq(1,92,10),include.lowest=T)
1つの方法は、ベクトルを行列に変換してから、列の合計を取得することです。
colSums(matrix(v, nrow=n))
[1] 55 155 255 355 455 555 655 755 855 955
注意してください:これは暗黙的に入力ベクトルが行列に再形成できると仮定しています。それができない場合、Rはベクトルの要素をリサイクルして行列を完成させます。
v <- 1:100
n <- 10
cutpoints <- seq( 1 , length( v ) , by = n )
categories <- findInterval( 1:length( v ) , cutpoints )
tapply( v , categories , sum )
apply
ファミリの関数なしでそれを行うもう1つの方法を追加します
v <- 1:100
n <- 10
diff(c(0, cumsum(v)[slice.index(v, 1)%%n == 0]))
## [1] 55 155 255 355 455 555 655 755 855 955
これまでに提供された主なバリエーションのいくつかを次に示します
f0 <- function(v, n) {
sidx = seq.int(from=1, to=length(v), by=n)
eidx = c((sidx-1)[2:length(sidx)], length(v))
sapply(1:length(sidx), function(i) sum(v[sidx[i]:eidx[i]]))
}
f1 <- function(v, n, na.rm=TRUE) { # 'tapply'
unname(tapply(v, (seq_along(v)-1) %/% n, sum, na.rm=na.rm))
}
f2 <- function(v, n, na.rm=TRUE) { # 'matrix'
nv <- length(v)
if (nv %% n)
v[ceiling(nv / n) * n] <- NA
colSums(matrix(v, n), na.rm=na.rm)
}
f3 <- function(v, n) { # 'cumsum'
nv = length(v)
i <- c(seq_len(nv %/% n) * n, if (nv %% n) nv else NULL)
diff(c(0L, cumsum(v)[i]))
}
基本的なテストケースは
v = list(1:4, 1:5, c(NA, 2:4), integer())
n = 2
f0
最終テストで失敗しますが、これはおそらく修正される可能性があります
> f0(integer(), n)
Error in sidx[i]:eidx[i] : NA/NaN argument
Cumsumアプローチf3
は丸め誤差が発生しやすく、NAがv
の早い段階で存在するため、後で「poisons」が発生します。
> f3(c(NA, 2:4), n)
[1] NA NA
パフォーマンスの面では、元のソリューションは悪くありません
> library(rbenchmark)
> cols <- c("test", "elapsed", "relative")
> v <- 1:100; n <- 10
> benchmark(f0(v, n), f1(v, n), f2(v, n), f3(v, n),
+ columns=cols)
test elapsed relative
1 f0(v, n) 0.012 3.00
2 f1(v, n) 0.065 16.25
3 f2(v, n) 0.004 1.00
4 f3(v, n) 0.004 1.00
しかし、行列解f2
は高速で柔軟なようです(たとえば、n
要素未満の後続のチャンクの処理を調整します)
> v <- runif(1e6); n <- 10
> benchmark(f0(v, n), f2(v, n), f3(v, n), columns=cols, replications=10)
test elapsed relative
1 f0(v, n) 5.804 34.141
2 f2(v, n) 0.170 1.000
3 f3(v, n) 0.251 1.476
パーティーに少し遅れましたが、まだrowsum()
の答えがありません。 rowsum()
はtapply()
よりも効率的であることが証明されており、他のいくつかの応答と比較しても非常に効率的だと思います。
_rowsum(v, rep(seq_len(length(v)/n), each=n))[,1]
# 1 2 3 4 5 6 7 8 9 10
# 55 155 255 355 455 555 655 755 855 955
_
@Josh O'Brienのグループ化手法を使用すると、効率がさらに向上する可能性があります。
_rowsum(v, (seq_along(v)-1) %/% n)[,1]
# 0 1 2 3 4 5 6 7 8 9
# 55 155 255 355 455 555 655 755 855 955
_
unname()
でラップするだけで、グループ名を削除できます。
1つの方法は、rollapply
からZoo
を使用することです。
_rollapply(v, width=n, FUN=sum, by=n)
# [1] 55 155 255 355 455 555 655 755 855 955
_
また、length(v)
がn
の倍数でない場合:
_v <- 1:92
rollapply(v, width=n, FUN=sum, by=n, partial=T, align="left")
# [1] 55 155 255 355 455 555 655 755 855 183
_