How do I smartly subset an array in R with dynamic dimensions? - arrays

I'm crafting a simulation model, and I think this problem has an easy fix, but I'm just not that used to working with arrays. Let's say I have an array, Array1, that has 3 dimensions. The first two are of constant and equal length, L, but the third dimension can be of length from 1 to X at any given time.
I want to be able to periodically subset Array1 to create a second array, Array2, that is composed of up to the last Y "sheets" of Array1. In other words, if the length of the third dimension of Array1 is greater than Y, then I want just the last Y sheets of Array1 but, if it's less than Y, I want all sheets of Array1.
I know that I can crudely pull this off using the tail function and a little finagling:
tmp1 = tail(Array1, (L*L*Y))
Array2 = array(tmp1, dim = (L, L, (L*L/length(tmp1))))
But it seems like there could be a more elegant way of doing this. Is there an equivalent of tail for arrays in R? Or is there a way that Array2 could be produced via simple logical indexing of Array1? Or perhaps the apply function could be used somehow?

Were you after something like this?
a <- array(1:(3*4*5), dim=c(3,4,5))
x <- dim(a)[3]
y <- 2
a[, , seq(to=x, len=min(x, y))]
, , 1
[,1] [,2] [,3] [,4]
[1,] 37 40 43 46
[2,] 38 41 44 47
[3,] 39 42 45 48
, , 2
[,1] [,2] [,3] [,4]
[1,] 49 52 55 58
[2,] 50 53 56 59
[3,] 51 54 57 60

Related

multi-dimensional array from another matrix

Suppose
t=c(0,0.5,0.7,0.9,1,1.2) and
v=matrix(1:40, nrow=5, ncol=8)
v
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 6 11 16 21 26 31 36
[2,] 2 7 12 17 22 27 32 37
[3,] 3 8 13 18 23 28 33 38
[4,] 4 9 14 19 24 29 34 39
[5,] 5 10 15 20 25 30 35 40
I would like to make an array of order 5x6x4.
array <- array(NA, dim = c(5, 6, 4))
5 is the number of rows, 6 is the length of t and 4 is the number of arrays. to create the first array, I would like to consider only the first two columns of v, and for each time point, the first element of the first matrix is filled by v[1,1]+v[1,2]*t[] which is the value of the first element of the first matrix of the first array which is the value of array[1,1,1]
, similarly, array[2,1,1]e v[2,1]+v[2,2]*t[1]
For the second array consider only 3rd and 4th column of v. For the third array consider only 5th and 6th column of v, and Finally, for the fourth array, consider the last two columns of v.
I would appreciate if anyone can help me using a for loop or alternative ways?
Thanks
Try these nested loops:
ary <- array(NA, dim = c(5, 6, 4))
for (i in 1:5) {
for (j in 1:6) {
for (k in 1:4) {
ary[i, j, k] <- v[i, k * 2 - 1] + v[i, k * 2] * t[j]
}
}
}

Create an array from a list with different number of outputs for each value

