简体   繁体   中英

Subset an array using a vector of indices

How can I subset an array using a vector of indices? This may be easier to show by an example.

# I have this array
bn <- structure(c(0.8, 0.09, 0.11, 0.09, 0.8, 0.11, 0.11, 0.11, 0.78, 
0.18, 0.13, 0.69, 0.88, 0.07, 0.05, 0.25, 0.49, 0.26, 0.43, 0.2, 
0.37, 0.34, 0.39, 0.27, 0.13, 0.44, 0.42), class = "table", .Dim = c(3L, 
3L, 3L), .Dimnames = structure(list(D = c("a", "b", "c"), A = c("a", 
"b", "c"), C = c("a", "b", "c")), .Names = c("D", "A", "C")))    

# and matrix of indices (correspond to dimensions of bn)
input <- structure(c("a", "b", NA), .Dim = c(1L, 3L), 
                   .Dimnames = list(NULL, c("A", "C", "D")))

I can subset bn by directly indexing to give the result

bn[, input[,"A"], input[,"C"]]
#    a    b    c 
# 0.18 0.13 0.69 

How can I do this without decomposing it like this (while I won't know before hand the dimension of the array, it will be the number of inputs + 1). Based on r-subset-array-using-vector (although that question is for a list not an array), I tried

bn[, input[,c("A","C")]]
bn[, input[,c("A","C"), drop=FALSE]]

which give Error in [.default (bn, input[, c("A", "C"), drop = FALSE], ) :
incorrect number of dimensions

This works , but will involve too much time being spent on coercing and constructing indices.

library(R.utils)
x = array(bn, dim=dim(bn), dimnames=dimnames(bn))
extract(x, indices=list("2"=1, "3"=2))

I could also melt the data and then pull out the relevant rows, and there is also this question subset-an-array-for-the-pairs-of-indices-in-r ] but the solution presupposes the dimensions of the array.

Is there a succinct way to do this by subsetting the array ?


An another option:

library(gRbase)
inp = input[,c("A", "C"), drop=FALSE]
ar_slice(bn, split(inp, colnames(inp)))

But it would be nice without the work of split

or taking a lead from r2evans

ar_slice(bn, setNames(as.list(inp), colnames(inp)))

One method, though it doesn't really look that pretty.

do.call(`[`, c(list(bn), list(TRUE), as.list(input[,c("A","C")])))
#    a    b    c 
# 0.18 0.13 0.69 

I'll trace how I came up with that.

  1. Initially, we want just bn[,"a","b"] . Realize that this is identical to db[TRUE,"a","b"] .
  2. Translate the [ to a function, ala `[<-`(bn, TRUE, "a", "b") .
  3. Knowing that you want to generate the argument list dynamically, I instantly think of do.call , so we need to know how to create (bn, TRUE, "a", "b") programmatically. The last part is:

     as.list(input[,c("A","C")]) # $A # [1] "a" # $C # [1] "b" 

    so we can create the whole slew of arguments by prepending list -ified bn and TRUE :

     str( c(list(bn), list(TRUE), as.list(input[,c("A","C")])) ) # List of 4 # $ : 'table' num [1:3, 1:3, 1:3] 0.8 0.09 0.11 0.09 0.8 0.11 0.11 0.11 0.78 0.18 ... # ..- attr(*, "dimnames")=List of 3 # .. ..$ D: chr [1:3] "a" "b" "c" # .. ..$ A: chr [1:3] "a" "b" "c" # .. ..$ C: chr [1:3] "a" "b" "c" # $ : logi TRUE # $ A: chr "a" # $ C: chr "b" 

This is assuming that your first axis is always "full" ( TRUE ). If you need to determine that dynamically, just know that the 2nd-and-beyond elements of the list within do.call are your axes, determine them as you deem necessary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM