2011-09-12 34 views
44

我在想,如果在R中有一個內置函數將函數應用於矩陣的每個元素(當然,函數應該根據矩陣索引計算)。等效會是這樣的:如何在每個矩陣元素的索引上應用函數

matrix_apply <- function(m, f) { 
    m2 <- m 
    for (r in seq(nrow(m2))) 
    for (c in seq(ncol(m2))) 
     m2[[r, c]] <- f(r, c) 
    return(m2) 
} 

如果沒有這樣的內置功能,什麼是初始化一個矩陣包含通過計算具有矩陣指數作爲參數的任意函數得到的值的最佳方式是什麼?

+2

您是否熟悉正確命名的'apply()'函數族? MARGIN參數接受行,列和行與列的值。更不用說,很多R函數都是矢量化的,可以避免這種類型的編程。 – Chase

+3

@leden你可以舉一個'f()'的例子嗎?據我所知,任何矢量化函數都可以在矩陣上工作,因爲它只是一個具有dim屬性的矢量。您不需要將其分解成行和列索引。目前,你Q中存在一些含糊不清的情況;似乎你想要一個通用的解決方案,但禁止它應該基於指數,這是次優的。 –

+0

我的意思是,爲什麼不能寫'f()',使得你真正需要的是'm [] < - f(m)'?我會添加一個例子... –

回答

27

我懷疑你想outer

> mat <- matrix(NA, nrow=5, ncol=3) 

> outer(1:nrow(mat), 1:ncol(mat) , FUN="*") 
    [,1] [,2] [,3] 
[1,] 1 2 3 
[2,] 2 4 6 
[3,] 3 6 9 
[4,] 4 8 12 
[5,] 5 10 15 

> outer(1:nrow(mat), 1:ncol(mat) , FUN=function(r,c) log(r+c)) 
      [,1]  [,2]  [,3] 
[1,] 0.6931472 1.098612 1.386294 
[2,] 1.0986123 1.386294 1.609438 
[3,] 1.3862944 1.609438 1.791759 
[4,] 1.6094379 1.791759 1.945910 
[5,] 1.7917595 1.945910 2.079442 

那得到一個不錯的緊湊輸出。但有可能mapply在其他情況下會有用。將mapply作爲執行與本頁其他人使用Vectorize相同的操作的另一種方式很有幫助。 mapply更爲一般,因爲Vectorize無法使用「原始」功能。

data.frame(mrow=c(row(mat)), # straightens out the arguments 
      mcol=c(col(mat)), 
      m.f.res= mapply(function(r,c) log(r+c), row(mat), col(mat) )) 
# mrow mcol m.f.res 
1  1 1 0.6931472 
2  2 1 1.0986123 
3  3 1 1.3862944 
4  4 1 1.6094379 
5  5 1 1.7917595 
6  1 2 1.0986123 
7  2 2 1.3862944 
8  3 2 1.6094379 
9  4 2 1.7917595 
10 5 2 1.9459101 
11 1 3 1.3862944 
12 2 3 1.6094379 
13 3 3 1.7917595 
14 4 3 1.9459101 
15 5 3 2.0794415 

你可能並不真正意味着提供給函數的行什麼()和col()函數將返回:由此產生的15(有些多餘)3×5矩陣陣列:

> outer(row(mat), col(mat) , FUN=function(r,c) log(r+c)) 
8

你也許會想的outer

rows <- 1:10 
cols <- 1:10 

outer(rows,cols,"+") 

     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] 
[1,] 2 3 4 5 6 7 8 9 10 11 
[2,] 3 4 5 6 7 8 9 10 11 12 
[3,] 4 5 6 7 8 9 10 11 12 13 
[4,] 5 6 7 8 9 10 11 12 13 14 
[5,] 6 7 8 9 10 11 12 13 14 15 
[6,] 7 8 9 10 11 12 13 14 15 16 
[7,] 8 9 10 11 12 13 14 15 16 17 
[8,] 9 10 11 12 13 14 15 16 17 18 
[9,] 10 11 12 13 14 15 16 17 18 19 
[10,] 11 12 13 14 15 16 17 18 19 20 

這顯然是一個很簡單的例子功能,但是您可以提供自己的自定義一個爲好。請參閱?outer

編輯

相反,下面的評論,你還可以通過矢量化....他們使用outer與非量化的功能!

m <- matrix(1:16,4,4) 

#A non-vectorized function 
myFun <- function(x,y,M){ 
    M[x,y] + (x*y) 
} 

#Oh noes! 
outer(1:4,1:4,myFun,m) 
Error in dim(robj) <- c(dX, dY) : 
    dims [product 16] do not match the length of object [256] 

#Oh ho! Vectorize()! 
myVecFun <- Vectorize(myFun,vectorize.args = c('x','y')) 

#Voila! 
outer(1:4,1:4,myVecFun,m) 
    [,1] [,2] [,3] [,4] 
[1,] 2 7 12 17 
[2,] 4 10 16 22 
[3,] 6 13 20 27 
[4,] 8 16 24 32 
+0

