Write and read 3D arrays in R - arrays

I have a 3D array in R constructed as (although the names don’t seem to show up):
v.arr <- array(1:18, c(2,3,3), dimnames = c("A", "B", "X",
"Y","Z","P","Q","R"))
and it shows up like this when printed to the screen:
, , 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
I write it out to a file using:
write.table(v.arr, file = “Test Data”)
I then read it back in with:
test.data <- read.table(“Test Data”)
and I get this:
X1 X2 X3 X4 X5 X6 X7 X8 X9
1 1 3 5 7 9 11 13 15 17
2 2 4 6 8 10 12 14 16 18
Obviously, I need to do something to either structure the file before writing or restructure it on the read-back to get back the 3D array. I can always restructure the data that I get from reading. Is that the best approach? Thanks in advance.

Your issue is that you are using write.table to do this, so it is (I believe) coercing your array to a table. If you are looking to save it and don't mind that it would be in an R-specific format, you can easily use the save and load functions.
save(v.arr,file = "~/Desktop/v.arr.RData")
rm(list=ls())
load("~/Desktop/v.arr.RData")
v.arr

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

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

R subsetting and assigning in a multidimensional array

I am working with R with a 3D dimensional array. I am trying to use it like a set of 2D matrix for different time instants.
I have find a behavior that I really don't understand and I will like to know why is happening. I have tried to find a explanation here and in other places but until now I still have the doubt.
I have my 3D array like this:
array3D=array(1:45,c(5,3,3))
And as I expected I can access to an individual 2D matrix
array3D[1,,]
[,1] [,2] [,3]
[1,] 1 16 31
[2,] 6 21 36
[3,] 11 26 41
However trying to access to two 2D matrices I don't get what I expect
array3D[1:2,,]
, , 1
[,1] [,2] [,3]
[1,] 1 6 11
[2,] 2 7 12
, , 2
[,1] [,2] [,3]
[1,] 16 21 26
[2,] 17 22 27
, , 3
[,1] [,2] [,3]
[1,] 31 36 41
[2,] 32 37 42
I have find that I can solve this using aperm(array3D[1:2,,]) but I don't understand what is doing.
And the other problem is when I try to do an assignment, that I don't understand why this doesn't works
array3D[1:2,,]=matrix(9:1,3,3)
array3D[1,,]
[,1] [,2] [,3]
[1,] 9 3 6
[2,] 7 1 4
[3,] 5 8 2
I think that I can solve this with a loop or maybe with aaply as I read here, but I think that if I want to work with 3D arrays is really important to understand what is happening. If someone can point me to the right direction I will be really happy.
I have tried to find the answer here and reading http://adv-r.had.co.nz/ but so far no luck.
Update
I have found that everything works if instead of using the first index I use the last one, but I still doesn't understand why.
Is something inherent to R?
Is possible to use the first one in some other way?
array3D=array(1:45,c(3,3,5))
array3D[,,1:2]=matrix(9:1,3,3)
array3D[,,2]
[,1] [,2] [,3]
[1,] 9 6 3
[2,] 8 5 2
[3,] 7 4 1
I think it's not quite clear what you want to achieve, but here are some examples:
On your first point, you can select two of the three three-by-three matrices in the z-direction by doing:
array3D[,,1:2]
And accordingly, you can replace with an array of appropriate size:
array3D[,,1:2] <- array(18:1,c(3,3,2))
About your question on why you have to use the third index: Think about it like the z-direction in a 3D coordinate system. The rows would be the x-direction (vertical) and the columns the y-direction (horizontal). When indexing array3D[1:2,,] you selected the first two rows, while keeping everything in the x and z direction.

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