valor - Cómo aplicar la función sobre los índices de cada elemento de la matriz
obtener fila y columna de una celda excel (5)
Me pregunto si hay una función incorporada en R que aplica una función a cada elemento de la matriz (por supuesto, la función debe calcularse en base a los índices de la matriz). El equivalente sería algo como esto:
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)
}
Si no hay tal función incorporada, ¿cuál es la mejor manera de inicializar una matriz para contener los valores obtenidos al calcular una función arbitraria que tiene índices de matriz como parámetros?
El enfoque más simple es simplemente usar un f()
que se puede aplicar directamente a los elementos de la matriz. Por ejemplo, usando la matriz m
de la respuesta de @ adamleerich
m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2)
No hay ninguna razón para usar apply()
en el caso del ejemplo as.character()
. En cambio, podemos operar los elementos de m
como si fuera un vector ( realmente es uno) y reemplazarlos en el lugar :
> m[] <- as.character(m)
> m
[,1] [,2] [,3] [,4]
[1,] "1" "3" "5" "7"
[2,] "2" "4" "6" "8"
La primera parte de ese bloque es la clave aquí. m[]
fuerza a los elementos de m
a ser reemplazados por la salida de as.character()
, en lugar de sobrescribir m
con un vector de caracteres.
Entonces esa es la solución general para aplicar una función a cada elemento de una matriz.
Si uno realmente necesita usar un f()
que funcione en índices de filas y columnas, entonces escribiría un f()
usando row()
y 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
o uno que use outer()
como otros han mostrado. Si f()
no está vectorizado, entonces replantearé mi estrategia lo más posible, ya que existe una forma de escribir una versión verdaderamente vectorizada, y ii) una función que no está vectorizada no va a funcionar. escalar muy bien.
Esto no responde exactamente tu pregunta, pero la encontré al tratar de resolver una pregunta similar, así que te mostraré algo.
Supongamos que tiene una función que desea aplicar a cada elemento de una matriz que solo requiere una parte.
mydouble <- function(x) {
return(x+x)
}
Y di que tienes una matriz X,
> x=c(1,-2,-3,4)
> X=matrix(x,2,2)
> X
[,1] [,2]
[1,] 1 -3
[2,] -2 4
entonces haces esto:
res=mydouble(X)
Luego hará un doble de elemento de cada valor.
Sin embargo, si realiza la lógica en la función siguiente, recibirá una advertencia de que no está parametrizada y no se comportará como esperaba.
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
Pero si usa la función apply () puede usarla.
Por ejemplo:
> apply(X,c(1,2),myabs)
[,1] [,2]
[1,] 1 3
[2,] 2 4
Así que eso es genial, ¿verdad? Bueno, se descompone si tienes una función con dos o más parms. Digamos por ejemplo que tienes esto:
mymath <- function(x,y) {
if(x<0) {
return(-x*y)
} else {
return(x*y)
}
}
En este caso, usa la función apply (). Sin embargo, perderá la matriz, pero los resultados se calculan correctamente. Pueden ser reformados si así lo deseas.
> 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
No nos dijiste qué tipo de función quieres aplicar a cada elemento, pero creo que la única razón por la que funcionan los ejemplos en las otras respuestas es porque las funciones ya están vectorizadas. Si realmente desea aplicar una función a cada elemento, el outer
no le dará nada especial que la función no le haya dado. ¡Notarás que las respuestas ni siquiera pasaron una matriz al outer
!
¿Qué le parece seguir el comentario y el uso de @ Chase?
Por ejemplo, tengo la matriz
m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2)
Si quiero convertirlo en una matriz de caracteres, elemento por elemento (solo como ejemplo) podría hacerlo
apply(m, c(1,2), as.character)
Por supuesto, como as.character
ya está vectorizado, pero mi función especial my.special.function
no lo es. Solo toma un argumento, un elemento. No hay una forma directa de conseguir que el outer
trabaje con él. Pero, esto funciona
apply(m, c(1,2), my.special.function)
Sospecho que quieres 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
Eso produce una buena salida compacta. pero es posible que mapply
sea útil en otras situaciones. Es útil pensar mapply
como otra forma de hacer la misma operación para la que otros en esta página usan Vectorize
. mapply
es más general debido a la incapacidad Vectorize
para usar funciones "primitivas".
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
Probablemente no tenías la intención de proporcionar a la función lo que las funciones row () y col () habrían devuelto: Esto produce una matriz de 15 matrices (algo redundantes) 3 x 5:
> outer(row(mat), col(mat) , FUN=function(r,c) log(r+c) )
Usted puede estar pensando en 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
Claramente, se trata de una función de ejemplo bastante trivial, pero también puede proporcionar su propia función personalizada. Ver ?outer
.
Editar
Contrario al comentario a continuación, también puedes usar funciones outer
con funciones no vectorizadas ... vectorizándolas.
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