通过自己的向量划分数组中矩阵的每个切片?

时间:2015-03-10 19:40:53

标签: arrays r matrix linear-algebra

假设我有两个数组(如果需要张量包,则为张量)

dim(Xbeta)
  products      draws Households
        13      20        10

dim(denom)
        1       20        10


set.seed(1)
Xbeta=array(rnorm(13*20*10,0,1),dim=c(13,20,10))
denom=array(rnorm(1*20*10,0,1),dim=c(1,20,10))

没有循环,我想做以下事情:

   for(i in 1:10){

    Xbeta[,,i]=t(t(Xbeta[,,i]) / denom[,,i])

       }

我想将Xbeta[,,i]切片中的每一列除以denom[,,i].

中的每个对应数字

例如...... Xbeta[,1,i]/denom[,1,i] ...等

3 个答案:

答案 0 :(得分:1)

# Is this what you're looking for?
Xbeta <- array(rnorm(13*20*10,0,1),dim=c(13,20,10))
denom <- array(rnorm(1*20*10,0,1),dim=c(1,20,10))
div.list <- sapply(1:10, FUN = function(x) t(Xbeta[,,x]) / denom[,,x], simplify = FALSE) 
result <-   array(do.call(c, div.list), dim = dim(Xbeta)[c(2,1,3)])

答案 1 :(得分:1)

我不确定为什么要为denon选择三维数组。无论如何,这可以通过密切关注这些数字如何存储在内存中来完成。在数组中,第一个维度&#34;移动最快&#34;。通过复制denom值13次&#34;每个&#34;然后你创建一个与你的分子具有完全相同尺寸的数组。

所以,让我们测试一下: 让我们保存ramdom值,以便我们可以将它们用于两种方法:

set.seed(1)
Num_2600 <- rnorm(13*20*10,0,1)
Denom_200 <- rnorm(20*10,0,1)
Xbeta=array(Num_2600,dim=c(13,20,10))
denom=array(Denom_200,dim=c(1,20,10))
Your_result <- array(NA, dim=c(13,20,10))

您的代码提供:

for(i in 1:10){
Your_result[,,i] <- t(t(Xbeta[,,i]) / denom[,,i])
   }

我的代码:

denom_myVersion <- array(rep( Denom_200 , each=13), c(13,20,10))

>  all(Your_result == Xbeta / denom_myVersion)
[1] TRUE
> 

所以我们得到了相同的结果。困难的部分是如何决定如何复制,以便数字落在正确的位置。注意:

denom_myVersion <- array(rep( Denom_200 , times=13), c(13,20,10))

>  all(Your_result == Xbeta / denom_myVersion)
[1] FALSE
> 

使用&#39;每个&#39;作为rep中的参数,每个元素在转到下一个元素之前重复13次。随着时间的推移,整个矢量重复13次。比较:

> rep(1:3, each =3)
[1] 1 1 1 2 2 2 3 3 3
> rep(1:3, times=3)
[1] 1 2 3 1 2 3 1 2 3

答案 2 :(得分:1)

你可以通过(1)三维转置分子数组和(2)将分母数组展平为一个向量来避免循环和复制,这样除法运算将自然地循环不完全分母向量遍及整个转置分子数组使数据按照您想要的方式排列。然后,你必须三维地“#34;”不转置&#34;恢复原始转置的结果。

aperm(aperm(Xbeta,c(2,3,1))/c(denom),c(3,1,2));

aperm()的第一次调用将列转换为行,将z切片转换为列,将行转换为z切片。对c()的{​​{1}}调用将分母数组展平为向量,因为在骑自行车时,我们并不关心维度。对denom的最后一次调用会颠倒原始的转置。

要详细了解此解决方案的逻辑,您对输入所拥有的内容基本上是每个分子数组的z切片的除数矢量,并且您希望将每个除数应用于相应z的每一行-slice和专栏。这意味着除数的向量必须首先应用于列,然后,当每个分母z切片耗尽时,应用于分子z切片。在分子阵列的完整行(覆盖行中的所有z切片)已经用尽之后,整个分母向量已经耗尽,导致它循环回到分子阵列的下一行的开头。

请参阅https://stat.ethz.ch/R-manual/R-devel/library/base/html/aperm.html

关于表现的粗略想法:

aperm()

此外,作为一般性建议,使用最少的样本输入来呈现这些问题是有帮助的(对于提问者和回答者),例如:

r> set.seed(1);
r> Xbeta <- array(rnorm(13*20*10,0,1), dim=c(13,20,10) );
r> denom <- array(rnorm(1*20*10,0,1), dim=c(1,20,10) );
r> robert <- function() { result <- array(NA, dim=c(13,20,10) ); for (i in 1:10) { result[,,i] <- t(t(Xbeta[,,i]) / denom[,,i]); }; };
r> andre <- function() { denom_myVersion <- array(rep(c(denom), each=13 ), c(13,20,10) ); result <- Xbeta / denom_myVersion; };
r> bgoldst <- function() { result <- aperm(aperm(Xbeta,c(2,3,1))/c(denom),c(3,1,2)); };
r> N <- 99999;
r> system.time({ replicate(N, robert() ); });
   user  system elapsed
 25.421   0.000  25.440
r> system.time({ replicate(N, andre() ); });
   user  system elapsed
 12.578   0.594  13.283
r> system.time({ replicate(N, bgoldst() ); });
   user  system elapsed
  8.484   0.594   9.142