【问题标题】:3D array -> apply -> 3D array3D 数组 -> 应用 -> 3D 数组
【发布时间】:2014-01-17 22:05:33
【问题描述】:

似乎apply 仅在一个边距上操作时不会重新组装 3D 阵列。考虑:

 arr <- array(
  runif(2*4*3), 
  dim=c(2, 4, 3), 
  dimnames=list(a=paste0("a", 1:2), b=paste0("b", 1:4), c=paste0("c", 1:3))
)
# , , c = c1
# 
#     b
# a           b1        b2        b3        b4
#   a1 0.7321399 0.8851802 0.2469866 0.9307044
#   a2 0.5896138 0.6183046 0.7732842 0.6652637
# 
# , , c = c2
#     b
# a           b1        b2        b3         b4
#   a1 0.5894680 0.7839048 0.3854357 0.56555024
#   a2 0.6158995 0.6530224 0.8401427 0.04044974
# 
# , , c = c3
#     b
# a           b1        b2         b3        b4
#   a1 0.3500653 0.7052743 0.42487635 0.5689287
#   a2 0.4097346 0.4527939 0.07192528 0.8638655

现在,制作一个 4 x 4 矩阵以随机排列每个 arr[, , i] 中的列,并使用 apply 矩阵乘以 arr 中的每个 a*b 子矩阵以重新排列它们的列。重点是每次apply迭代的结果都是一个矩阵

cols.shuf.mx <- matrix(c(0,1,0,0,1,0,0,0,0,0,0,1,0,0,1,0), ncol=4)
apply(arr, 3, `%*%`, cols.shuf.mx)
#         c
#             c1         c2         c3
# [1,] 0.8851802 0.78390483 0.70527431
# [2,] 0.6183046 0.65302236 0.45279387
# [3,] 0.7321399 0.58946800 0.35006532
# [4,] 0.5896138 0.61589947 0.40973463
# [5,] 0.9307044 0.56555024 0.56892870
# [6,] 0.6652637 0.04044974 0.86386552
# [7,] 0.2469866 0.38543569 0.42487635
# [8,] 0.7732842 0.84014275 0.07192528

然而,我预计结果是:

# , , c = c1
#    
# a            1         2         3         4
#   a1 0.8851802 0.7321399 0.9307044 0.2469866
#   a2 0.6183046 0.5896138 0.6652637 0.7732842
#
# , , c = c2
#    
# a            1         2          3         4
#   a1 0.7839048 0.5894680 0.56555024 0.3854357
#   a2 0.6530224 0.6158995 0.04044974 0.8401427
#
# , , c = c3
#   
# a            1         2         3          4
#   a1 0.7052743 0.3500653 0.5689287 0.42487635
#   a2 0.4527939 0.4097346 0.8638655 0.07192528

我可以通过plyr::aaply 获得预期结果:

aperm(aaply(arr, 3, `%*%`, cols.shuf.mx), c(2, 3, 1))

但想知道是否有一个 简单 的基本方法来实现这个结果(即我是否在这里遗漏了一些明显的东西来获得预期的结果)。

我意识到这里发生的事情是记录在案的 (If each call to FUN returns a vector of length n, then apply returns an array of dimension c(n, dim(X)[MARGIN]) if n &gt; 1),但我仍然觉得奇怪的是,如果一个函数返回一个具有维度的对象,它们基本上会被忽略。

【问题讨论】:

  • 请使用set.seed 使数据可重现。
  • 为什么不直接使用res &lt;- apply(arr, 3, %*%, cols.shuf.mx); attributes(res) &lt;- attributes(arr)?我认为这可以纯粹用矩阵代数来完成。
  • @Roland,在这种特殊情况下有效,但是如果我对 %*% 的右操作数不是正方形(即结果矩阵与输入不同)怎么办?不过好主意。另外,对于set.seed 感到抱歉,但在这种情况下似乎无关紧要,因为重要的是结构。

标签: r multidimensional-array apply


【解决方案1】:

这是一个不太理想的解决方案,需要预先知道函数结果矩阵的维度:

vapply(
  1:dim(arr)[3], 
  function(x, y) arr[,,x] %*% y, 
  FUN.VALUE=arr[,,1], 
  y=cols.shuf.mx
) 

【讨论】:

  • 我喜欢。我也查看了vapply,但没有跟进。
【解决方案2】:

如果您阅读了apply 的帮助页面,它基本上与您的第一句话一致。它具有特定的设计,您需要构建一个新功能来做一些不同的事情。顺便说一句:这比aperm(aaply(...))rigamarole 更简单地为您提供相同的结果:

arr[ , c(2,1,4,3)  , ]
#-------------------------
, , c = c1

    b
a           b2        b1        b4        b3
  a1 0.4089769 0.2875775 0.5281055 0.9404673
  a2 0.8830174 0.7883051 0.8924190 0.0455565

, , c = c2

    b
a           b2        b1        b4        b3
  a1 0.9568333 0.5514350 0.1029247 0.6775706
  a2 0.4533342 0.4566147 0.8998250 0.5726334

, , c = c3

    b
a           b2         b1        b4        b3
  a1 0.3279207 0.24608773 0.6405068 0.8895393
  a2 0.9545036 0.04205953 0.9942698 0.6928034

【讨论】:

  • rigamarole 只是为了说明一个返回维度向量的apply。此解决方案仅适用于特定示例,但不适用于一般问题(aperm(aaply(...)) 适用于一般问题)。是的,我阅读了文档(参见 Q 的最后一段),但忽略结果的维度似乎是一个非常奇怪的设计决定。
猜你喜欢
  • 1970-01-01
  • 2014-05-06
  • 1970-01-01
  • 2015-05-09
  • 1970-01-01
  • 2014-04-20
  • 1970-01-01
  • 2020-05-08
  • 2016-04-17
相关资源
最近更新 更多