I've got an array like this :
, , 1
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
, , 2
[,1] [,2] [,3]
[1,] 10 13 16
[2,] 11 14 17
[3,] 12 15 18
, , 3
[,1] [,2] [,3]
[1,] 19 22 25
[2,] 20 23 26
[3,] 21 24 27
And I would like to add a column for each component, filled with 0, to finally have this :
, , 1
[,1] [,2] [,3] [,4]
[1,] 1 4 7 0
[2,] 2 5 8 0
[3,] 3 6 9 0
, , 2
[,1] [,2] [,3] [,4]
[1,] 10 13 16 0
[2,] 11 14 17 0
[3,] 12 15 18 0
, , 3
[,1] [,2] [,3] [,4]
[1,] 19 22 25 0
[2,] 20 23 26 0
[3,] 21 24 27 0
Is there a simple way to do this using R?
Here is a way:
library(abind)
abind(x, array(0, replace(dim(x), 2, 1)), along = 2)
And another one:
aperm(apply(x, c(1, 3), c, 0), c(2, 1, 3))
You could also try something like (though its a bit manual but should be faster than the other base R solution)
indx <- dim(df) + c(0, 1, 0)
array(sapply(1:indx[3], function(x) cbind(df[,,x], 0)), indx)
Some benchmarks
n <- 1e5
df <- array(1:27, c(3, 3, n))
library(abind)
library(microbenchmark)
flodel1 <- function(x) abind(x, array(0, replace(dim(x), 2, 1)), along = 2)
flodel2 <- function(x) aperm(apply(x, c(1, 3), c, 0), c(2, 1, 3))
David <- function(x) {indx <- dim(x) + c(0, 1, 0) ; array(sapply(seq_len(indx[3]), function(y) cbind(x[,,y], 0)), indx)}
Res <- microbenchmark(flodel1(df),
flodel2(df),
David(df))
# Unit: milliseconds
# expr min lq mean median uq max neval
# flodel1(df) 45.8943 65.37496 90.68902 90.24751 107.5991 159.9881 100
# flodel2(df) 553.4831 634.73127 673.95636 679.79709 710.0540 808.6248 100
# David(df) 434.9524 531.85597 576.77011 555.46865 626.3344 757.9358 100
Just for the challenge, another idea (with some extra sauce) that seems valid unless I've missed something:
add_col_or_row = function(x, n = 1, add_col = T, fill = 0)
{
m1 = matrix(x, ncol = if(add_col) nrow(x) * ncol(x) else nrow(x), byrow = T)
m2 = matrix(fill, nrow = if(add_col) dim(x)[3] else prod(dim(x)[-1]),
ncol = if(add_col) nrow(x) * n else n)
array(t(cbind(m1, m2)),
c(nrow(x) + ((!add_col) * n), ncol(x) + (add_col * n), dim(x)[3]))
}
aa = array(1:24, c(3, 4, 2))
aa
#, , 1
#
# [,1] [,2] [,3] [,4]
#[1,] 1 4 7 10
#[2,] 2 5 8 11
#[3,] 3 6 9 12
#
#, , 2
#
# [,1] [,2] [,3] [,4]
#[1,] 13 16 19 22
#[2,] 14 17 20 23
#[3,] 15 18 21 24
add_col_or_row(aa, 2, T)
#, , 1
#
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 1 4 7 10 0 0
#[2,] 2 5 8 11 0 0
#[3,] 3 6 9 12 0 0
#
#, , 2
#
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 13 16 19 22 0 0
#[2,] 14 17 20 23 0 0
#[3,] 15 18 21 24 0 0
#
add_col_or_row(aa, 2, F)
#, , 1
#
# [,1] [,2] [,3] [,4]
#[1,] 1 4 7 10
#[2,] 2 5 8 11
#[3,] 3 6 9 12
#[4,] 0 0 0 0
#[5,] 0 0 0 0
#
#, , 2
#
# [,1] [,2] [,3] [,4]
#[1,] 13 16 19 22
#[2,] 14 17 20 23
#[3,] 15 18 21 24
#[4,] 0 0 0 0
#[5,] 0 0 0 0
And a benchmark using David Arenburg's data:
microbenchmark(flodel1(df), add_col_or_row(df), times = 20)
#Unit: milliseconds
# expr min lq median uq max neval
# flodel1(df) 35.69158 54.88014 55.58363 56.40300 58.31250 20
# add_col_or_row(df) 19.87134 38.57792 39.11297 39.58347 44.59873 20
identical("dimnames<-"(flodel1(df), NULL), add_col_or_row(df))
#[1] TRUE
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With