Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R use matrix to select row of multidimensional array

I have a multidimensional array, created in the following way:

my_array <- array(seq(12), dim=my_dims, dimnames=my_dimnames)

where "my_dims" is a numeric vector and "my_dimnames" is a list of character vectors, with lengths corresponding to the dimensions specified in "mydims", for example:

my_dims <- c(2, 3, 2)
my_dimnames <- list(c("D_11", "D_12"), c("D_21", "D_22", "D_23"), c("D_31", "D_32"))

So that "my_array" looks something like this:

, , D_31

     D_21 D_22 D_23
D_11    1    3    5
D_12    2    4    6

, , D_32

     D_21 D_22 D_23
D_11    7    9   11
D_12    8   10   12

Additionally, I have a character vector containing specific values of each dimension:

my_values <- c("D_11", "D_21", "D_32")

Now, from this question: R - how to get a value of a multi-dimensional array by a vector of indices I learned that I can read and write values from and to specific cells in "my_array" using matrix indexing, like this:

my_array[matrix(my_values, 1)]

to get the value "7" and

my_array[matrix(my_values, 1)] <- 1

to set that same cell to value "1"

What I don't understand, though, is how I can get all values from a specific dimension from "my_array", given specific values for all other dimensions using this method.

For example: how can I get a vector containing all values of the first dimension with fixed values "D_21" and "D_32" for the second and third dimension? So in this case what I try to extract would be a vector of the form:

c(7, 8)

How do I need to adjust the matrix indexing to achieve this result?

Thanks a lot in advance!

like image 342
scholt Avatar asked Jan 24 '26 19:01

scholt


1 Answers

I don't know if something like this already exists, but as mentioned in the comments, you can make use of the dimnames of your array.

It would be best if your "my_values" object were a list, as that would give you a lot of flexibility that you won't have with a vector.

Here's a possible approach. Create a function that creates a matrix that can be used to subset from your array. The function would essentially look something like this:

mat_maker <- function(array, vals) {
  x <- sapply(vals, is.null)
  vals[x] <- dimnames(array)[x]
  as.matrix(expand.grid(vals))
}

The extraction function would be like this. (Most likely, you would just roll both of these functions together, but I thought I would share them here separately so that you can see what is going on.)

array_extractor <- function(array, vals) {
  array[mat_maker(array, vals)]
}

Now, try the following examples out. Notice that the "vals" argument is a list, and that NULL is used for dimensions that are not being specified.

## All values where rowname == "D_11"
mat_maker(my_array, list("D_11", NULL, NULL))
#      Var1   Var2   Var3  
# [1,] "D_11" "D_21" "D_31"
# [2,] "D_11" "D_22" "D_31"
# [3,] "D_11" "D_23" "D_31"
# [4,] "D_11" "D_21" "D_32"
# [5,] "D_11" "D_22" "D_32"
# [6,] "D_11" "D_23" "D_32"
array_extractor(my_array, list("D_11", NULL, NULL))
# [1]  1  3  5  7  9 11


## All first column values from the second array object
## This is your specific example
mat_maker(my_array, list(NULL, "D_21", "D_32"))
#      Var1   Var2   Var3  
# [1,] "D_11" "D_21" "D_32"
# [2,] "D_12" "D_21" "D_32"
array_extractor(my_array, list(NULL, "D_21", "D_32"))
# [1] 7 8

## First two columns from all array dimensions
array_extractor(my_array, list(NULL, c("D_21", "D_22"), NULL))
# [1]  1  2  3  4  7  8  9 10

An extension of this function would be to put the dimensional attributes (including the names) back into the output. It could look something like this:

extractMe <- function(array, vals) {
  x <- sapply(vals, is.null)
  vals[x] <- dimnames(array)[x]
  temp <- as.matrix(expand.grid(vals))
  `dimnames<-`(`dim<-`(array[temp], lengths(vals)), vals)
}

Here's the usage:

extractMe(my_array, list("D_11", NULL, NULL))
# , , D_31
# 
#      D_21 D_22 D_23
# D_11    1    3    5
# 
# , , D_32
# 
#      D_21 D_22 D_23
# D_11    7    9   11

extractMe(my_array, list(NULL, "D_21", "D_32"))
# , , D_32
# 
#      D_21
# D_11    7
# D_12    8

extractMe(my_array, list(NULL, c("D_21", "D_22"), NULL))
# , , D_31
# 
#      D_21 D_22
# D_11    1    3
# D_12    2    4
# 
# , , D_32
# 
#      D_21 D_22
# D_11    7    9
# D_12    8   10

And, for cases where you want just a vector of the values, just wrap it with c:

c(extractMe(my_array, list(NULL, "D_21", "D_32")))
# [1] 7 8
like image 148
A5C1D2H2I1M1N2O1R2T1 Avatar answered Jan 26 '26 10:01

A5C1D2H2I1M1N2O1R2T1



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!