library("broadcast")
# Simple example ====
x <- array(1:20, c(5, 4))
y <- array(-1:-15, c(5, 3))
z <- array(21:40, c(5, 4))
input <- list(x, y, z)
# column binding:
bind_array(input, 2L)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11]
## [1,] 1 6 11 16 -1 -6 -11 21 26 31 36
## [2,] 2 7 12 17 -2 -7 -12 22 27 32 37
## [3,] 3 8 13 18 -3 -8 -13 23 28 33 38
## [4,] 4 9 14 19 -4 -9 -14 24 29 34 39
## [5,] 5 10 15 20 -5 -10 -15 25 30 35 40
# Broadcasting example ====
x <- array(1:20, c(5, 4))
y <- array(-1:-5, c(5, 1))
z <- array(21:40, c(5, 4))
input <- list(x, y, z)
bind_array(input, 2L)
## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
## [1,] 1 6 11 16 -1 21 26 31 36
## [2,] 2 7 12 17 -2 22 27 32 37
## [3,] 3 8 13 18 -3 23 28 33 38
## [4,] 4 9 14 19 -4 24 29 34 39
## [5,] 5 10 15 20 -5 25 30 35 40
# Mixing types ====
# here, atomic and recursive arrays are mixed,
# resulting in recursive arrays
# creating the arrays:
x <- c(
lapply(1:3, \(x)sample(c(TRUE, FALSE, NA))),
lapply(1:3, \(x)sample(1:10)),
lapply(1:3, \(x)rnorm(10)),
lapply(1:3, \(x)sample(letters))
) |> matrix(4, 3, byrow = TRUE)
dimnames(x) <- list(letters[1:4], LETTERS[1:3])
print(x)
## A B C
## a logical,3 logical,3 logical,3
## b integer,10 integer,10 integer,10
## c numeric,10 numeric,10 numeric,10
## d character,26 character,26 character,26
y <- matrix(1:12, 4, 3)
print(y)
## [,1] [,2] [,3]
## [1,] 1 5 9
## [2,] 2 6 10
## [3,] 3 7 11
## [4,] 4 8 12
z <- matrix(letters[1:12], c(4, 3))
# column-binding:
input <- list(x = x, y = y, z = z)
bind_array(input, along = 2L)
## A B C y.1 y.2 y.3 z.1 z.2 z.3
## a logical,3 logical,3 logical,3 1 5 9 "a" "e" "i"
## b integer,10 integer,10 integer,10 2 6 10 "b" "f" "j"
## c numeric,10 numeric,10 numeric,10 3 7 11 "c" "g" "k"
## d character,26 character,26 character,26 4 8 12 "d" "h" "l"
# Illustrating `along` argument ====
# using recursive arrays for clearer visual distinction
input <- list(x = x, y = y)
bind_array(input, along = 0L) # binds on new dimension before first
## , , A
##
## a b c d
## x logical,3 integer,10 numeric,10 character,26
## y 1 2 3 4
##
## , , B
##
## a b c d
## x logical,3 integer,10 numeric,10 character,26
## y 5 6 7 8
##
## , , C
##
## a b c d
## x logical,3 integer,10 numeric,10 character,26
## y 9 10 11 12
bind_array(input, along = 1L) # binds on first dimension (i.e. rows)
## A B C
## a logical,3 logical,3 logical,3
## b integer,10 integer,10 integer,10
## c numeric,10 numeric,10 numeric,10
## d character,26 character,26 character,26
## y.1 1 5 9
## y.2 2 6 10
## y.3 3 7 11
## y.4 4 8 12
bind_array(input, along = 2L)
## A B C y.1 y.2 y.3
## a logical,3 logical,3 logical,3 1 5 9
## b integer,10 integer,10 integer,10 2 6 10
## c numeric,10 numeric,10 numeric,10 3 7 11
## d character,26 character,26 character,26 4 8 12
bind_array(input, along = 3L) # bind on new dimension after last
## , , x
##
## A B C
## a logical,3 logical,3 logical,3
## b integer,10 integer,10 integer,10
## c numeric,10 numeric,10 numeric,10
## d character,26 character,26 character,26
##
## , , y
##
## A B C
## a 1 5 9
## b 2 6 10
## c 3 7 11
## d 4 8 12
bind_array(input, along = 0L, TRUE) # binds on new dimension after last
## , , x
##
## A B C
## a logical,3 logical,3 logical,3
## b integer,10 integer,10 integer,10
## c numeric,10 numeric,10 numeric,10
## d character,26 character,26 character,26
##
## , , y
##
## A B C
## a 1 5 9
## b 2 6 10
## c 3 7 11
## d 4 8 12
bind_array(input, along = 1L, TRUE) # binds on last dimension (i.e. columns)
## A B C y.1 y.2 y.3
## a logical,3 logical,3 logical,3 1 5 9
## b integer,10 integer,10 integer,10 2 6 10
## c numeric,10 numeric,10 numeric,10 3 7 11
## d character,26 character,26 character,26 4 8 12
bind_array(input, along = 2L, TRUE)
## A B C
## a logical,3 logical,3 logical,3
## b integer,10 integer,10 integer,10
## c numeric,10 numeric,10 numeric,10
## d character,26 character,26 character,26
## y.1 1 5 9
## y.2 2 6 10
## y.3 3 7 11
## y.4 4 8 12
bind_array(input, along = 3L, TRUE) # bind on new dimension before first
## , , A
##
## a b c d
## x logical,3 integer,10 numeric,10 character,26
## y 1 2 3 4
##
## , , B
##
## a b c d
## x logical,3 integer,10 numeric,10 character,26
## y 5 6 7 8
##
## , , C
##
## a b c d
## x logical,3 integer,10 numeric,10 character,26
## y 9 10 11 12
# binding, with empty arrays ====
emptyarray <- array(numeric(0L), c(0L, 3L))
dimnames(emptyarray) <- list(NULL, paste("empty", 1:3))
print(emptyarray)
## empty 1 empty 2 empty 3
input <- list(x = x, y = emptyarray)
bind_array(input, along = 1L, comnames_from = 2L) # row-bind
## A B C
## a logical,3 logical,3 logical,3
## b integer,10 integer,10 integer,10
## c numeric,10 numeric,10 numeric,10
## d character,26 character,26 character,26
# Illustrating `name_along` ====
x <- array(1:20, c(5, 3), list(NULL, LETTERS[1:3]))
y <- array(-1:-20, c(5, 3))
z <- array(-1:-20, c(5, 3))
bind_array(list(a = x, b = y, z), 2L)
## A B C b.1 b.2 b.3
## [1,] 1 6 11 -1 -6 -11 -1 -6 -11
## [2,] 2 7 12 -2 -7 -12 -2 -7 -12
## [3,] 3 8 13 -3 -8 -13 -3 -8 -13
## [4,] 4 9 14 -4 -9 -14 -4 -9 -14
## [5,] 5 10 15 -5 -10 -15 -5 -10 -15
bind_array(list(x, y, z), 2L)
## A B C
## [1,] 1 6 11 -1 -6 -11 -1 -6 -11
## [2,] 2 7 12 -2 -7 -12 -2 -7 -12
## [3,] 3 8 13 -3 -8 -13 -3 -8 -13
## [4,] 4 9 14 -4 -9 -14 -4 -9 -14
## [5,] 5 10 15 -5 -10 -15 -5 -10 -15
bind_array(list(a = unname(x), b = y, c = z), 2L)
## a.1 a.2 a.3 b.1 b.2 b.3 c.1 c.2 c.3
## [1,] 1 6 11 -1 -6 -11 -1 -6 -11
## [2,] 2 7 12 -2 -7 -12 -2 -7 -12
## [3,] 3 8 13 -3 -8 -13 -3 -8 -13
## [4,] 4 9 14 -4 -9 -14 -4 -9 -14
## [5,] 5 10 15 -5 -10 -15 -5 -10 -15
bind_array(list(x, a = y, b = z), 2L)
## A B C a.1 a.2 a.3 b.1 b.2 b.3
## [1,] 1 6 11 -1 -6 -11 -1 -6 -11
## [2,] 2 7 12 -2 -7 -12 -2 -7 -12
## [3,] 3 8 13 -3 -8 -13 -3 -8 -13
## [4,] 4 9 14 -4 -9 -14 -4 -9 -14
## [5,] 5 10 15 -5 -10 -15 -5 -10 -15
input <- list(x, y, z)
names(input) <- c("", NA, "")
bind_array(input, 2L)
## A B C
## [1,] 1 6 11 -1 -6 -11 -1 -6 -11
## [2,] 2 7 12 -2 -7 -12 -2 -7 -12
## [3,] 3 8 13 -3 -8 -13 -3 -8 -13
## [4,] 4 9 14 -4 -9 -14 -4 -9 -14
## [5,] 5 10 15 -5 -10 -15 -5 -10 -15bind_array
Dimensional Binding of Arrays with Broadcasting
Description
bind_array() binds (atomic/recursive) arrays and (atomic/recursive) matrices.
Allows for broadcasting.
Usage
bind_array(
input,
along,
rev = FALSE,
ndim2bc = 16L,
name_along = TRUE,
comnames_from = 1L
)
Arguments
input
|
a list of arrays; both atomic and recursive arrays are supported, and can be mixed. If argument input has length 0, or it contains exclusively objects where one or more dimensions are 0, an error is returned. If input has length 1, bind_array() simply returns input[[1L]]. input may not contain more than 2^16 objects.
|
along
|
a single integer, indicating the dimension along which to bind the dimensions. I.e. use along = 1 for row-binding, along = 2 for column-binding, etc. Specifying along = 0 will bind the arrays on a new dimension before the first, making along the new first dimension. Specifying along = N + 1, with N = max(lst.ndim(input)), will create an additional dimension (N + 1) and bind the arrays along that new dimension.
|
rev
|
Boolean, indicating if along should be reversed, counting backwards. If FALSE (default), along works like normally; if TRUE, along is reversed. I.e. along = 0, rev = TRUE is equivalent to along = N+1, rev = FALSE; and along = N+1, rev = TRUE is equivalent to along = 0, rev = FALSE; with N = max(lst.ndim(input)).
|
ndim2bc
|
a single non-negative integer; specify here the maximum number of dimensions that are allowed to be broadcasted when binding arrays. If ndim2bc = 0L, no broadcasting will be allowed at all.
|
name_along
|
Boolean, indicating if dimension along should be named. Please run the code in the examples section to get a demonstration of the naming behaviour. |
comnames_from
|
either an integer scalar or NULL. Indicates which object in input should be used for naming the shared dimension. If NULL, no communal names will be given. For example: When binding columns of matrices, the matrices will share the same rownames. Using comnames_from = 10 will then result in bind_array() using rownames(input[[10]]) for the rownames of the output. |
Details
The API of bind_array() is inspired by the fantastic abind::abind() function by Tony Plare & Richard Heiberger (2016).
But bind_array() differs considerably from abind::abind in the following ways:
-
bind_array()allows for broadcasting, whileabind::abinddoes not support broadcasting. -
bind_array()is generally faster and more memory-efficient thanabind::abind, asbind_array()relies heavily on ‘C’ and ‘C++’ code. -
bind_array()differs fromabind::abindin that it can handle recursive arrays properly
(theabind::abindfunction would unlist everything to atomic arrays, ruining the structure). -
unlike
abind::abind,bind_array()only binds (atomic/recursive) arrays and matrices.
bind_array()does not attempt to convert things to arrays when they are not arrays, but will give an error instead.
This saves computation time and prevents unexpected results. -
bind_array()has more streamlined naming options, compared toabind::abind.
Value
An array.
References
Plate T, Heiberger R (2016). abind: Combine Multidimensional Arrays. R package version 1.4-5, https://CRAN.R-project.org/package=abind.