РЕДАКТИРОВАТЬ: я упростил пример и функции после комментария @jdorbes.Надеюсь, это улучшит пост.
У меня есть серия N-мерных массивов, которые мне нужно «вращать» вдоль их первого измерения (например, в 2-мерной матрице, переключаясь между собой в первой и второй половинеколонны).Например, рассматривая трехмерный случай, я могу определить свой массив следующим образом:
field <- array(1:32, c(4, 4, 2))
Я разработал очень базовую и зависящую от размера функцию, которая достигает цели.Конечно, эту же операцию можно выполнить и с head
и tail
, но я обнаружил, что это более быстрый способ:
rotate.test <- function(field) {
xxx <- field
dims <- length(dim(xxx))
if (dims == 2) { # for x,y data
ll <- length(field[, 1])
field[(ll * 0.5 + 1 ):ll, ] <- xxx[1:(ll * 0.5), ]
field[1:(ll * 0.5), ] <- xxx[(ll * 0.5 + 1):ll, ]
}
if (dims == 3) { # for x,y,t data
ll <- length(field[, 1, 1])
field[(ll * 0.5 + 1 ):ll, , ] <- xxx[1:(ll * 0.5), , ]
field[1:(ll * 0.5), , ] <- xxx[(ll * 0.5 + 1):ll, , ]
}
return(field)
}
Результат читается как:
> rotate.test(field)
, , 1
[,1] [,2] [,3] [,4]
[1,] 3 7 11 15
[2,] 4 8 12 16
[3,] 1 5 9 13
[4,] 2 6 10 14
, , 2
[,1] [,2] [,3] [,4]
[1,] 19 23 27 31
[2,] 20 24 28 32
[3,] 17 21 25 29
[4,] 18 22 26 30
Это может быть дополнительно обобщено для N-мерных данных, но я думаю, вы видите, что это очень неуклюже.После этого поста Выберите по одному из n измерений в массиве Я обнаружил, что могу обобщить его, введя очень полезный вызов функции do.call
:
array_indexing <- function(field, dim, value, drop = FALSE) {
indices <- rep(list(bquote()), length(dim(field)))
indices[[dim]] <- value
out <- do.call("[",c(list(field), indices, list(drop = drop)))
return(out)
}
Затем с помощью abind
rotate.evo <- function(field) {
require("abind")
xdim <- 1
ll <- dim(field)[xdim]
firstchunk <- array_indexing(field, xdim, (ll * 0.5 + 1):ll)
secondchunk <- array_indexing(field, xdim, 1:(ll * 0.5))
out <- abind(firstchunk, secondchunk, along = 1)
return(out)
}
Однако сравнительный анализ (выполненный с rbenchmark
) очень вероятен из-за вызова abind
вместо более простой замены индекса.
test replications elapsed relative user.self sys.self
2 rotate.evo(field) 1000 0.547 6.36 0.542 0.005
1 rotate.test(field) 1000 0.086 1.00 0.069 0.016
user.child sys.child
2 0 0
1 0 0
Вот оновозникает мой вопрос: есть ли способ обобщить замену индекса, как это делается с помощью функции array_indexing
?Другими словами, есть ли способ выполнить это переключение быстро и надежно без написания специальных случаев для каждого измерения?Я пытаюсь выяснить, существует ли в R метод для обобщения замены некоторого индекса массива по определенному измерению.
Я знаю, что это может звучать странно, но было бы здорово, если бы я могИзбегайте загрузки дополнительных пакетов.Этот код включен в онлайн-инструмент, который должен быть как можно легче (на самом деле, я тоже пытаюсь избавиться от abind!)
Спасибо за любую подсказку, и, пожалуйста, спросите, не является ли какая-либо часть моего объяснения неполной,Бест, Паоло