【问题标题】:Select along one of n dimensions in array沿数组中的 n 个维度之一选择
【发布时间】:2013-01-08 04:06:54
【问题描述】:

我在 R 中有一个数组,由这样的函数创建:

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

我想选择一维,所以对于上面的例子,我会:

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

如果我事先不知道我的数组可能有多少维(除了我想要选择的命名维),有没有一种方法可以概括?我想编写一个函数,该函数接受可能格式化为上述 A 的输入,或者:

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

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

背景

一般背景是我正在研究 ODE 模型,因此对于 deSolve 的 ODE 函数,它必须采用具有我当前状态的单个命名向量。对于其他一些函数,比如计算相平面/方向场,有一个更高维的数组来应用微分方程会更实用,而且我想避免拥有相同函数的多个副本,只是使用不同的我要选择的维度后的逗号数。

【问题讨论】:

    标签: r multidimensional-array


    【解决方案1】:

    我花了很多时间为 plyr 找出最快的方法,而我能想到的最好方法是手动构建对 [ 的调用:

    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)
    }
    

    (您可以在https://github.com/hadley/devtools/wiki/Computing-on-the-language 找到有关此技术的更多信息)

    然后您可以按如下方式使用它:

    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)
    

    如果您想基于多个维度进行提取,它也会以简单的方式进行概括,但您需要重新考虑函数的参数。

    【讨论】:

    • 也很不错。所以我假设A["x",,]A["x",1:4,1:4] 快,对吗?
    • @flodel IIRC,是的(尤其是当数组变大时)。你也可以做A["x", T, T]
    • @flodel microbenchmark(A["x", ,], A["x", 1:4, 1:4], A["x", T, T]) - 内容不多,但我可能很在意,因为*aply 可能会调用它数百万次。
    • 所有好的解决方案,这个通过对我的数据进行一些基准测试而获胜,并且得到了很好的评论。谢谢!
    • 对我的情况来说不是绝对必要的,但是否有可能更早地提取索引?这似乎在以后会非常有用。所以我也许可以调用:A[index_array(A,1,'x')] &lt;- 2 来设置值。我希望这能解释我想要什么......
    【解决方案2】:

    我写了这个通用函数。不一定超快,但对于arrayInd 和矩阵索引来说是一个不错的应用:

    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])
    
    }
    

    例子:

    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】:

      也许有一个更简单的方法,但这是可行的:

      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
      

      我们把它概括为一个可以从任意维度提取的函数,不一定是第一个:

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

      例子:

      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】:

        abind 包有一个函数 asub,除了其他非常有用的数组操作函数之外,还可以执行此操作:

        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)
        

        并且它允许在多个维度上建立索引:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-12-18
          • 1970-01-01
          • 1970-01-01
          • 2015-02-01
          • 2013-04-13
          • 2019-05-08
          相关资源
          最近更新 更多