【问题标题】:How to apply function over each matrix element's indices如何对每个矩阵元素的索引应用函数
【发布时间】:2011-11-15 18:15:33
【问题描述】:

我想知道 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)
}

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

【问题讨论】:

  • 您熟悉恰如其分的apply() 系列函数吗? MARGIN 参数接受行、列和行和列的值。更何况还有不少 R 函数是矢量化的,可以避免这种类型的编程。
  • @leden 你能举个f()的例子吗?据我所知,任何矢量化函数都可以在矩阵上工作,因为它只是一个带有 dim 属性的向量。您不需要将其分解为行和列索引。目前,您的 Q 存在一定的歧义;似乎您想要一个通用解决方案,但禁止它应该基于索引,这是次优的。
  • 我的意思是,为什么f() 不能写成你真正需要的是m[] &lt;- f(m)?我将添加一个示例...
  • 我认为 OP 需要回应我们所有人,而不仅仅是因为它有礼貌 :-) 。完全按照所写的方式阅读他的示例,m2 矩阵是使用函数“f(r,c)”生成的,该函数纯粹是索引的函数,与原始矩阵的内容无关。由于这可能不是他想要的,而不是 'g(r,c,m[r,c])' 或 'g(m[r,c])' ,到目前为止提供的答案非常好,但不是必须回答他的(模棱两可的)问题。
  • 我只需要能够应用一个函数,该函数至少需要每个矩阵列的索引。一个这样的应用程序,假设我想创建一个乘法表,或者只是评估两个参数的某个函数并将结果存储到矩阵中。

标签: r function dictionary matrix apply


【解决方案1】:

我怀疑你想要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) )

【讨论】:

    【解决方案2】:

    最简单的方法只是使用一个f(),它可以直接应用于矩阵的元素。例如,使用@adamleerich 的答案中的矩阵m

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

    对于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() 没有矢量化,那么我会尽可能重新考虑我的策略 i) 可能是一种编写真正矢量化版本的方法,并且 ii) 未矢量化的函数不会扩展性很好。

    【讨论】:

      【解决方案3】:

      您没有告诉我们要对每个元素应用哪种函数,但我认为其他答案中的示例有效的唯一原因是因为函数已经矢量化。如果你真的想对每个元素应用一个函数,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)
      

      【讨论】:

      • 您可以使outer 与非矢量化函数一起工作,但只能像使用apply() 一样伪造矢量化。
      • 此外,我在我的回答中展示了如何在不诉诸 apply() 的情况下执行 as.character(),因此,我们可能应该提倡正确的做事方式,而不是假装想要的结果 - 你的 apply() is 只是隐藏了一个更长的单循环,其中 OP 嵌套了两个循环。
      【解决方案4】:

      你可能在想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
      

      【讨论】:

      • 我不认为outer 是他要找的。仅仅因为他的双 for 循环示例看起来像是对 outer 的调用,并不意味着 outer 会起作用。你能举一个使用未矢量化函数的例子吗?
      • @adamleerich 查看我的编辑。非向量化函数可以向量化。
      【解决方案5】:

      这并不能完全回答您的问题,但我在尝试找出类似问题时发现了它,因此我将向您展示一些内容。

      假设您有一个函数,您想将其应用于矩阵的每个元素,而该矩阵只需要一个部分。

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-30
        • 2014-09-06
        相关资源
        最近更新 更多