Подтвердить что ты не робот

Как применить функцию по индексам каждого матричного элемента

Мне интересно, есть ли встроенная функция в 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)
}

Если такой встроенной функции нет, то какой способ инициализации матрицы содержать значения, полученные путем вычисления произвольной функции, имеющей матричные индексы в качестве параметров?

4b9b3361

Ответ 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(), который может быть применен непосредственно к элементам матрицы. Например, используя матрицу m из @adamleerich Ответ

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) функция, которая не является векторизованной, не собирается очень хорошо.

Ответ 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)

Ответ 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

Ответ 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