我不認爲他正在尋找'outer'。僅僅因爲他用double for循環的例子看起來像是對'outer'的調用並不意味着'outer'會起作用。你可以給一個使用未矢量化函數的例子嗎? – adamleerich

+0

@adamleerich查看我的編輯。非矢量化函數可以被矢量化。 – joran

10

你沒有告訴我們你想對每個元素應用什麼樣的函數,但我認爲其他答案中例子的唯一原因是因爲函數已經被矢量化了。如果你真的想對每個元素應用一個函數,outer不會給你任何特別的東西,這個函數還沒有給你。你會注意到答案甚至沒有傳遞一個矩陣到outer

如何遵循@ Chase的評論和使用apply

例如,我有矩陣

m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2) 

如果我想要把它變成一個字符矩陣,通過元素(就像一個例子)元素我能做到這一點

apply(m, c(1,2), as.character) 

中當然,as.character已經被矢量化了,但是我的特殊功能my.special.function不是。它只需要一個參數,一個元素。沒有直接的方法可以讓outer與它一起工作。但是,這個工程

apply(m, c(1,2), my.special.function) 
+0

您可以使用非矢量化函數來使'outer'工作,但只能通過使用apply()僞裝它來僞造矢量化。 –

+0

此外,我在我的回答中展示瞭如何在不訴諸'apply()'的情況下執行'as.character()',因此,我們應該提倡正確的方式來做事而不是僞造理想的結果 - 你的'apply()'* *只是隱藏了一個更長的單循環,其中OP有兩個嵌套的循環。 –

15

最簡單的方法是只是使用的f(),可直接應用於矩陣的元素。例如,使用從@ adamleerich的回答

m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2) 

矩陣m沒有理由在as.character()例子中使用apply()。相反,我們可以對m的元素進行操作,就好像它是一個向量(它真的是一個),並就地替換

> m[] <- as.character(m) 
> m 
    [,1] [,2] [,3] [,4] 
[1,] "1" "3" "5" "7" 
[2,] "2" "4" "6" "8" 

該塊的第一部分是這裏的關鍵。 m[]強制將m的元素替換爲as.character()的輸出,而不是用字符向量覆蓋m

因此,是對矩陣的每個元素應用函數的一般解決方案。

如果真正需要使用的f()上的行和列的索引工作,那麼我用row()col()f()

> m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2) 
> row(m) 
    [,1] [,2] [,3] [,4] 
[1,] 1 1 1 1 
[2,] 2 2 2 2 
> col(m) 
    [,1] [,2] [,3] [,4] 
[1,] 1 2 3 4 
[2,] 1 2 3 4 
> row(m) * col(m) ## `*`(row(m), col(m)) to see this is just f() 
    [,1] [,2] [,3] [,4] 
[1,] 1 2 3 4 
[2,] 2 4 6 8 

或者一個使用outer()其他的顯示。如果f()沒有被矢量化,那麼我會盡可能地重新思考我的策略,因爲我可能是寫一個真正的矢量化版本的方法,並且ii)沒有矢量化的函數不會很大好。

+0

+1'm []'風格的好例子。 – Iterator

0

這並不完全回答你的問題,但我找到它時,試圖找出一個類似的問題,所以我會告訴你的東西。

假設你有一個函數,你想要應用到矩陣的每個元素只需要一個部分。

mydouble <- function(x) { 
    return(x+x) 
} 

,說你有一個矩陣X,

> x=c(1,-2,-3,4) 
> X=matrix(x,2,2) 
> X 
    [,1] [,2] 
[1,] 1 -3 
[2,] -2 4 

那麼你這樣做:

res=mydouble(X) 

然後,它會做的每個值的各個元素的雙層。

但是,如果您在下面的函數中執行邏輯,您將得到一個警告,表明它沒有參數化,並且不像您期望的那樣運行。

myabs <- function(x) { 
    if (x<0) { 
     return (-x) 
    } else { 
     return (x) 
    } 
} 

> myabs(X) 
    [,1] [,2] 
[1,] 1 -3 
[2,] -2 4 
Warning message: 
In if (x < 0) { : 
    the condition has length > 1 and only the first element will be used 

但是,如果你使用apply()函數,你可以使用它。

例如:

> apply(X,c(1,2),myabs) 
    [,1] [,2] 
[1,] 1 3 
[2,] 2 4 

所以這是很大的,對不對?那麼,如果你有一個具有兩個或更多參數的函數,它就會崩潰。例如說,你有這樣的:

mymath <- function(x,y) { 
    if(x<0) { 
     return(-x*y) 
    } else { 
     return(x*y) 
    } 
} 

在這種情況下,你使用apply()函數。但是,它將丟失矩陣,但結果正確計算。如果你這麼傾向,他們可以改革。

> mapply(mymath,X,X) 
[1] 1 -4 -9 16 
> mapply(mymath,X,2) 
[1] 2 4 6 8 
> matrix(mapply(mymath,X,2),c(2,2)) 
    [,1] [,2] 
[1,] 2 6 
[2,] 4 8 
相關問題