我想知道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)
}
如果没有这样的内置函数,那么初始化矩阵以包含通过计算以矩阵索引作为参数的任意函数获得的值的最佳方法是什么?
答案 0 :(得分: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
你可能并不真正想要为函数提供row()和col()函数返回的内容:这会产生一个15(有点冗余)3 x 5矩阵的数组:
> outer(row(mat), col(mat) , FUN=function(r,c) log(r+c) )
答案 1 :(得分:18)
最简单的方法 只是使用可以直接应用于矩阵元素的f()
。例如,使用@ adamleerich的答案
m
m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2)
在apply()
示例的情况下,没有理由使用as.character()
。相反,我们可以对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()
,那么我将使用f()
和row()
编写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()
没有矢量化,那么我会尽可能重新考虑我的策略,因为我可能是一种编写真正矢量化版本的方法,而ii)没有矢量化的函数不是规模很大。
答案 2 :(得分:13)
您没有告诉我们您希望将哪种功能应用于每个元素,但我认为其他答案中的示例工作的唯一原因是因为函数已经过矢量化。如果你真的想要为每个元素应用一个函数,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)
答案 3 :(得分: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
答案 4 :(得分: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
这太好了,对吗?好吧,如果你有一个包含两个或更多parms的函数,它就会崩溃。比方说,你有这个:
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