顺序添加n个元素
Sequential adding of n elements
我 运行 在 R 中遇到一个问题,我需要在 R 中操作一个向量。
假设我有一个长度为 12 的向量:
vector <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
我现在需要将元素 1+2
、3+4
、5+6
等添加到一个新向量中,在示例中为:
newvector <- c(3, 7, 11, 15, 19, 23)
我需要为更长的序列做同样的事情,这样它就添加了前三个,然后是 4-6
,然后是 7-9
等等
newvector <- c(6, 15, 24, 33)
等等。
我会这样做:split
将向量分成 n 组,Reduce
对每组的第 n 个元素求和。
newvector <- Reduce(`+`, split(vector,c(1,2)))
[1] 3 7 11 15 19 23
作为一个函数,你可以这样:
splitSum <- function(v, n) Reduce(`+`, split(v, c(1:n)))
splitSum(vector,3)
[1] 6 15 24 33
一个选项可以是:
tapply(x, cumsum(seq_along(x) %% 2 == 1), sum)
1 2 3 4 5 6
3 7 11 15 19 23
对于 n = 3:
tapply(x, cumsum(seq_along(x) %% 3 == 1), sum)
1 2 3 4
6 15 24 33
v <- 1:12
v1 <- rep(0, ((length(v))/2))
for(i in 1:((length(v))/2))
v1[i] <- v[i]+v[i+1]
v1
我只是使用了一个 for
循环。也许在 if
条件之前检查向量长度是否可以分成 2 和 3 个元素的组可能会改善这个...
将向量放入矩阵,然后使用colSums
。这是执行此操作的函数。
vector <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
calculate_sum <- function(v, n) {
colSums(matrix(v, nrow = n))
}
calculate_sum(vector, 2)
#[1] 3 7 11 15 19 23
calculate_sum(vector, 3)
#[1] 6 15 24 33
具有一些基准测试的 RcppRoll
解决方案:
library(RcppRoll)
#> Warning: package 'RcppRoll' was built under R version 4.1.2
v <- as.numeric(1:12e4)
n <- 3L
fRoll <- function(v, n) roll_sum(v, n, by = n)
fMatrix <- function(v, n) colSums(matrix(v, nrow = n))
fCumsum <- function(v, n) diff(c(0, cumsum(v))[seq(1, length(v) + 1L, n)])
fReduce <- function(v, n) Reduce(`+`, split(v, 1:n))
fLoop <- function(v, n) {
vOut <- numeric(ceiling(length(v)/n))
idx <- 0:(n - 1)
for (i in seq_along(vOut)) {
vOut[i] <- sum(v[i*n - idx])
}
return(vOut)
}
fApply1 <- function(v, n) tapply(v, cumsum(seq_along(v) %% n == 1), sum)
fApply2 <- function(v, n) tapply(v, 0:(length(v) - 1) %/% n, sum)
microbenchmark::microbenchmark(fRoll(v, n), fMatrix(v, n), fCumsum(v, n), fReduce(v, n), fLoop(v, n), fApply1(v, n), fApply2(v, n))
#> Unit: microseconds
#> expr min lq mean median uq max neval
#> fRoll(v, n) 145.7 215.45 290.512 234.35 284.05 1559.6 100
#> fMatrix(v, n) 282.0 360.85 428.385 382.20 437.70 1678.0 100
#> fCumsum(v, n) 1724.5 1805.05 2060.008 1859.15 2094.30 6169.5 100
#> fReduce(v, n) 1852.5 1943.15 2056.358 1985.75 2096.15 4335.6 100
#> fLoop(v, n) 19976.5 22618.05 25725.492 23860.95 25300.10 73618.3 100
#> fApply1(v, n) 69336.2 73841.35 77741.583 76639.80 80791.70 123253.8 100
#> fApply2(v, n) 69178.3 73870.80 77691.152 76582.65 79066.60 101159.1 100
# check that all the functions return the same result
results <- lapply(list(fRoll, fMatrix, fCumsum, fReduce, fLoop, fApply1, fApply2), function(f) as.numeric(f(v, n)))
sum(duplicated.default(results)) == length(results) - 1L
#> [1] TRUE
Created on 2021-12-02 by the reprex package (v2.0.1)
可能不会在基础 r 中击败 colSums(matrix(
。
我 运行 在 R 中遇到一个问题,我需要在 R 中操作一个向量。
假设我有一个长度为 12 的向量:
vector <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
我现在需要将元素 1+2
、3+4
、5+6
等添加到一个新向量中,在示例中为:
newvector <- c(3, 7, 11, 15, 19, 23)
我需要为更长的序列做同样的事情,这样它就添加了前三个,然后是 4-6
,然后是 7-9
等等
newvector <- c(6, 15, 24, 33)
等等。
我会这样做:split
将向量分成 n 组,Reduce
对每组的第 n 个元素求和。
newvector <- Reduce(`+`, split(vector,c(1,2)))
[1] 3 7 11 15 19 23
作为一个函数,你可以这样:
splitSum <- function(v, n) Reduce(`+`, split(v, c(1:n)))
splitSum(vector,3)
[1] 6 15 24 33
一个选项可以是:
tapply(x, cumsum(seq_along(x) %% 2 == 1), sum)
1 2 3 4 5 6
3 7 11 15 19 23
对于 n = 3:
tapply(x, cumsum(seq_along(x) %% 3 == 1), sum)
1 2 3 4
6 15 24 33
v <- 1:12
v1 <- rep(0, ((length(v))/2))
for(i in 1:((length(v))/2))
v1[i] <- v[i]+v[i+1]
v1
我只是使用了一个 for
循环。也许在 if
条件之前检查向量长度是否可以分成 2 和 3 个元素的组可能会改善这个...
将向量放入矩阵,然后使用colSums
。这是执行此操作的函数。
vector <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
calculate_sum <- function(v, n) {
colSums(matrix(v, nrow = n))
}
calculate_sum(vector, 2)
#[1] 3 7 11 15 19 23
calculate_sum(vector, 3)
#[1] 6 15 24 33
具有一些基准测试的 RcppRoll
解决方案:
library(RcppRoll)
#> Warning: package 'RcppRoll' was built under R version 4.1.2
v <- as.numeric(1:12e4)
n <- 3L
fRoll <- function(v, n) roll_sum(v, n, by = n)
fMatrix <- function(v, n) colSums(matrix(v, nrow = n))
fCumsum <- function(v, n) diff(c(0, cumsum(v))[seq(1, length(v) + 1L, n)])
fReduce <- function(v, n) Reduce(`+`, split(v, 1:n))
fLoop <- function(v, n) {
vOut <- numeric(ceiling(length(v)/n))
idx <- 0:(n - 1)
for (i in seq_along(vOut)) {
vOut[i] <- sum(v[i*n - idx])
}
return(vOut)
}
fApply1 <- function(v, n) tapply(v, cumsum(seq_along(v) %% n == 1), sum)
fApply2 <- function(v, n) tapply(v, 0:(length(v) - 1) %/% n, sum)
microbenchmark::microbenchmark(fRoll(v, n), fMatrix(v, n), fCumsum(v, n), fReduce(v, n), fLoop(v, n), fApply1(v, n), fApply2(v, n))
#> Unit: microseconds
#> expr min lq mean median uq max neval
#> fRoll(v, n) 145.7 215.45 290.512 234.35 284.05 1559.6 100
#> fMatrix(v, n) 282.0 360.85 428.385 382.20 437.70 1678.0 100
#> fCumsum(v, n) 1724.5 1805.05 2060.008 1859.15 2094.30 6169.5 100
#> fReduce(v, n) 1852.5 1943.15 2056.358 1985.75 2096.15 4335.6 100
#> fLoop(v, n) 19976.5 22618.05 25725.492 23860.95 25300.10 73618.3 100
#> fApply1(v, n) 69336.2 73841.35 77741.583 76639.80 80791.70 123253.8 100
#> fApply2(v, n) 69178.3 73870.80 77691.152 76582.65 79066.60 101159.1 100
# check that all the functions return the same result
results <- lapply(list(fRoll, fMatrix, fCumsum, fReduce, fLoop, fApply1, fApply2), function(f) as.numeric(f(v, n)))
sum(duplicated.default(results)) == length(results) - 1L
#> [1] TRUE
Created on 2021-12-02 by the reprex package (v2.0.1)
可能不会在基础 r 中击败 colSums(matrix(
。