2011-09-12 62 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 
相关问题