How to create lower dimensional matrix from higher dimensional array in R? - arrays

Suppose I have an array such that:
temp<-array(0, dim=c(100,10,4))
I can merge matrices 1 & 2 from the array into a single matrix using cbind:
temp.merge<-cbind(temp[,,1],temp[,,2])
Is there a way to merge all n matrices (in this case 4) into a single one without having to write out the position of each one as above?

If you have the array set up right in memory, you can just reset the dimensions and it will work.
dim(temp) <- c(100, 40)

If #Neal's answer works, definately use it.
This also works:
# generates 100 X 40 array
do.call("cbind",lapply(1:4,function(x){return(temp[,,x])}))
You would think that:
do.call("cbind",list(temp[,,1:4])) ## generates 4000 X 1 array
would work, but it does not...

Also:
as.matrix(as.data.frame(temp))
Example:
> temp <- array(1:8, dim=c(2,2,2))
> temp
#, , 1
#
# [,1] [,2]
#[1,] 1 3
#[2,] 2 4
#
#, , 2
#
# [,1] [,2]
#[1,] 5 7
#[2,] 6 8
as.matrix(as.data.frame(temp))
# V1 V2 V3 V4
#[1,] 1 3 5 7
#[2,] 2 4 6 8

Related

Indexing and subscripts for R arrays with variable dimensions

Suppose you have an n-dimensional, homogeneous data structure (array) in R with a variable but fixed number of dimensions:
n_dim <- 3
n_row <- 3
a <- array(seq(n_row ^ n_dim), dim = rep(n_row, n_dim))
a
>, , 1
>
> [,1] [,2] [,3]
>[1,] 1 4 7
>[2,] 2 5 8
>[3,] 3 6 9
>[..]
Is there a simple syntax to access a subscript of a given dimension, instead of counting the commas from n_dim or counting the position with 1-dim positions a[c(1,...)]? Is there any a[get row in dim] method that provides this already?
# Give me the 1st row of the "last" dimension
expr <- paste0("a[",
paste0(rep(", ", n_dim - 1), collapse = ""),
x,
"]")
expr
> [1] "a[, , 1]"
eval(parse(text = expr))
> [,1] [,2] [,3]
>[1,] 1 4 7
>[2,] 2 5 8
>[3,] 3 6 9
Thank you!
One option would be abind
library(abind)
asub(a, 1, n_dim)
# [,1] [,2] [,3]
#[1,] 1 4 7
#[2,] 2 5 8
#[3,] 3 6 9

How to bind columns in high dimensional arrays following a specific order?

I have two high dimensional arrays, both with 1000 rows, 3 columns, 10 slices and 4 groups of slices.
I want to bind them but matching the columns between them. Example below:
#dumb data
array1 <- array(1:4, dim = c(2,1,2,2),dimnames = list(NULL,"Ca",1:2,1:2)); array1
array2 <- array(5:8, dim = c(2,1,2,2),dimnames = list(NULL,"Cb",1:2,1:2)); array2
#desired result
cbind(array1[,,1,1],array2[,,1,1],array1[,,2,1],array2[,,2,1],
array1[,,1,2],array2[,,1,2],array1[,,2,2],array2[,,2,2])
the outcome is:
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 5 3 7 1 5 3 7
[2,] 2 6 4 8 2 6 4 8
Although column names do not show up, I have ordered manually the columns to be: First column of the first array, first column of the second array, second column of the first array, second column of the second array, and so on.
Is there a other way to do this than manually using cbind?
Thanks in advance!
Here is one way to accomplish this for the example, but might require some modification for the actual data set:
m1 <- cbind(array1, array2)
l1 <- lapply(seq_len(nrow(m1) / 2), function(x) m1[seq(2 * x - 1, 2 * x), ])
m2 <- do.call(cbind, l1)
> m2
array1 array2 array1 array2 array1 array2 array1 array2
[1,] 1 5 3 7 1 5 3 7
[2,] 2 6 4 8 2 6 4 8

Separate the matrices in the 3rd dim. of a 3D array in R

