如何在每个matrix元素的索引上应用函数
我想知道在R中是否有一个内置函数将函数应用到matrix的每个元素(当然,函数应该根据matrix索引来计算)。 相当于这样的东西:
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) }
如果没有这样的内置函数,初始化matrix以包含通过计算具有matrix索引作为参数的任意函数获得的值的最佳方法是什么?
我怀疑你想要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
视为另一种执行与本页上的其他人使用Vectorize
相同的操作的方法是有帮助的。 由于无法Vectorize
使用“原始”function,因此更加通用。
data.frame(mrow=c(row(mat)), # straightens out the arguments mcol=c(col(mat)), mfres= mapply(function(r,c) log(r+c), row(mat), col(mat) ) ) # mrow mcol mfres 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
你可能并没有真正的意思向函数提供row()和col()函数返回的内容:这将产生15个(有点冗余的)3×5matrix的数组:
> outer(row(mat), col(mat) , FUN=function(r,c) log(r+c) )
最简单的方法就是使用可以直接应用于matrix元素的f()
。 例如,使用来自@ adamleerich的答案的matrixm
m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2)
在as.character()
例子中,没有理由使用apply()
。 相反,我们可以对m
的元素进行操作,就好像它是一个向量(它确实是一个向量),并在原地replace:
> m[] <- as.character(m) > m [,1] [,2] [,3] [,4] [1,] "1" "3" "5" "7" [2,] "2" "4" "6" "8"
该块的第一部分是这里的关键。 m[]
强制将m
的元素replace为as.character()
的输出,而不是用一个字符向量来覆盖m
。
所以这是将函数应用到matrix的每个元素的一般解决scheme。
如果真的需要使用行和列索引的f()
,那么我会使用row()
和col()
写一个f()
col()
:
> 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()
没有被vector化,那么我会尽可能的重新思考我的策略,因为我可能是写一个真正的vector化版本的方法,ii)没有vector化的函数不会规模很好。
你没有告诉我们你想要对每个元素应用什么样的函数,但是我认为其他答案中例子的唯一原因是因为函数已经被vector化了。 如果你真的想把一个函数应用到每个元素, outer
不会给你任何特殊的东西,这个函数还没有给你。 你会注意到答案甚至没有传递一个matrix到outer
!
如何遵循@ Chase的评论和使用apply
。
例如,我有matrix
m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2)
如果我想把它变成一个字符matrix,按元素(就像一个例子),我可以做到这一点
apply(m, c(1,2), as.character)
当然, as.character
已经被vector化了,但是我的特殊函数my.special.function
不是。 它只需要一个参数,一个元素。 没有直接的方法让outer
的工作。 但是,这个工作
apply(m, c(1,2), my.special.function)
你可能会想到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
这显然是一个相当简单的示例function,但是您也可以提供自己的定制function。 看?outer
。
编辑
相反,下面的评论,你也可以使用outer
与非vector化的function….vector化他们!
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
这并不能完全回答你的问题,但是我在找出一个类似的问题的时候发现了它,所以我会告诉你一些事情。
假设你有一个函数,你想要应用到matrix的每个元素只需要一个部分。
mydouble <- function(x) { return(x+x) }
并说你有一个matrixX,
> 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()函数。 但是,它会丢失matrix,但结果正确计算。 如果你这么倾向,他们可以改革。
> 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