Select along one of n dimensions in array

て烟熏妆下的殇ゞ 提交于 2019-12-28 05:54:11

问题


I have an array in R, created by a function like this:

A <- array(data=NA, dim=c(2,4,4), dimnames=list(c("x","y"),NULL,NULL))

And I would like to select along one dimension, so for the example above I would have:

A["x",,]
dim(A["x",,])    #[1] 4 4

Is there a way to generalize if I do not know in advance how many dimensions (in addition to the named one I want to select by) my array might have? I would like to write a function that takes input that might formatted as A above, or as:

B <- c(1,2)
names(B) <- c("x", "y")

C <- matrix(1, 2, 2, dimnames=list(c("x","y"),NULL))

Background

The general background is that I am working on an ODE model, so for deSolve's ODE function it must take a single named vector with my current state. For some other functions, like calculating phase-planes/direction fields, it would be more practical to have a higher-dimensional array to apply the differential equation to, and I would like to avoid having many copies of the same function, simply with different numbers of commas after the dimension I want to select.


回答1:


I spent quite a lot of time figuring out the fastest way to do this for plyr, and the best I could come up with was manually constructing the call to [:

index_array <- function(x, dim, value, drop = FALSE) { 
  # Create list representing arguments supplied to [
  # bquote() creates an object corresponding to a missing argument
  indices <- rep(list(bquote()), length(dim(x)))
  indices[[dim]] <- value

  # Generate the call to [
  call <- as.call(c(
    list(as.name("["), quote(x)),
    indices,
    list(drop = drop)))
  # Print it, just to make it easier to see what's going on
  print(call)

  # Finally, evaluate it
  eval(call)
}

(You can find more information about this technique at https://github.com/hadley/devtools/wiki/Computing-on-the-language)

You can then use it as follows:

A <- array(data=NA, dim=c(2,4,4), dimnames=list(c("x","y"),NULL,NULL))
index_array(A, 2, 2)
index_array(A, 2, 2, drop = TRUE)
index_array(A, 3, 2, drop = TRUE)

It would also generalise in a straightforward way if you want to extract based on more than one dimension, but you'd need to rethink the arguments to the function.




回答2:


I wrote this general function. Not necessarily super fast but a nice application for arrayInd and matrix indexing:

extract <- function(A, .dim, .value) {

    val.idx  <- match(.value, dimnames(A)[[.dim]])
    all.idx  <- arrayInd(seq_along(A), dim(A))
    keep.idx <- all.idx[all.idx[, .dim] == val.idx, , drop = FALSE]
    array(A[keep.idx], dim = dim(A)[-.dim], dimnames = dimnames(A)[-.dim])

}

Example:

A <- array(data=1:32, dim=c(2,4,4),
           dimnames=list(c("x","y"), LETTERS[1:4], letters[1:4]))

extract(A, 1, "x")
extract(A, 2, "D")
extract(A, 3, "b")



回答3:


Perhaps there is an easier way, but this works:

do.call("[",c(list(A,"x"),lapply(dim(A)[-1],seq)))
     [,1] [,2] [,3] [,4]
[1,]   NA   NA   NA   NA
[2,]   NA   NA   NA   NA
[3,]   NA   NA   NA   NA
[4,]   NA   NA   NA   NA

Let's generalize it into a function that can extract from any dimension, not necessarily the first one:

extract <- function(A, .dim, .value) {
    idx.list <- lapply(dim(A), seq_len)
    idx.list[[.dim]] <- .value
    do.call(`[`, c(list(A), idx.list))
}

Example:

A <- array(data=1:32, dim=c(2,4,4),
           dimnames=list(c("x","y"), LETTERS[1:4], letters[1:4]))

extract(A, 1, "x")
extract(A, 2, "D")
extract(A, 3, "b")



回答4:


The abind package has a function, asub, to do this in addition to other very useful array manipulation functions:

library(abind)
A <- array(data=1:32, dim=c(2,4,4),
           dimnames=list(c("x","y"), LETTERS[1:4], letters[1:4]))

asub(A, 'x', 1)
asub(A, 'D', 2)
asub(A, 'b', 3)

And it allows indexing in multiple dimensions:

asub(A, list('x', c('C', 'D')), c(1,2))


来源:https://stackoverflow.com/questions/14500707/select-along-one-of-n-dimensions-in-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!