equalizing matrices for combining in abind R - arrays

I believe that a similar question was asked here, but I can't seem to find it anymore.
I have two matrices with different dimensions, and I want to equalise them so that I can combine them in an array.
for example, I have the following two matrices:
a <- matrix(1:6, 3, 2)
b <- matrix(1:12, 4, 3)
a
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
b
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
Because I am working with time series data, I would like the added rows/colums to have NAs in them. In my example, matrix a would get an extra column and an extra row only containing NAs like this:
[,1] [,2] [,3]
[1,] 1 4 NA
[2,] 2 5 NA
[3,] 3 6 NA
[4,] NA NA NA
In my dataset I will have 79 matrices with unequal dimensions, and I need to make them as big as the matrix with the largest dimensions.

If b is the largest matrix, you can create a matrix with the same dimensions as b, filled with NA, and replace the rows and columns corresponding to the smaller matrix a with the values of a:
a2 <- "[<-"(x = matrix(NA, nrow = nrow(b), ncol = ncol(b)),
i = 1:nrow(a), j = 1:ncol(a),
value = a)
a2
# [,1] [,2] [,3]
# [1,] 1 4 NA
# [2,] 2 5 NA
# [3,] 3 6 NA
# [4,] NA NA NA
Example with several matrices, where we find the largest matrix and pad all matrices with NA to match the dimension of the largest.
# create some matrices of different size
a <- matrix(1:6, nrow = 3, ncol = 2)
b <- matrix(1:12, nrow = 4, ncol = 3)
c <- matrix(1:4, nrow = 2, ncol = 2)
# put them in a list
l <- list(a, b, c)
# index of largest (here, max number of rows) matrix in the list
id <- which.max(unlist((lapply(l, nrow))))
# pad matrices with NA
l2 <- lapply(l, function(x){
x <- "[<-"(x = matrix(NA, nrow = nrow(l[[id]]), ncol = ncol(l[[id]])),
i = 1:nrow(x), j = 1:ncol(x),
value = x)
})
l2
# [[1]]
# [,1] [,2] [,3]
# [1,] 1 4 NA
# [2,] 2 5 NA
# [3,] 3 6 NA
# [4,] NA NA NA
#
# [[2]]
# [,1] [,2] [,3]
# [1,] 1 5 9
# [2,] 2 6 10
# [3,] 3 7 11
# [4,] 4 8 12
#
# [[3]]
# [,1] [,2] [,3]
# [1,] 1 3 NA
# [2,] 2 4 NA
# [3,] NA NA NA
# [4,] NA NA NA

