如何用m *(n-i)维矩阵切割n维数组?

时间:2015-08-10 17:24:39

标签: r slice

如果我有一个名词的二维阵列可以通过一米切片 * 名词的矩阵这样的

a <- array(1:27,c(3,3,3))

b <- matrix(rep(1:3,3),3)

# This will return the index a[1,1,1] a[2,2,2] and a[3,3,3]
a[b]

# Output
[1]  1 14 27

是否有任何“有效且简单”的方法来做一个类似的切片,但保持一些尺寸免费? 这是一个带有 m * (n-i)维数组的n维数组和 得到 i + 1 维数组作为结果。

a <- array(1:27,c(3,3,3))

b <- matrix(rep(1:2,2),2)

# This will return a vector of the index a[1] a[2] a[1] and a[2]
a[b]

# Output
[1] 1 2 1 2


# This will return the indexes of the cartesian product between the vectors,
# that is a array consisting of a[1,,1] a[1,,2] a[2,,1] and a[2,,2]
a[c(1,2),,c(1,2)]

# Output
, , 1

     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8

, , 2

     [,1] [,2] [,3]
[1,]   10   13   16
[2,]   11   14   17

如果最后一个命令返回一个数组,则应该是所需的结果 用[1,,1]和[2,,2]。 现在我用for循环和abind解决了这个问题,但我确信必须有更好的方法。

# Desired functionality
a <- array(1:27,c(3,3,3))
b <- array(c(c(1,2),c(1,2)),c(2,2))
sliceem(a,b,freeDimension=2)

# Desired output (In this case rbind(a[1,,1],a[2,,2]) ) 
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]   11   14   17

1 个答案:

答案 0 :(得分:3)

我认为这是最干净的方法 - 制作一个单独的功能:

slicem <- function(a,idx,drop=FALSE) do.call(`[`,c(list(a),idx,list(drop=drop)))

# usage for OP's example
a      <- array(1:27, c(3,3,3))    
idx    <- list(1:2, TRUE, 1:2)
slicem(a,idx)

给出了

, , 1

     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8

, , 2

     [,1] [,2] [,3]
[1,]   10   13   16
[2,]   11   14   17

您必须为未选择的每个维度编写TRUE

遵循OP的新期望......

library(abind)
nistfun <- function(a,list_o_idx,drop=FALSE){
  lens <- lengths(list_o_idx)
  do.call(abind, lapply(seq.int(max(lens)), function(i)
    slicem(a, mapply(`[`, list_o_idx, pmin(lens,i), SIMPLIFY=FALSE), drop=drop)
  ))
}

# usage for OP's new example
nistfun(a, idx)

# , , 1
# 
#      [,1] [,2] [,3]
# [1,]    1    4    7
# 
# , , 2
# 
#      [,1] [,2] [,3]
# [1,]   11   14   17

现在,任何非TRUE索引必须具有相同的长度,因为它们将匹配。

此处使用

abind而不是rbind(请参阅此答案的早期编辑),因为这是考虑切片数组的唯一明智的一般方法。如果你真的想要删除维度,那么它应该被删除以及如何删除它是非常模糊的,所以单独返回向量:

nistfun(a, idx, drop=TRUE)
# [1]  1  4  7 11 14 17

如果你想把它扔回某种数组中,你可以在事后:

matrix( nistfun(a, idx), max(lengths(idx)), dim(a)[sapply(idx,isTRUE)]), byrow=TRUE)

#      [,1] [,2] [,3]
# [1,]    1    4    7
# [2,]   11   14   17