В R, как вы обобщаете вычисление совокупной суммы по разным полям матрицы в многомерный массив?

Например, учитывая матрицу

a2 <- array(1:6, dim = c(2,3))
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

Совокупная сумма по разным полям может быть рассчитана с помощью apply:

apply(a2, 2, cumsum)
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    3    7   11
t(apply(a2, 1, cumsum))
     [,1] [,2] [,3]
[1,]    1    4    9
[2,]    2    6   12

Обратите внимание, что в последнем случае требуется некоторое изменение формы. Теперь вопрос:

Как бы вы рассчитали кумулятивные суммы для многомерного массива?

Например, для трехмерного массива, такого как:

a3 <- array(1:24, dim = c(2,3,4))

Меня интересует накопленная сумма по строкам, столбцам и третьему измерению, сохраняющая структуру исходного массива. В частности, совокупная сумма строки должна быть:

, , 1

     [,1] [,2] [,3]
[1,]    1    4    9
[2,]    2    6   12

, , 2

     [,1] [,2] [,3]
[1,]    7   16   27
[2,]    8   18   30

, , 3

     [,1] [,2] [,3]
[1,]   13   28   45
[2,]   14   30   48

, , 4

     [,1] [,2] [,3]
[1,]   19   40   63
[2,]   20   42   66

Каков будет ответ для n-мерного массива?

2
dzeltzer 1 Май 2019 в 15:06

4 ответа

Лучший ответ

Экстраполирование от @G. В ответе Гротендика эта функция использует aperm для вычисления кумулятивной суммы по любому полю n-мерного массива:

array_cumsum <- function(a, margin) {
  n <- length(dim(a))
  permorder <- append(x = 2:n, 1, margin - 1)
  aperm(apply(a, -margin, cumsum), permorder)
}

Например, используя простой массив, состоящий из единиц, для простоты просмотра кумулятивных сумм, функция может использоваться для вычисления запаса по 2-му измерению:

a <- array(1, dim = c(2,3,4))
array_cumsum(a3, 2)
# , , 1
# 
# [,1] [,2] [,3]
# [1,]    1    2    3
# [2,]    1    2    3
# 
# , , 2
# 
# [,1] [,2] [,3]
# [1,]    1    2    3
# [2,]    1    2    3
# 
# , , 3
# 
# [,1] [,2] [,3]
# [1,]    1    2    3
# [2,]    1    2    3
# 
# , , 4
# 
# [,1] [,2] [,3]
# [1,]    1    2    3
# [2,]    1    2    3

А также над 3-м измерением:

array_cumsum(a3, 3)
# , , 1
# 
# [,1] [,2] [,3]
# [1,]    1    1    1
# [2,]    1    1    1
# 
# , , 2
# 
# [,1] [,2] [,3]
# [1,]    2    2    2
# [2,]    2    2    2
# 
# , , 3
# 
# [,1] [,2] [,3]
# [1,]    3    3    3
# [2,]    3    3    3
# 
# , , 4
# 
# [,1] [,2] [,3]
# [1,]    4    4    4
# [2,]    4    4    4
0
dzeltzer 2 Май 2019 в 07:18

Одним из способов является использование старого доброго цикла for

res <- a3
for (k in 1:dim(a3)[3]) res[, , k] <- t(apply(a3[, , k], 1, cumsum))
res
#, , 1
#
#     [,1] [,2] [,3]
#[1,]    1    4    9
#[2,]    2    6   12
#
#, , 2
#
#     [,1] [,2] [,3]
#[1,]    7   16   27
#[2,]    8   18   30
#
#, , 3
#
#     [,1] [,2] [,3]
#[1,]   13   28   45
#[2,]   14   30   48
#
#, , 4
#
#     [,1] [,2] [,3]
#[1,]   19   40   63
#[2,]   20   42   66
3
Maurits Evers 1 Май 2019 в 12:34

Это почти дает то, что вы хотите, но результат транспонирован

apply(a3, c(1, 3), cumsum)

#, , 1

#     [,1] [,2]
#[1,]    1    2
#[2,]    4    6
#[3,]    9   12

#, , 2

#     [,1] [,2]
#[1,]    7    8
#[2,]   16   18
#[3,]   27   30

#, , 3

#     [,1] [,2]
#[1,]   13   14
#[2,]   28   30
#[3,]   45   48

#, , 4

#     [,1] [,2]
#[1,]   19   20
#[2,]   40   42
#[3,]   63   66

Я не знаю, как мы можем перенести результат в один и тот же вызов apply (должен быть способ). Я старался

t(apply(a3, c(1, 3), cumsum))
apply(a3, c(1, 3), function(x) t(cumsum(x)))

Но это не работает Однако сейчас, если мы снова используем apply и транспонируем, мы можем вернуть исходную структуру.

apply(apply(a3, c(1, 3), cumsum), c(1, 3), t)
1
Ronak Shah 1 Май 2019 в 12:55

Используйте apply, а затем aperm. Единственная сложность - правильно определить размер полей:

aperm(apply(a3, -2, cumsum), c(2, 1, 3))

Каждый из них также работает:

aperm(apply(a3, c(1, 3), cumsum), c(2, 1, 3))

aperm(apply(a3, c(3, 1), cumsum), c(3, 1, 2))

apply(apply(a3, -2, cumsum), -2, c)

apply(apply(a3, c(1, 3), cumsum), c(1, 3), c)

library(plyr)
aa <- aperm(aaply(a3, c(1, 3), cumsum), c(1, 3, 2))
dimnames(aa) <- NULL
1
G. Grothendieck 2 Май 2019 в 01:35