2011-12-20 111 views
16

所以我想通過在R.矩陣這個作品真的直觀一些簡單的功能應用功能:R:應用功能在矩陣和保持矩陣尺寸

> (function(x)x*x)(matrix(1:10, nrow=2)) 
[,1] [,2] [,3] [,4] [,5] 
[1,] 1 9 25 49 81 
[2,] 4 16 36 64 100 

...但顯然我不瞭解其所有運作:

> m = (matrix(1:10, nrow=2)) 
> (function(x) if (x %% 3 == 0) { return(NA) } else { return(x+1) })(m) 
    [,1] [,2] [,3] [,4] [,5] 
[1,] 2 4 6 8 10 
[2,] 3 5 7 9 11 
Warning message: 
In if (x == 3) { : 
    the condition has length > 1 and only the first element will be used 

我這個念起來發現了矢量化和sapply,這似乎都很大,只是喜歡我想要的東西,除了他們兩個我的矩陣轉換成一個列表:

> y = (function(x) if (x %% 3 == 0) { return(NA) } else { return(x+1) }) 
> sapply(m, y) 
[1] 2 3 NA 5 6 NA 8 9 NA 11 
> Vectorize(y)(m) 
[1] 2 3 NA 5 6 NA 8 9 NA 11 

...但我想保留它的當前尺寸矩陣。我該怎麼做?謝謝!

+0

還檢查了這個有用的帖子在不同版本適用的:http://nsaunders.wordpress.com/2010/08/20/a-brief-introduction-to-apply-in-r/ – patrickmdnet 2011-12-20 17:36:15

回答

15

@Joshua Ulrich(and Dason)有一個很好的答案。如果沒有y這個功能,直接做就是最好的解決方案。但如果你真的需要來調用一個函數,你可以使用vapply更快。它產生一個矢量沒有尺寸(如sapply,但速度更快),但你可以使用structure它們添加回:

# Your function (optimized) 
y = function(x) if (x %% 3) x+1 else NA 

m <- matrix(1:1e6,1e3) 
system.time(r1 <- apply(m,1:2,y)) # 4.89 secs 
system.time(r2 <- structure(sapply(m, y), dim=dim(m))) # 2.89 secs 
system.time(r3 <- structure(vapply(m, y, numeric(1)), dim=dim(m))) # 1.66 secs 
identical(r1, r2) # TRUE 
identical(r1, r3) # TRUE 

...正如你所看到的,vapply辦法是約3倍比apply快...並且原因vapplysapply更快是因爲sapply必須分析結果以發現它可以簡化爲數字向量。隨着vapply,您所指定的結果類型(numeric(1)),因此它不必猜...

UPDATE我想通了保留矩陣結構的另一個(短)的方式:

m <- matrix(1:10, nrow=2) 
m[] <- vapply(m, y, numeric(1)) 

您只需使用m[] <-將新值分配給對象。然後保留所有其他屬性(如dim,dimnames,class等)。

+0

非常感謝。我同意回顧一下,我用跳過實際功能的玩具示例是正確的調用,但我真的很想知道在實際上它是一個函數時應如何處理。 (我嘗試着設計一個比我真正處理的效果更簡單的效果,但顯然錯過了該標記。)無論如何,有時間信息是非常有幫助的,因爲我正試圖優化這一點 - 謝謝! – 2011-12-20 17:41:42

12

一種方法是對行和列使用apply

apply(m,1:2,y) 
    [,1] [,2] [,3] [,4] [,5] 
[1,] 2 NA 6 8 NA 
[2,] 3 5 NA 9 11 

您還可以使用下標做,因爲==已經矢量化:

m[m %% 3 == 0] <- NA 
m <- m+1 
m 
    [,1] [,2] [,3] [,4] [,5] 
[1,] 2 NA 6 8 NA 
[2,] 3 5 NA 9 11 
7

對於這個特定的例子中,你可以只做這樣的事情

> # Create some fake data 
> mat <- matrix(1:16, 4, 4) 
> # Set all elements divisible by 3 to NA 
> mat[mat %% 3 == 0] <- NA 
> # Add 1 to all non NA elements 
> mat <- mat + 1 
> mat 
    [,1] [,2] [,3] [,4] 
[1,] 2 6 NA 14 
[2,] 3 NA 11 15 
[3,] NA 8 12 NA 
[4,] 5 9 NA 17 
+0

一位同事指出了這種做法。它確實滿足我的需求,我很欣賞它,但它確實看起來應該有一種方法來將預先存在的函數應用於矩陣。 – 2011-12-20 17:37:51

6

Dason和Josh的解決方案使用ifelse略有改進。

mat <- matrix(1:16, 4, 4) 
ifelse(mat %% 3 == 0, NA, mat + 1) 
    [,1] [,2] [,3] [,4] 
[1,] 2 6 NA 14 
[2,] 3 NA 11 15 
[3,] NA 8 12 NA 
[4,] 5 9 NA 17 
+0

不錯的一個。這將是最快的。使用'rbenchmark'進行快速檢查表明它比'vapply'解決方案快8倍左右。矢量化始終是勝利! – Ramnath 2011-12-20 19:51:26