如何在每个矩阵元素的索引上应用函数

eol*_*old 48 dictionary r function matrix apply

我想知道在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)
}
Run Code Online (Sandbox Code Playgroud)

如果没有这样的内置函数,那么初始化矩阵以包含通过计算具有矩阵索引作为参数的任意函数获得的值的最佳方法是什么?

42-*_*42- 29

我怀疑你想要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
Run Code Online (Sandbox Code Playgroud)

这产生了一个很好的紧凑输出.但它可能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
Run Code Online (Sandbox Code Playgroud)

您可能并不真正意味着向函数提供row()和col()函数将返回的内容:这将生成一个15(有点冗余)3 x 5矩阵的数组:

> outer(row(mat), col(mat) , FUN=function(r,c) log(r+c) )
Run Code Online (Sandbox Code Playgroud)


Rei*_*son 18

最简单的方法就是使用f()可以直接应用于矩阵元素的方法.例如,使用m来自@ adamleerich的答案的矩阵

m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2)
Run Code Online (Sandbox Code Playgroud)

apply()as.character()示例的情况下没有理由使用.相反,我们可以对元素进行操作,m就好像它是一个向量(它确实是一个)并在原地替换:

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

该块的第一部分是关键点.m[]强制元素m被输出替换as.character(),而不是m用字符向量覆盖.

就是将函数应用于矩阵的每个元素的一般解决方案.

如果真的需要使用一个f()适用于行和列索引的,那么我会写一个f()using 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
Run Code Online (Sandbox Code Playgroud)

或者outer()像其他人一样使用的.如果f()没有矢量化,那么我会尽可能重新考虑我的策略,因为我可能是一种编写真正矢量化版本的方法,而ii)没有矢量化的函数不会很好地扩展.


ada*_*ich 13

你没有告诉我们你想要对每个元素应用什么样的函数,但我认为其他答案中的例子工作的唯一原因是因为函数已经被矢量化了.如果你真的想要为每个元素应用一个函数,outer那么就不会给你任何特殊的功能.您会注意到答案甚至没有通过矩阵outer!

如何关注@ Chase的评论和使用apply.

例如,我有矩阵

m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2)
Run Code Online (Sandbox Code Playgroud)

如果我想把它变成一个字符矩阵,逐个元素(就像一个例子)我可以这样做

apply(m, c(1,2), as.character)
Run Code Online (Sandbox Code Playgroud)

当然,as.character已经是矢量化了,但我的特殊功能my.special.function却没有.它只需要一个参数,一个元素.没有直接的方式来outer使用它.但是,这很有效

apply(m, c(1,2), my.special.function)
Run Code Online (Sandbox Code Playgroud)


jor*_*ran 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
Run Code Online (Sandbox Code Playgroud)

这显然是一个相当简单的示例函数,但您也可以提供自己的自定义函数.见?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
Run Code Online (Sandbox Code Playgroud)