I have a list of 3D arrays which looks like this:
my.arrs <- list(array(1:5, c(5,4,2)),array(1:5, c(5,4,2)),array(1:5, c(5,4,2)));
my.arrs
What I wish to have is a new list with each matrix contained in my list of arrays separated (ideally it should look like this):
my.new.matrices (list of 6)
my.array[[1]][1]
my.array[[1]][2]
my.array[[2]][1]
my.array[[2]][2]
my.array[[3]][1]
my.array[[3]][2]
Before having this issue, I worked on something very similar. I had this as the result of a simulation I run in R:
> TBM
, , 1
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] 0.05151012 0.345498935 0.26056614 0.04567956 0.073153163 -0.070264403 0.158124924
, , 2
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] -0.65883235 -0.43591955 -0.116739746 -0.28835563 0.04351086 -0.03692388 0.60592379
, , 3
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] 0.2816988 0.3726166 0.4434252 0.4204302 0.2684518 0.454951339 0.64363895
And I wrote this for() loop:
TBM.vector3 <- list()
for(i in 1:dim(TBM)[3]) {
print(i)
TBM.vector3[[i]] <- as.vector(TBM[,,i])
}
TBM.vector3
which makes exactly what I want i.e., separate each matrix in the third dimension and store them in a list of vector. I want to automatize this process a list of array like my.arrs.
1) tapply Each of 3 arrays is made up of 2 5x4 matrices so create a long vector out of it all and then grab successive vectors of 5*4 components and turn them into a matrix of the desired shape:
tapply(unlist(my.arrs), gl(3*2, 5*4), matrix, 5)
or more generally:
dims <- dim(my.arrs[[1]]) # c(5, 4, 2)
tapply(unlist(my.arrs), gl(length(my.arrs) * dims[3], prod(dims[1:2])), matrix, dims[1])
2) sapply/lapply Another possibility (where dims is defined above):
c(sapply(my.arrs, function(x) lapply(1:dims[3], function(i) x[,,i])))
If I understand what you are asking for, here is one approach:
unlist(lapply(my.arrs, function(x) {
lapply(1:dim(x)[3], function(y) {
x[,,y]
})
}), recursive = FALSE)
#[[1]]
# [,1] [,2] [,3] [,4]
#[1,] 1 1 1 1
#[2,] 2 2 2 2
#[3,] 3 3 3 3
#[4,] 4 4 4 4
#[5,] 5 5 5 5
## ...
## ...
#[[6]]
# [,1] [,2] [,3] [,4]
#[1,] 11 11 11 11
#[2,] 12 12 12 12
#[3,] 13 13 13 13
#[4,] 14 14 14 14
#[5,] 15 15 15 15
The outer lapply iterates over each array
The inner lapply iterates over each slice (3rd dimension) of each array, so that 2 is not hardcoded into the function
Calling unlist with recursive = FALSE (which is not the default behavior) expands the lapply(lapply(...)) result from a length 3 list of length 2 lists into a single length 6 list.
Data:
my.arrs <- list(
array(1:5, c(5,4,2)),
array(6:10, c(5,4,2)),
array(11:15, c(5,4,2))
)
Thank you #G. Grothendieck and #nrussell for your answers,
I was also working on my one meanwhile, had simular results with unlist() and found what is my actual problem.
The output of the simulation I run for n <- 2, gives a list of this format (later I want to make it run for a larger data set and 100 of realizations, so let's start small):
TBM List of 3
tbm1: num [1:29, 1:28, 1:2] ...
tbm2: num [1:29, 1:28, 1:2] ...
tbm3: num [1:29, 1:28, 1:2] ...
... being my output data.
Because I will have a large data set and n <- 100, I can not unlist manually. Thus I wrote this:
TBM.n <- rep(list(matrix(nrow=29, ncol=28)),6)
for(j in 1:length(TBM)){
for(jj in 1:dim(TBM[[i]])[3]){
print(jj)
print(unlist(TBM[[j]][,,jj]))
TBM.n[[j]] <- unlist(TBM[[j]][,,jj])
}
}
print(jj) gives:
1
2
1
2
1
2
print(unlist(TBM[[j]][,,jj])) gives my data split as I want.
And there here come my actual problem, the storage. When I write:
TBM.n[[j]] <- unlist(TBM[[j]][,,jj])
or
TBM.n[[jj]] <- unlist(TBM[[j]][,,jj])
I got the data stored for tbm1[,,2], tbm2[,,2], tbm3[,,2] and tbm2[,,2], tbm3[,,2] repectively.
Until now I did not find a solution for storing the whole 6 matrices. I have the feeling it is an indexing problem, still trying, not solving.
Do you have any suggestions ?
Thank you Marion H
EDIT
Here is my final code I adapted from #nrussel:
TBM.n <- list()
for (i3 in 1){ #in length(TBM)
TBM.n[[i3]] <- unlist(lapply(TBM, function(x){
lapply(1:dim(x)[3], function(y){
x[,,y]
})
}), recursive = FALSE
)
}
The output gives me the desired results:
TBM.n List of 1
:List of 6
..$ tbm11: num[1:29, 1:28] ...
..$ tbm12: num[1:29, 1:28] ...
..$ tbm21: num[1:29, 1:28] ...
..$ tbm22: num[1:29, 1:28] ...
..$ tbm31: num[1:29, 1:28] ...
..$ tbm32: num[1:29, 1:28] ...
Again thank you for your help !

Converting a complicated list of matrices into an array of matrices

I would like to convert a list of matrices into an array of stapled matrices. My list looks like l3 in:
getme<-matrix(1,3,3)
getme2<-matrix(2,4,4)
l1<-list(getme,getme2)
names(l1)<-c('getme','getme2')
getme<-matrix(3,3,3)
getme2<-matrix(4,4,4)
l2<-list(getme,getme2)
names(l2)<-c('getme','getme2')
l3<-list(l1,l2)
The goal is to append each conformable matrix into an array. The name of the array/variable should be equal to the name of the level of the list.
So for example:
getme<-array(dim=c(3,3,2))
m=2
for(i in 1:m){getme[,,i]<-l3[[i]]$getme}
Since my lists get vary large in terms of both mand number of getmematrices, I need to automatize this procedure across all m levels of the list l3. Ideally I would want code that produces j arrays getme, getme2,...getme_j, where only l3is used as an input. That is the names of the variable levels, names(l3[[1]]), are applied on the way.
The combination of matrices into arrays is easy with abind from the abind package:
library(abind)
res <- lapply(seq_along(l3[[1]]), function(x)
abind(lapply(l3, "[[", x), along = 3))
The outer lapply function is used to apply a function to the numbers form 1 to the length of the list l3. The current number is represented by parameter x. The other lapply command is used to extract the xth element from the list l3. These elements are combined into an array with abind. Since the length of l3 is 2, the outer lapply returns a list of length 2.
This returns a list of arrays:
[[1]]
, , 1
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 1 1 1
[3,] 1 1 1
, , 2
[,1] [,2] [,3]
[1,] 3 3 3
[2,] 3 3 3
[3,] 3 3 3
[[2]]
, , 1
[,1] [,2] [,3] [,4]
[1,] 2 2 2 2
[2,] 2 2 2 2
[3,] 2 2 2 2
[4,] 2 2 2 2
, , 2
[,1] [,2] [,3] [,4]
[1,] 4 4 4 4
[2,] 4 4 4 4
[3,] 4 4 4 4
[4,] 4 4 4 4
You can use the original names with
names(res) <- names(l3[[1]])

Extract the anti-diagonals from an array

I want to extract the anti-diagonals of an array
m=array(1:18,c(3,3,2))
My best shot
k=dim(m)[3]
mn=matrix(nrow = k, ncol = 3)
for (i in 1:k){
mn=diag(m[,,i][3:1,1:3])
}
This returns 12 14 16, the anti-diagonal of the second matrix in the array. I want to achieve this
[1] 3 5 7
[2] 12 14 16
I want the “anti-diags” as arrays
Manually diag(m[,,1][3:1,1:3]) and diag(m[,,2][3:1,1:3]) works fine, but the array I’m working with is dim(c(3,3,22)), so I thought "loop!"
MQ: How to extract the anti-diagonals from an array using the loop? (better and elegant solutions are more than welcome)
This should work:
mn <- array(NA, dim=dim(m))
for (i in 1:dim(m)[3]){
mn[,,i]=diag(m[,,i][cbind(3:1,1:3)])
}
It was unclear whether you want the "anti-diag" to become the new diag, but that is what your code suggested as the intent. The form matrix[cbind(vec1,vec2)] pulls the (R,C) referenced elements from the matrix.
If you do not want them as arrays then this is an alternate result:
mn <- array(NA, dim=c(2,3))
for (i in 1:dim(m)[3]){
mn[i,]=m[,,i][cbind(3:1,1:3)]
}
mn
[,1] [,2] [,3]
[1,] 3 5 7
[2,] 12 14 16
This is a loopless way of getting the same values:
m[cbind( rep(3:1,2), rep(1:3,2), rep(1:2,each=3)) ]
[1] 3 5 7 12 14 16
You could use lapply across the third dimension and extract the anti-diagonal by first rotating the matrix ( see this great answer ) by reversing the column order and taking the diagonal of that. Basically like this...
out <- lapply( 1:dim(m)[3] , function(x) diag( t( apply( m[,,x] , 2 , rev ) ) ) )
[[1]]
[1] 3 5 7
[[2]]
[1] 12 14 16
If you need them glued together as an array then use do.call...
do.call( rbind , out )
[,1] [,2] [,3]
[1,] 3 5 7
[2,] 12 14 16
In this particular case, a for loop will be much quicker (benchmark it) and you should use #DWin's answer.
It occurs to me that we can simplfy this a bit and avoid using lists and bad use of lapply (by assuming thatm is available outside the scope of lapply) because we can also simply apply across the third dimension of your matrices. So we can apply once to rotate the matrices, then take the diag of each rotated matrix like so...
rotM <- apply( m , 2:3 , rev )
out <- t( apply( rotM , 3 , diag ) )
[,1] [,2] [,3]
[1,] 3 5 7
[2,] 12 14 16

Resources