Je me demande s’il existe une fonction intégrée dans R qui applique une fonction à chaque élément de la matrice (bien entendu, la fonction devrait être calculée à partir des indices de la matrice). L'équivalent serait quelque chose comme ceci:
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)
}
En l'absence d'une telle fonction intégrée, quel est le meilleur moyen d'initialiser une matrice pour qu'elle contienne des valeurs obtenues en calculant une fonction arbitraire ayant pour paramètres des indices de matrice?
Je pense que vous voulez 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
Cela donne une belle sortie compacte. mais il est possible que mapply
soit utile dans d’autres situations. Il est utile de penser à mapply
comme à un autre moyen d'effectuer la même opération que celle utilisée par les autres utilisateurs de cette page sur Vectorize
. mapply
est plus général en raison de l'incapacité Vectorize
à utiliser des fonctions "primitives".
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
Vous n'avez probablement pas réellement voulu dire de fournir à la fonction ce que les fonctions row () et col () auraient renvoyé: Ceci produit un tableau de 15 matrices 3 x 5 (quelque peu redondantes):
> outer(row(mat), col(mat) , FUN=function(r,c) log(r+c) )
L’approche la plus simple est consiste simplement à utiliser une f()
pouvant être appliquée directement aux éléments de la matrice. Par exemple, en utilisant la matrice m
de la réponse de @ adamleerich
m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2)
Il n'y a aucune raison d'utiliser apply()
dans le cas de l'exemple as.character()
. Au lieu de cela, nous pouvons utiliser les éléments de m
comme s’il s’agissait d’un vecteur (it vraiment _ en est un) et remplacer in-situ:
> m[] <- as.character(m)
> m
[,1] [,2] [,3] [,4]
[1,] "1" "3" "5" "7"
[2,] "2" "4" "6" "8"
La première partie de ce bloc est la clé ici. m[]
force les éléments de m
à être remplacés par la sortie de as.character()
, plutôt que d'écraser m
par un vecteur de caractères.
Alors que est la solution générale pour appliquer une fonction à chaque élément d’une matrice.
S'il faut vraiment utiliser une f()
qui fonctionne avec les index de ligne et de colonne, j'écrirai une f()
à l'aide de row()
et de 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
ou ceux qui utilisent outer()
comme les autres l'ont montré. Si f()
n'est pas vectorisé, alors je repenserais ma stratégie autant que possible car i) est probablement un moyen d'écrire une version véritablement vectorisée, et ii) une fonction qui n'est pas vectorisée ne va pas très évoluer bien.
Vous ne nous avez pas indiqué le type de fonction que vous souhaitez appliquer à chaque élément, mais je pense que la seule raison pour laquelle les exemples des autres réponses fonctionnent est que les fonctions sont déjà vectorisées. Si vous voulez vraiment appliquer une fonction à chaque élément, outer
ne vous donnera rien de spécial que la fonction ne vous a pas déjà donné. Vous remarquerez que les réponses ne passent même pas une matrice à outer
!
Pourquoi ne pas suivre le commentaire de @ Chase et utiliser apply
.
Par exemple, j'ai la matrice
m <- matrix(c(1,2,3,4,5,6,7,8), nrow = 2)
Si je veux le transformer en matrice de caractères, élément par élément (à titre d'exemple), je pourrais le faire.
apply(m, c(1,2), as.character)
Bien sûr, as.character
est déjà vectorisé, mais ma fonction spéciale my.special.function
ne l’est pas. Cela ne prend qu'un argument, un élément. Il n’existe aucun moyen simple d’obtenir outer
avec. Mais ça marche
apply(m, c(1,2), my.special.function)
Vous pensez peut-être à 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
C'est clairement un exemple de fonction assez trivial, mais vous pouvez également fournir votre propre fonction personnalisée. Voir ?outer
.
Modifier
Contrairement au commentaire ci-dessous, vous pouvez également utiliser outer
avec des fonctions non vectorisées en .... les vectorisant!
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
Cela ne répond pas exactement à votre question, mais je l’ai trouvée en essayant de trouver une question similaire, alors je vais vous montrer quelque chose.
Supposons que vous ayez une fonction que vous souhaitez appliquer à chaque élément d'une matrice qui ne nécessite qu'une partie.
mydouble <- function(x) {
return(x+x)
}
Et dis que tu as une matrice X,
> x=c(1,-2,-3,4)
> X=matrix(x,2,2)
> X
[,1] [,2]
[1,] 1 -3
[2,] -2 4
alors vous faites ceci:
res=mydouble(X)
Ensuite, il fera un double élément par élément de chaque valeur.
Cependant, si vous utilisez la logique dans la fonction comme ci-dessous, vous recevrez un avertissement indiquant qu'elle n'est pas paramétrée et qu'elle ne se comporte pas comme prévu.
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
Mais si vous utilisez la fonction apply (), vous pouvez l'utiliser.
Par exemple:
> apply(X,c(1,2),myabs)
[,1] [,2]
[1,] 1 3
[2,] 2 4
Donc c'est génial, non? Eh bien, ça tombe en panne si vous avez une fonction avec deux parmes ou plus. Disons par exemple que vous avez ceci:
mymath <- function(x,y) {
if(x<0) {
return(-x*y)
} else {
return(x*y)
}
}
Dans ce cas, vous utilisez la fonction apply (). Cependant, la matrice sera perdue mais les résultats sont calculés correctement. Ils peuvent être réformés si vous le souhaitez.
> 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