I am trying to create an array out of a list with different numbers of outputs for each value that I obtained from a function.
This is the code I am using:
list_i1 = sapply(implicit$image_1_id, num, simplify = 'array')
And these are the outputs.
> list_i1[[1]]
[1] 86 101
> list_i1[[2]]
[1] 35 61 112
> list_i1[[3]]
[1] 10 15
Due to the fact that some of the values have more 2 output numbers whereas some have 3, I am unable to create an array from the following list. Ideally, I would like to have a zero in the slot that isn't filled by a third output within the array so as to look like this:
1 86 35 10
2 101 61 15
3 0 112 0
I came up with a very similar solution to #Fernandes, using tips from here and here
Recreate your example:
lst <- list(c(86, 101), c(35, 61, 112), c(10, 15))
# [[1]]
# [1] 86 101
#
# [[2]]
# [1] 35 61 112
#
# [[3]]
# [1] 10 15
Figure out the number of rows needed, and then extend each of the vectors to that length:
num_row <- max(sapply(lst, length))
for (i in seq_along(lst)) {
length(lst[[i]]) <- num_row
}
# [[1]]
# [1] 86 101 NA
#
# [[2]]
# [1] 35 61 112
#
# [[3]]
# [1] 10 15 NA
Column bind all the now-equal-length-vectors together into a matrix:
m <- sapply(lst, cbind)
# [,1] [,2] [,3]
# [1,] 86 35 10
# [2,] 101 61 15
# [3,] NA 112 NA
Replace all the NA's with the desired 0's:
m[is.na(m)] <- 0
# [,1] [,2] [,3]
# [1,] 86 35 10
# [2,] 101 61 15
# [3,] 0 112 0
I really wanted to replace the for loop with with some kind of 'apply', but couldn't figure it out. If anyone knows how to not use the for loop, I'd like to see it!
a = c(86, 101)
b = c(35, 61, 112)
c = c(10, 15)
list_i1 = list(a, b, c)
n = max(length(list_i1[[1]]),
length(list_i1[[2]]),
length(list_i1[[3]]))
length(list_i1[[1]]) = n
length(list_i1[[2]]) = n
length(list_i1[[3]]) = n
x = cbind(list_i1[[1]], list_i1[[2]], list_i1[[3]])
x[is.na(x)] = 0
x
# [,1] [,2] [,3]
#[1,] 86 35 10
#[2,] 101 61 15
#[3,] 0 112 0

Indexing a matrix by column/row when it might become length 1 [duplicate]

> a<-matrix(c(1:9),3,3)
> a
[,1] [,2] [,3]
[1,] 1 4 7
[2,] 2 5 8
[3,] 3 6 9
> a[3,]*a[,3] # I expect 1x1 matrix as result of this.
[1] 21 48 81
> class(a)
[1] "matrix"
> class(a[3,])
[1] "integer"
In R, 1-dimensional matrix is changed to a vector. Can I avoid this?
I would like to keep 1-D matrix as a matrix. Actually, I need to throw many kind of matrix to RcppArmadillo, even zero-D matrix. Changing matrix to vector by itself is my problem.
This is an R FAQ. You need to do a[3,,drop = FALSE].
You're confusing element-by-element multiplication and matrix multiplication (see ?"*"). You want %*%:
> a[3,]%*%a[,3]
[,1]
[1,] 150

R - Indexing Array using Array

Lets assume I have an array of dim(x) <- c(3,3,3). I also have a df or matrix with two** columns containing index combinations that I need.
When I pass x[df[[1]],df[[2]],] I get a VERY large array which I then need to go through and take the diagonal of using the apply function. This is very memory and time inefficient. Is there some sort of shortcut (without using for loops) to index an array so that it would return the vector of values that the df asks for.
Trivial Example:
`a <- array(1:27,dim = c(3,3,3))
df <- data.frame(c(1,2,2,1,3,2),c(2,3,2,1,3,2))`
In this example, I would want to pass something like "a[df[[1]],df[[2]],]"
and get something like this (or transposed):
. [,1] [,2] [,3] [,4] [,5] [,6]
[1,] 4 8 5 1 9 5
[2,] 13 17 14 10 18 14
[3,] 22 26 23 19 27 23
When I pass that function now, I get a 3-d array of dim = c(6,6,3) as apposed to the more helpful dim = c(6,3). I can easily take apply(result, 3,diag) to get what I want, but when df>>6 it takes up a lot of space (like 750GB of space and throws warnings, errors and stops execution before beginning)
This works
temp <- array(1:27, dim=c(3,3,3))
df <- data.frame(a=c(1,2,3), b=c(1,2,3), c=c(1,2,3))
temp[cbind(df[[1]], df[[2]], df[[3]])]
[1] 1 14 27
This is sometimes referred to as matrix indexing.
To query by two of the dimensions and leave the third one open, you might just use the regular matrix subsetting: For example, to select the the first and second row and second column for each of the "z" dimension matrices, you could use something like temp[1:2, 2,] or from your dataset:
temp[1:2, 2,]
[,1] [,2] [,3]
[1,] 4 13 22
[2,] 5 14 23
temp[df[[1]][1:2], df[[2]][2], ]
[,1] [,2] [,3]
[1,] 4 13 22
[2,] 5 14 23
Which are of course identical.

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.

Resources