As you only want to extend the small matrix with NA, we can use a simple approach such as:
create a matrix as big as b, with only NA. Code:
extended.a = matrix(NA,nrow(b),ncol(b))
fill this matrix with the values from a. Code:
extended.a[cbind(rep(1:nrow(a),ncol(a)), rep(1:ncol(a),each=nrow(a)))] = a
edit:
As per Roland's suggestion, you can also get the vector of indices with which(..., arr.ind=TRUE).
For example, which(TRUE | a, arr.ind=TRUE)
Or even: which(matrix(TRUE,nrow(a),ncol(a), arr.ind=TRUE)
Or far better, using the expand.grid function: expand.grid(1:nrow(a), 1:ncol(a))

Maybe we can try the following base R option
> replace(NA + b, cbind(c(row(a)), c(col(a))), a)
[,1] [,2] [,3]
[1,] 1 4 NA
[2,] 2 5 NA
[3,] 3 6 NA
[4,] NA NA NA

Related

Randomly populate R arrays

I would like to be able to populate an array with different values at each array level.
Consider the array
x <- array(dim = c(2, 5, 2)) # 2 levels, 5 columns, 2 rows
x
, , 1
[,1] [,2] [,3] [,4] [,5]
[1,] NA NA NA NA NA
[2,] NA NA NA NA NA
, , 2
[,1] [,2] [,3] [,4] [,5]
[1,] NA NA NA NA NA
[2,] NA NA NA NA NA
I now generate random values to populate levels of the the array
y <- replicate(2, sample(1:10, 5, replace = FALSE))
y
[,1] [,2]
[1,] 6 5
[2,] 8 6
[3,] 9 3
[4,] 3 7
[5,] 2 9
What is the best way to go about randomly populating the first level of x (x[,,1]) with the first column of y (i.e., values 6, 8, 9, 3, 2) and likewise the second level of x (x[,, 2]) with the second column of y (i.e., 5, 6, 3, 7, 9)?
That is, the final result might be
, , 1
[,1] [,2] [,3] [,4] [,5]
[1,] 6 8 3 3 2
[2,] 9 6 3 2 8
, , 2
[,1] [,2] [,3] [,4] [,5]
[1,] 6 6 9 3 5
[2,] 7 5 7 9 3
This would be a straightforward task if each level consisted of the same value (e.g., both levels having values 6, 8, 9, 3, 2 at random), but for this purpose, each level of the array needs to contain a different subset of values.
Any simple solutions? I realize the 'abind' R package may work here, but I think there is an easier way forward.
You seem to have all the pieces in hand. You just need to put them together. Decide the size of the third dimension for your array, construct it so you can populate rather than grow, put together the set of values you'll use to populate the array, then populate it.
set.seed(123)
d3 <- 2
x <- array(dim = c(2, 5, d3))
y <- replicate(d3, sample(1:10, 5, replace = FALSE))
for (i in seq_len(d3)) x[,,i] <- sample(y[,i], 10, replace = TRUE)
x
# , , 1
#
# [,1] [,2] [,3] [,4] [,5]
# [1,] 6 7 3 8 8
# [2,] 4 4 6 3 6
#
# , , 2
#
# [,1] [,2] [,3] [,4] [,5]
# [1,] 3 4 4 8 5
# [2,] 4 3 4 8 1
y
# [,1] [,2]
# [1,] 3 1
# [2,] 8 5
# [3,] 4 8
# [4,] 7 4
# [5,] 6 3
You can simply recast a 10x2 matrix into a 2x5x2 array:
set.seed(2017);
y <- replicate(2, sample(1:10, 5), replace = F)
array(apply(y, 2, function(x) sample(x, 10, replace = TRUE)), dim = c(2, 5, 2))
#, , 1
#
# [,1] [,2] [,3] [,4] [,5]
#[1,] 3 10 4 5 9
#[2,] 10 4 5 3 9
#
#, , 2
#
# [,1] [,2] [,3] [,4] [,5]
#[1,] 10 2 1 10 8
#[2,] 1 10 2 1 1
#y;
# [,1] [,2]
#[1,] 10 8
#[2,] 5 1
#[3,] 4 4
#[4,] 3 10
#[5,] 9 2
Explanation: apply(y, 2, ...) creates a 10x2 matrix where entries in column 1 are sampled from column 1 of y, and entries in column 2 are sampled from column 2 of y. We then simply recast the 10x2 matrix into an array of dimensions c(2, 5, 2).

R: extract matrix from array, using a matrix of indices

I´m coding in R and I have a 3 dimensional array that contains data (ab in the example). Then I have a matrix that contains indices of the 3rd array dimension (idx). This matrix has the same number of rows and columns of the array. I want to use the indices contained in idx to extract data from the array, to get a matrix with same dimension of idx. Please see the example below:
a <- c(1:9)
b <- rev(a)
#array of data
ab <- array(c(a,b), dim = c(3,3,2))
ab
, , 1
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
, , 2
[,1] [,2] [,3]
[1,] 9 6 3
[2,] 8 5 2
[3,] 7 4 1
#matrix of indices
idx <- matrix(sample(1:2,9,replace=TRUE), nrow = 3)
idx
[,1] [,2] [,3]
[1,] 2 2 2
[2,] 2 1 1
[3,] 1 1 1
#now I want to get the following matrix:
[,1] [,2] [,3]
[1,] 9 6 3
[2,] 8 5 8
[3,] 3 6 9
#these two don´t do the job
ab[idx]
ab[ , ,idx]
Does anybody know how can I get that?
Many thanks!
Sara
We need an index for row/column and the third dimension (from 'idx') to extract the elements. We do this by cbinding the row index, column index with the 'idx'.
i1 <- dim(ab)[1]
j1 <- dim(ab)[2]
matrix(ab[cbind(rep(seq_len(i1), j1),rep(seq_len(j1), each = i1), c(idx))], ncol=3)
# [,1] [,2] [,3]
#[1,] 9 6 3
#[2,] 8 5 8
#[3,] 3 6 9
Might be a bit complicated, but it works at least:
First of all my idx:
[,1] [,2] [,3]
[1,] 2 2 1
[2,] 1 2 1
[3,] 2 2 2
First I made it both to a vector:
idVec <- as.vector(idx)
d3mat <- apply(ab,3,as.vector)
Then I constructed a vector, to run over each element:
len <- length(idVec)
len <- 1:len
Then I apllied a function to each element of the vector len:
resultvec <- sapply(len, function(x, vec, mat){return(mat[x,vec[x]])}, mat=d3mat, vec=idVec)
And then transform the result back to a matrix:
matrix(resultVec,3,3)
[,1] [,2] [,3]
[1,] 9 6 7
[2,] 2 5 8
[3,] 7 4 1

Apply column vector to each row of each matrix in array in R

If I have the array
> (arr = array(c(1,1,2,2), c(2,2,2)))
, , 1
[,1] [,2]
[1,] 1 2
[2,] 1 2
, , 2
[,1] [,2]
[1,] 1 2
[2,] 1 2
then how could I apply a column vector, say c(3,3), to each row of each matrix and sum these up? So essentially, I need to do 4 * c(1,2) %*% c(3,3). Could an apply function be used here?
Thanks everyone for the help! I believe the correct method is
sum(apply(arr, c(1,3), function(x) x %*% c(1,2,3)))
which here we are dotting the vector [1,2,3] to each row of each matrix in our array called arr and summing them up. Note that here I changed the array to be
arr = array(c(1,2,3,4,5,6,7,8,9,10,11,12), c(2,3,2))
arr
, , 1
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
, , 2
[,1] [,2] [,3]
[1,] 7 9 11
[2,] 8 10 12
and now the vector we are dotting the rows with is c(1,2,3) instead of c(3,3) in the original post.
EDITED
This should give you the answer:
l <- list(matrix(c(1,1,2,2), ncol = 2),
matrix(c(1,1,2,2), ncol = 2))
l
#[[1]]
# [,1] [,2]
# [1,] 1 2
# [2,] 1 2
#
# [[2]]
# [,1] [,2]
# [1,] 1 2
# [2,] 1 2
ivector <- c(3, 3) # a vector that is multiplied with the rows of each listelement
# apply over all listelements
res <- lapply(l, function(x, ivector){
#apply to all rows of the matrizes
apply(x, 1, function(rowel, ivector){
return(sum(rowel %*% ivector))
}, ivector = ivector)
}, ivector = ivector)
res
#[[1]]
#[1] 9 9
#
#[[2]]
#[1] 9 9
# And finally sum up the results:
sum(Reduce("+", res))
#[1] 36
Does that help?

R filling array by rows

I would like to do some matrix operations and it would be best to utilize 3 (or higher) dimensional arrays. If I want to fill matrices by row there is an argument (byrow = TRUE) however there is no such option for creating/filling a multidimensional array. The only way I've been able to accomplish it is by using aperm to transpose an array that was filled by column. For example:
arr.1 <- array(1:12, c(3,2,2))
arr.1
arr.2 <- aperm(arr.1, c(2,1,3))
arr.2
produces the correct result, a dimension 2,3,2 array that is filled by row. It seems a bit counter intuitive to have to work backward from a Column x Row x Range array to get to a Row x Column x Range array. This might be bad habits from previous f77 coding or have I overlooked something simple?
Arrays in R are filled in by traversing the first dimension first. So first the first dimension is traversed, then the second dimension, and then third dimension if it is available.
In case of a matrix:
array(c(1,2,3), dim = c(3,3))
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 2 2 2
[3,] 3 3 3
Or with assignment:
M <- array(dim = c(3,3))
M[,] <- c(1,2,3)
M
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 2 2 2
[3,] 3 3 3
Assigning to the second dimension is easy:
M <- array(dim = c(3,3))
M[,2:3] <- c(1,2,3)
M
[,1] [,2] [,3]
[1,] NA 1 1
[2,] NA 2 2
[3,] NA 3 3
But assigning to first dimension is more tricky. The following doesn't give the expected result:
M <- array(dim = c(3,3))
M[2:3,] <- c(1,2,3)
M
[,1] [,2] [,3]
[1,] NA NA NA
[2,] 1 3 2
[3,] 2 1 3
Data is filled by first traversing the first dimension, then second. What we want is to first traverse the second dimension, then first. So we have to aperm the array (or transpose in case of matrix).
M <- array(dim = c(3,3))
Mt <- aperm(M)
Mt[,2:3] <- c(1,2,3)
M <- aperm(Mt)
M
[,1] [,2] [,3]
[1,] NA NA NA
[2,] 1 2 3
[3,] 1 2 3
There are maybe more elegant ways to do the last which I am not aware of.
If you want to interpret a vector of values as an n-dimensional array in "row-major order" (as in C, or more precisely, last dimension varying fastest), you can use function array2() from package listarrays. This is the logical extension of matrix(..., byrow = TRUE) to multiple dimensions.
Compare base R
> (a <- array(1:24, c(2,3,4)))
, , 1
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
, , 2
[,1] [,2] [,3]
[1,] 7 9 11
[2,] 8 10 12
, , 3
[,1] [,2] [,3]
[1,] 13 15 17
[2,] 14 16 18
, , 4
[,1] [,2] [,3]
[1,] 19 21 23
[2,] 20 22 24
with
> library(listarrays)
> (a <- array2(1:24, c(2,3,4)))
, , 1
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 13 17 21
, , 2
[,1] [,2] [,3]
[1,] 2 6 10
[2,] 14 18 22
, , 3
[,1] [,2] [,3]
[1,] 3 7 11
[2,] 15 19 23
, , 4
[,1] [,2] [,3]
[1,] 4 8 12
[2,] 16 20 24
My recommendation would be to "teach" yourself the default order by running
foo<- array(1:60,3,4,5)
Then you can fill an arbitrary array either by rearranging your source vector or by creating matrices and loading them into the z-layers of the array in the order desired.

R how to store jagged arrays

Here, I need to build a jagged arrays to store data, here is the code for you
a<-list()
b=1
for(i in 1:5){
b+1
a[i]<-array(0,c(b,1))
}
You can see, what I want to do it to save arrays of different dimensions, even though here is 0 as an example, into a.
Would you please help me on how to create a jagged arrays/lists/matrices, to store different dimensions arrays?
Thanks
For create jagged arrays also know as ragged arrays this is an example using list function and using x[1] for indexing:
x = list(a=c(1,2,3,4),b=c(-1,-3,-4),c=c(23,45,23,45,25,48),d=c(2,1))
stk = stack(x)
ustk= unstack(stk)
identical(ustk,x)
[1] TRUE
> x
$a
[1] 1 2 3 4
$b
[1] -1 -3 -4
$c
[1] 23 45 23 45 24 48
$d
[1] 2 1
> x[1]
$a
[1] 1 2 3 4
> x[2]
$b
[1] -1 -3 -4
other method:
# empty list to start with
X <- list()
# we get a vector
v1 <- c(1, 2, 3, 4, 5)
# add it to the ragged array
X <- c(X, list(v1))
# get another couple of vectors and add them as well
v2 <- c(9, 8, 7, 6)
v3 <- c(2, 4, 6, 8)
X <- c(X, list(v2, v3))
# add some more elements to the first vector in
# the vector directly
X[[1]] <- c(X[[1]], 4, 3, 2, 1)
For created jagged matrices this is an example:
x = c(3,2,5)
struct = lapply(x, function(i){
sapply(1:i, function(k){
c(rep(NA, k-1),exp( - (0:(i-k))))
})
})
> x
[1] 3 2 5
> struct
[[1]]
[,1] [,2] [,3]
[1,] 1.0000000 NA NA
[2,] 0.3678794 1.0000000 NA
[3,] 0.1353353 0.3678794 1
[[2]]
[,1] [,2]
[1,] 1.0000000 NA
[2,] 0.3678794 1
[[3]]
[,1] [,2] [,3] [,4] [,5]
[1,] 1.00000000 NA NA NA NA
[2,] 0.36787944 1.00000000 NA NA NA
[3,] 0.13533528 0.36787944 1.0000000 NA NA
[4,] 0.04978707 0.13533528 0.3678794 1.0000000 NA
[5,] 0.01831564 0.04978707 0.1353353 0.3678794 1

Resources