将数组中矩阵的每个切片除以它自己的向量?
Divide every slice of a matrix in an array by its own vector?
假设我有两个数组(如果需要张量包,则为张量)
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]
...等等
# 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)])
我不确定您为什么为 denon
选择 3 维数组。无论如何,这可以通过密切注意这些数字在内存中的存储方式来完成。在数组中,第一个维度 "moves the fastest"。通过将 denom 值复制 13 次 "each",然后创建一个与分子维度完全相同的数组。
那么,让我们来测试一下:
让我们保存 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
>
将'each'作为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
您可以通过 (1) 三维转置分子数组和 (2) 将分母数组展平为向量来避免循环和复制,这样除法运算将自然地循环整个不完整的分母向量转置分子数组,使数据按照您想要的方式排列。然后,您必须对结果进行 3 维 "untranspose" 才能取回原始转置。
aperm(aperm(Xbeta,c(2,3,1))/c(denom),c(3,1,2));
第一次调用 aperm()
将列转置为行,将 z 切片转置为列,将行转置为 z 切片。 c()
对 denom
的调用将分母数组展平为向量,因为在循环时,我们不关心维数。对 aperm()
的最终调用反转了原来的转置。
要更详细地了解此解决方案的逻辑,您的输入基本上是分子数组的每个 z 切片的除数向量,并且您想将每个除数应用于分子数组的每一行相应的 z 切片和列。这意味着除数向量必须首先跨列应用,然后,当每个分母 z 切片用完时,跨分子 z 切片应用。在用完分子数组的完整行(覆盖该行中的所有 z 切片)后,整个分母向量也用完,导致它循环回到分子数组下一行的开头。
见https://stat.ethz.ch/R-manual/R-devel/library/base/html/aperm.html。
对于性能的粗略了解:
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
此外,作为一般性建议,使用最少的样本输入来呈现此类问题(对于提问者和回答者)是有帮助的,例如:
r> n <- array(1:12,dim=c(2,3,2)); n;
, , 1
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
, , 2
[,1] [,2] [,3]
[1,] 7 9 11
[2,] 8 10 12
r> d <- array(1:6,dim=c(1,3,2)); d;
, , 1
[,1] [,2] [,3]
[1,] 1 2 3
, , 2
[,1] [,2] [,3]
[1,] 4 5 6
r> aperm(aperm(n,c(2,3,1))/c(d),c(3,1,2));
, , 1
[,1] [,2] [,3]
[1,] 1 1.5 1.666667
[2,] 2 2.0 2.000000
, , 2
[,1] [,2] [,3]
[1,] 1.75 1.8 1.833333
[2,] 2.00 2.0 2.000000
假设我有两个数组(如果需要张量包,则为张量)
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]
...等等
# 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)])
我不确定您为什么为 denon
选择 3 维数组。无论如何,这可以通过密切注意这些数字在内存中的存储方式来完成。在数组中,第一个维度 "moves the fastest"。通过将 denom 值复制 13 次 "each",然后创建一个与分子维度完全相同的数组。
那么,让我们来测试一下: 让我们保存 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
>
将'each'作为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
您可以通过 (1) 三维转置分子数组和 (2) 将分母数组展平为向量来避免循环和复制,这样除法运算将自然地循环整个不完整的分母向量转置分子数组,使数据按照您想要的方式排列。然后,您必须对结果进行 3 维 "untranspose" 才能取回原始转置。
aperm(aperm(Xbeta,c(2,3,1))/c(denom),c(3,1,2));
第一次调用 aperm()
将列转置为行,将 z 切片转置为列,将行转置为 z 切片。 c()
对 denom
的调用将分母数组展平为向量,因为在循环时,我们不关心维数。对 aperm()
的最终调用反转了原来的转置。
要更详细地了解此解决方案的逻辑,您的输入基本上是分子数组的每个 z 切片的除数向量,并且您想将每个除数应用于分子数组的每一行相应的 z 切片和列。这意味着除数向量必须首先跨列应用,然后,当每个分母 z 切片用完时,跨分子 z 切片应用。在用完分子数组的完整行(覆盖该行中的所有 z 切片)后,整个分母向量也用完,导致它循环回到分子数组下一行的开头。
见https://stat.ethz.ch/R-manual/R-devel/library/base/html/aperm.html。
对于性能的粗略了解:
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
此外,作为一般性建议,使用最少的样本输入来呈现此类问题(对于提问者和回答者)是有帮助的,例如:
r> n <- array(1:12,dim=c(2,3,2)); n;
, , 1
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
, , 2
[,1] [,2] [,3]
[1,] 7 9 11
[2,] 8 10 12
r> d <- array(1:6,dim=c(1,3,2)); d;
, , 1
[,1] [,2] [,3]
[1,] 1 2 3
, , 2
[,1] [,2] [,3]
[1,] 4 5 6
r> aperm(aperm(n,c(2,3,1))/c(d),c(3,1,2));
, , 1
[,1] [,2] [,3]
[1,] 1 1.5 1.666667
[2,] 2 2.0 2.000000
, , 2
[,1] [,2] [,3]
[1,] 1.75 1.8 1.833333
[2,] 2.00 2.0 2.000000