Вычисление скользящих сумм векторов с R - PullRequest
4 голосов
/ 02 ноября 2011

У меня длинный вектор x и другой v, который содержит длины. Я хотел бы сложить x так, чтобы ответ y был вектором длины length(v), а y[1] - sum(x[1:v[i]]), y[2] - sum(x[(1+v[1]):(v[1]+v[2])]) и так далее. По сути, это выполнение разреженного умножения матриц из пространства измерения length(x) в пространство измерения length(v). Однако я бы предпочел не вводить «продвинутую технику», хотя мне, возможно, придется. Это должно быть очень, очень быстро. Может ли кто-нибудь придумать что-нибудь попроще, чем использование пакета с разреженной матрицей?

Пример -

x <- c(1,1,3,4,5)
v <- c(2,3)
y <- myFunc(x,v)

y должно быть c(2,12)

Я открыт для любой предварительной обработки, например, для сохранения в v начальных индексов каждого отрезка.

Ответы [ 4 ]

8 голосов
/ 02 ноября 2011
  y <- cumsum(x)[cumsum(v)]
  y <- c(y[1], diff(y))

Похоже, что он выполняет дополнительную работу, потому что он вычисляет сумму для всего вектора, но на самом деле он быстрее, чем другие решения, как для небольшого, так и для большого числа групп.

Вот как я смоделировал данные

set.seed(5)
N <- 1e6
n <- 10
x <- round(runif(N,0,100),1)
v <- as.vector(table(sample(n, N, replace=TRUE)))

На моей машине время с n <- 10:

  • Брэндон Бертельсен (для петли): 0,017
  • Рамнатх (строка): 0,057
  • Джон (разделить / применить): 0,280
  • Аарон (cumum): 0,008

меняется на n <- 1e5 время:

  • Брэндон Бертельсен (для петли): 2,181
  • Рамнатх (строка): 0,226
  • Джон (разделить / применить): 0,852
  • Аарон (сумма): 0,015

Я подозреваю, что это быстрее, чем делать умножение матриц, даже с разреженным матричным пакетом, потому что не нужно формировать матрицу или делать какие-либо умножения. Если требуется больше скорости, я подозреваю, что это можно было бы ускорить, написав ее на C; не сложно сделать с пакетами inline и rcpp, но я оставлю это вам.

1 голос
/ 02 ноября 2011

Вы можете сделать это, используя rowsum.Это должно быть достаточно быстро, так как он использует C код в фоновом режиме.

y <- rowsum(x, rep(1:length(v), v))
1 голос
/ 02 ноября 2011

Вот немного другая тактика.

s <- rep(1:length(v), v)
l <- split(x, s)
y <- sapply(l, sum)
0 голосов
/ 02 ноября 2011

Попробуйте что-то вроде:

for (i in 1:length(v)) { 
    y[i] <- ifelse(i > 1,sum(x[v[i-1]:v[i]]), sum(x[1:v[i]]))
}
...