我希望能够为子集化构建do.call
公式,而无需识别输入数组中每个维度的实际范围。
我遇到的问题是我无法弄清楚如何模仿直接函数x[,,1:n,]
,其他维度中没有条目意味着“抓住所有元素”。
这是一些失败的示例代码。据我所知,[
或do.call
将NULL
列表值替换为1
索引。
x<-array(1:6,c(2,3))
dimlist<-vector('list', length(dim(x)))
shortdim<-2
dimlist[[shortdim]] <- 1: (dim(x)[shortdim] -1)
flipped <- do.call(`[`,c(list(x),dimlist))
我想我可以通过为-2*max(dim(x))
的每个元素分配值dimlist
来克服解决方案,但是很糟糕。
(FWIW,我有替代功能,通过melt/recast
或可怕的“构建字符串然后eval(parse(mystring))
完成所需的工作,但我想做得更好”。)
编辑:顺便说一句,我对使用melt & acast
的函数运行了此代码的一个版本(相当于DWin的TRUE设置);后者慢了好几倍,没有真正意外。
答案 0 :(得分:14)
经过一番探讨,alist
似乎可以解决问题:
x <- matrix(1:6, nrow=3)
x
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
# 1st row
do.call(`[`, alist(x, 1, ))
[1] 1 4
# 2nd column
do.call(`[`, alist(x, , 2))
[1] 4 5 6
来自?alist
:
'alist'处理其参数,就好像它们描述了函数一样 参数。因此,不评估值和标记参数 允许没有值,而'list'只是忽略它们。 'alist'最常用于'formals'。
<小时/> 一种动态选择提取哪个维度的方法。要创建所需长度的初始
alist
,请参阅here(Hadley,使用bquote
)或here(使用alist
)。
m <- array(1:24, c(2,3,4))
ndims <- 3
a <- rep(alist(,)[1], ndims)
for(i in seq_len(ndims))
{
slice <- a
slice[[i]] <- 1
print(do.call(`[`, c(list(m), slice)))
}
[,1] [,2] [,3] [,4]
[1,] 1 7 13 19
[2,] 3 9 15 21
[3,] 5 11 17 23
[,1] [,2] [,3] [,4]
[1,] 1 7 13 19
[2,] 2 8 14 20
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
答案 1 :(得分:11)
在这个例子中,我总是使用TRUE
作为占位符:
> x
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
> do.call("[", list(x, TRUE,1))
[1] 1 2
让我们使用一个更复杂的x
示例:x <- array(1:36, c(2,9,2)
,然后如果希望在下标列表中替换向量,将会恢复所有第一维和第二维以及仅第三维的第二个“切片”:
shortdim <- 3
short.idx <- 2
dlist <- rep(TRUE, length(dim(x)) )
dlist <- as.list(rep(TRUE, length(dim(x)) ))
> dlist
[[1]]
[1] TRUE
[[2]]
[1] TRUE
[[3]]
[1] TRUE
> dlist[shortdim] <- 2
> do.call("[", c(list(x), dlist) )
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,] 19 21 23 25 27 29 31 33 35
[2,] 20 22 24 26 28 30 32 34 36
有时候有用的另一点是逻辑索引被回收,因此你可以使用c(TRUE,FALSE)来挑选其他所有项目:
(x<-array(1:36, c(2,9,2)))
, , 1
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,] 1 3 5 7 9 11 13 15 17
[2,] 2 4 6 8 10 12 14 16 18
, , 2
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,] 19 21 23 25 27 29 31 33 35
[2,] 20 22 24 26 28 30 32 34 36
> x[TRUE,c(TRUE,FALSE), TRUE]
, , 1
[,1] [,2] [,3] [,4] [,5]
[1,] 1 5 9 13 17
[2,] 2 6 10 14 18
, , 2
[,1] [,2] [,3] [,4] [,5]
[1,] 19 23 27 31 35
[2,] 20 24 28 32 36
每种其他项目的进一步变化都是可能的。尝试使用c(FALSE,FALSE,TRUE)来获取以第3项开头的每个第三项。
答案 2 :(得分:9)
不是一个直接的答案,但我会演示asub
作为替代方案,因为我很确定这是OP最终会追求的。
library(abind)
提取第一行:
asub(x, idx = list(1), dims = 1)
提取第二和第三列:
asub(x, idx = list(2:3), dims = 2)
删除尺寸shortdim
中的最后一项,如OP所希望的那样:
asub(x, idx = list(1:(dim(x)[shortdim]-1)), dims = shortdim)
您也可以使用否定索引,这样也可以使用:
asub(x, idx = list(-dim(x)[shortdim]), dims = shortdim)
最后,我会提到该函数有一个drop
选项,就像[
一样。
答案 3 :(得分:1)
好的,这是四个版本的代码,后跟microbenchmark
。对于所有这些,速度似乎几乎相同。我想检查所有答案是否被接受,但由于我不能,这里是使用的chintzy标准:
DWin丢失是因为您必须为占位符输入“TRUE”
flodel丢失,因为它需要一个非基础库
当然,由于eval(parse())
,我原来输了。所以Hong Ooi获胜。他前进到下一轮谁想要成为一个切碎的偶像: - )
flip1<-function(x,flipdim=1) {
if (flipdim > length(dim(x))) stop("Dimension selected exceeds dim of input")
a <-"x["
b<-paste("dim(x)[",flipdim,"]:1",collapse="")
d <-"]"
#now the trick: get the right number of commas
lead<-paste(rep(',',(flipdim-1)),collapse="")
follow <-paste(rep(',',(length(dim(x))-flipdim)),collapse="")
thestr<-paste(a,lead,b,follow,d,collapse="")
flipped<-eval(parse(text=thestr))
return(invisible(flipped))
}
flip2<-function(x,flipdim=1) {
if (flipdim > length(dim(x))) stop("Dimension selected exceeds dim of input")
dimlist<-vector('list', length(dim(x)) )
dimlist[]<-TRUE #placeholder to make do.call happy
dimlist[[flipdim]] <- dim(x)[flipdim]:1
flipped <- do.call(`[`,c(list(x),dimlist) )
return(invisible(flipped))
}
# and another...
flip3 <- function(x,flipdim=1) {
if (flipdim > length(dim(x))) stop("Dimension selected exceeds dim of input")
flipped <- asub(x, idx = list(dim(x)[flipdim]:1), dims = flipdim)
return(invisible(flipped))
}
#and finally,
flip4 <- function(x,flipdim=1) {
if (flipdim > length(dim(x))) stop("Dimension selected exceeds dim of input")
dimlist <- rep(list(bquote()), length(dim(x)))
dimlist[[flipdim]] <- dim(x)[flipdim]:1
flipped<- do.call(`[`, c(list(x), dimlist))
return(invisible(flipped))
}
Rgames> foo<-array(1:1e6,c(100,100,100))
Rgames> microbenchmark(flip1(foo),flip2(foo),flip3(foo),flip4(foo)
Unit: milliseconds
expr min lq median uq max neval
flip1(foo) 18.40221 18.47759 18.55974 18.67384 35.65597 100
flip2(foo) 21.32266 21.53074 21.76426 31.56631 76.87494 100
flip3(foo) 18.13689 18.18972 18.22697 18.28618 30.21792 100
flip4(foo) 21.17689 21.57282 21.73175 28.41672 81.60040 100
答案 4 :(得分:0)
您可以使用substitute()
获取空参数。这可以包含在普通列表中。
然后,以编程方式生成可变数量的空参数,只需rep()
它:
n <- 4
rep(list(substitute()), n)