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(1, 5)) # rows will be broadcasted from 1 to 5
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] [,10] [,11] [,12] [,13]
## [1,] 1 6 11 16 -1 -2 -3 -4 -5 21 26 31 36
## [2,] 2 7 12 17 -1 -2 -3 -4 -5 22 27 32 37
## [3,] 3 8 13 18 -1 -2 -3 -4 -5 23 28 33 38
## [4,] 4 9 14 19 -1 -2 -3 -4 -5 24 29 34 39
## [5,] 5 10 15 20 -1 -2 -3 -4 -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 -15
# binding vectors and arrays ====
x <- setNames(1:4, letters[1:4]) |> vector2array(direction = 2L, ndim = 2L)
y <- array(1:20, c(5, 4), list(NULL, LETTERS[1:4]))
input <- list(x, y)
bind_array(input, 1L, comnames_from = 1L) # row-bind, with names from vector `x`
## a b c d
## [1,] 1 2 3 4
## [2,] 1 6 11 16
## [3,] 2 7 12 17
## [4,] 3 8 13 18
## [5,] 4 9 14 19
## [6,] 5 10 15 20bind_array
Dimensional Binding of Arrays with Broadcasting
Description
bind_array() binds (atomic/recursive) arrays along a dimension.
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. If the user wishes to include vectors to bind in input, the vectors must be turned into arrays; for example using vector2array.
|
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 as a result from the (broadcasted) binding.
The type of the result is determined from the highest type of any of the inputs.
The hierarchy of types is:
raw < logical < integer < double < complex < character < list .
If one of the input arrays is a broadcaster, the result will also be a broadcaster.
References
Plate T, Heiberger R (2016). abind: Combine Multidimensional Arrays. R package version 1.4-5, https://CRAN.R-project.org/package=abind.