array_recycling | R Documentation |
Arithmetic and other binary operations in base R between a matrix or
array and a vector don't let the user control how the latter should
be recycled: it's always recycled along the first dimension of the
matrix or array. This has led users to use various tricks when they
need recycling along the second dimension (a.k.a. "horizontal recycling"),
like the popular "double-transposition" trick: t(t(x) / cs)
.
However this is inefficient and inelegant.
as_tile()
is meant to address this.
It also allows arithmetic and other binary operations between two arrays of distinct dimensions (rejected as "non-conformable" by arithmetic operations in base R), typically between a small one (the tile) and a bigger one, as long as their geometries are compatible.
as_tile(x, along=1L, dim=NULL)
x |
An array-like object or a vector. |
along |
Can only be used when |
dim |
|
A tile object (tile is an extension of array).
base::colSums
in the base package.
array and matrix objects in base R.
## ---------------------------------------------------------------------
## 2D EXAMPLES
## ---------------------------------------------------------------------
m0 <- matrix(1:54, nrow=6)
x <- c(-1, 0, 100)
## Arithmetic operations in base R recycle 'x' along the first dimension
## of the matrix ("vertical recycling"):
m0 * x
## To recycle 'x' along the second dimension of the matrix ("horizontal
## recycling"), we turn it into an "horizontal" tile:
t <- as_tile(x, along=2)
t
m0 * t
## The above produces the same result as the double-transposition trick
## but is more efficient (and also makes code easier to read):
stopifnot(identical(m0 * t, t(t(m0) * x)))
## A less artificial example:
cs0 <- colSums(m0)
m <- m0 / as_tile(cs0, along=2)
stopifnot(all(colSums(m) == 1)) # sanity check
## Using an arbitrary 2D tile:
t <- m0[1:2, 1:3]
t
## Unfortunately arithmetic operations in base R refuse to operate on
## arrays that don't have the same dimensions:
## Not run:
m0 / t # ERROR! (non-conformable arrays)
## End(Not run)
## Wrapping 't' in a tile object makes this work:
m0 / as_tile(t)
## ---------------------------------------------------------------------
## 3D EXAMPLES
## ---------------------------------------------------------------------
## Note that colSums() supports multidimensional arrays. In this case
## the user can use the 'dims' argument to control how the array should
## be sliced into "columns". See '?base::colSums' for the details.
a <- array(runif(300), dim=c(10, 5, 6))
## Using 'dims=2' indicates that the columns are the 2D slices obtained
## by slicing the array along its 3rd dimension. With this slicing, each
## column is a 10 x 5 matrix.
cs2 <- colSums(a, dims=2)
cs2 # vector of length 6 (one value per 2D slice)
t <- as_tile(cs2, along=3)
a / t
stopifnot(all(colSums(a / t, dims=2) == 1)) # sanity check
## By default (i.e. when 'dims=1') the array is considered to be made
## of 5*6 columns of length 10.
cs1 <- colSums(a)
cs1 # 5 x 6 matrix
t <- as_tile(cs1, dim=c(1L, dim(cs1)))
a / t
stopifnot(all(colSums(a / t) == 1)) # sanity check
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.