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

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

Related

How can to associate dimnames of array and data frame index-values in R?

I have the array A
A
,,A
[,1] [,2] [,3]
[1,] 3 7 8
[2,] 4 11 9
[3,] 2 12 4.3
,,B
[,1] [,2] [,3]
[1,] 31 7 8
[2,] 4.2 4 9.5
[3,] 1 1 7
,,C
[,1] [,2] [,3]
[1,] 4 71 8.3
[2,] 4 41 9
[3,] 11 0 73
,,D
[,1] [,2] [,3]
[1,] 7 7 8.3
[2,] 3 4.1 9
[3,] 1 0.5 73
dim(A)
3 3 4
dimnames(A)[3]
A B C D
and I have the data.frame df
df
X Y Z
2 1 A
3 2 D
I would like to put in a new column of df, the values of array A, based on df index-values X(row for the array), Y(column for the array) and third dimension Z, let's say, my aspect result is:
df
X Y Z Res
2 1 A 4 # Res is the value of array A in A[2,1,"A"]
3 2 D 0.5 # Res is the value of array A in A[3,2,"D"]
I tried this code:
df$Res <- NA
if (df$Z == dimnames(A)[3]){
for (i in 1:nrow(df)){
df[i,4] <- A[df[i,1],df[i,2],df[i,3]]
}
}
But it'doesn't work well...
Any idea to associate the dimnames of third dimension array and data frame index-value?
P.S. This is a simple example. My true array is:
dim(A)
137 93 227
and
dim(df)
6080 3
P.S.2 I prefer to don't use merge or other type of similar code for allocation problem

Mean of multiple dimensions' observations within array

I have got an array as follows:
ar.1 = array(1:12, dim=c(2,2,3))
> ar.1
, , 1
[,1] [,2]
[1,] 1 3
[2,] 2 4
, , 2
[,1] [,2]
[1,] 5 7
[2,] 6 8
, , 3
[,1] [,2]
[1,] 9 11
[2,] 10 12
I just need to compute the mean between the values in the 3 different layers and obtain a 2-dimensional matrix.
Expected output:
5 7
6 8
5 = (1+5+9) / 3
6 = (2+6+10) / 3
etc..
It should be really easy but I couldn't find any quick solution yet as my real array is larger than 2x2x3.
Thanks
Try this
matrix(rowMeans(apply(ar.1, 3, c)), dim(ar.1)[1], dim(ar.1)[2])
# [,1] [,2]
#[1,] 5 7
#[2,] 6 8

ordering a "window" of a multidimensional array

I'm new to R and this is my first question (apologies if the question is posed wrongly).
I would like to change the order of the rows accordingly to the values by the columns of a "window" inside a multidimensional array.
Here's a simplified example:
x1<-matrix(c(1,3,2,4), 2)
x1
[,1] [,2]
[1,] 1 2
[2,] 3 4
x2<-matrix(c(7,5,8,6),2)
x2
[,1] [,2]
[1,] 7 8
[2,] 5 6
x3<-array(c(x1,x2), dim = c(2,2,2))
I would then like to re-arrange the first "window" of the array so that it will be like x4:
x4<-x1[order(x1[,1], decreasing = TRUE),]
x4
[,1] [,2]
[1,] 3 4
[2,] 1 2
How can I do that inside the array?
Plus, will the change affect also all the other "windows" in the array?
So that, in the end, I will end up with an array like this:
x3[,,1]
[,1] [,2]
[1,] 3 4
[2,] 1 2
x3[,,2]
[,1] [,2]
[1,] 5 6
[2,] 7 8
Thanks a lot!
You are trying to reorder the rows (1st dimension) of the array; It is similar to how you will reorder the rows of a matrix except that it is 3d so you need to specify three indices:
x3[order(x3[,2,1], decreasing = T),,]
#, , 1
# [,1] [,2]
#[1,] 3 4
#[2,] 1 2
#, , 2
# [,1] [,2]
#[1,] 5 6
#[2,] 7 8

Sum of matrices in 3-dimensional object of variable dimensions without looping

I have a 3-dimensional object in R, which contains n square matrices. For example:
myObject[,,1] # returns a square matrix
myObject[,,2] # returns a square matrix of the same size
...
All the matrices within the object are of the same size. I'd like to add all matrices together, without a loop. This is simple enough if I know how many matrices are in the object. For example:
matrixSum <- myObject[,,1] + myObject[,,2] + myObject[,,3]
The problem is, I need to do this for several thousand such objects, and there are a variable number of matrices in each object. Is there any way I can do this without a loop? In a sense, I'd like to try to "vectorize" this summation.
The most convient, but certainly not the fastest, is to use apply:
matrixSum <- apply(myObject, c(1,2), sum)
Example
myObject <- array(c(1,2,3),dim = c(3,4,3))
myObject
, , 1
[,1] [,2] [,3] [,4]
[1,] 1 1 1 1
[2,] 2 2 2 2
[3,] 3 3 3 3
, , 2
[,1] [,2] [,3] [,4]
[1,] 1 1 1 1
[2,] 2 2 2 2
[3,] 3 3 3 3
, , 3
[,1] [,2] [,3] [,4]
[1,] 1 1 1 1
[2,] 2 2 2 2
[3,] 3 3 3 3
apply(myObject, c(1,2), sum)
[,1] [,2] [,3] [,4]
[1,] 3 3 3 3
[2,] 6 6 6 6
[3,] 9 9 9 9
Addition:
Using rowSums should be must faster:
rowSums(myObject, dims = 2)
[,1] [,2] [,3] [,4]
[1,] 3 3 3 3
[2,] 6 6 6 6
[3,] 9 9 9 9

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.

Resources