2014-01-17 27 views
4

似乎apply將只在一個保證金操作時不重新組裝3D陣列。試想一下:三維陣列 - >應用 - > 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×4矩陣中每個arr[, , i]周圍洗牌列,並使用apply到矩陣乘法每個a*b子矩陣arr重新整理其列。最重要的一點是,每個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 > 1),但它仍然看起來很奇怪,如果一個函數返回一個對象的維度,他們基本上被忽略。

+0

請使用'set.seed'使數據可重現。 – Roland

+1

爲什麼不簡單地使用'res < - apply(arr,3,'%*%',cols.shuf.mx);屬性(res)< - 屬性(arr)'?我認爲這可以純粹用矩陣代數來完成。 – Roland

+0

@Roland,在這種特殊情況下工作,但如果我的右操作數'%*%'是不是方(即結果矩陣不一樣的輸入)?好主意,但。另外,對於'set.seed'抱歉,但在這種情況下它看起來並不相關,因爲所有重要的是結構。 – BrodieG

回答

0

如果你讀了apply幫助頁面,它基本上是與你的第一句話同意。它建立在一個特定的設計上,你需要構建一個新的功能來做不同的事情。 BTW:這給你同樣的結果更加簡單比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 
+0

rigamarole只是爲了說明返回尺寸向量的'apply'。此解決方案僅適用於特定示例,但不適用於常見問題(「aperm(aaply(...))」適用於常見問題)。是的,我閱讀了文檔(參見Q的最後一段),但忽略結果的維度似乎是一個非常奇怪的設計決定。 – BrodieG

1

這裏是不是夢幻般的解決方案不太需要的功能,結果矩陣的尺寸預知:

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

我喜歡它。我也看着'vapply',但沒有經過。 –