Question

Supposons que j'ai n par 2 matrice et une fonction qui prend un 2-vecteur tel que l'un de ses arguments. Je voudrais appliquer la fonction à chaque ligne de la matrice et obtenir un vecteur n. Comment faire en R?

Par exemple, je voudrais calculer la densité d'une distribution standard 2D normale sur trois points:

bivariate.density(x = c(0, 0), mu = c(0, 0), sigma = c(1, 1), rho = 0){
    exp(-1/(2*(1-rho^2))*(x[1]^2/sigma[1]^2+x[2]^2/sigma[2]^2-2*rho*x[1]*x[2]/(sigma[1]*sigma[2]))) * 1/(2*pi*sigma[1]*sigma[2]*sqrt(1-rho^2))
}

out <- rbind(c(1, 2), c(3, 4), c(5, 6))

Comment appliquer la fonction à chaque rangée de out?

Comment transmettre des valeurs pour les autres arguments en plus des points à la fonction de la manière que vous spécifiez?

Était-ce utile?

La solution

Vous utilisez simplement la fonction apply():

R> M <- matrix(1:6, nrow=3, byrow=TRUE)
R> M
     [,1] [,2]
[1,]    1    2
[2,]    3    4
[3,]    5    6
R> apply(M, 1, function(x) 2*x[1]+x[2])
[1]  4 10 16
R> 

Cela prend une matrice et applique une fonction (bête) à chaque ligne. Vous passez des arguments supplémentaires à la fonction comme quatrième, cinquième, ... arguments à apply().

Autres conseils

Si vous voulez appliquer des fonctions communes telles que la somme ou la moyenne, vous devez utiliser rowSums ou rowMeans car ils sont plus rapides que l'approche de apply(data, 1, sum). Dans le cas contraire, le bâton avec apply(data, 1, fun). Vous pouvez passer des arguments supplémentaires après l'argument FUN (comme Dirk déjà suggéré):

set.seed(1)
m <- matrix(round(runif(20, 1, 5)), ncol=4)
diag(m) <- NA
m
     [,1] [,2] [,3] [,4]
[1,]   NA    5    2    3
[2,]    2   NA    2    4
[3,]    3    4   NA    5
[4,]    5    4    3   NA
[5,]    2    1    4    4

Ensuite, vous pouvez faire quelque chose comme ceci:

apply(m, 1, quantile, probs=c(.25,.5, .75), na.rm=TRUE)
    [,1] [,2] [,3] [,4] [,5]
25%  2.5    2  3.5  3.5 1.75
50%  3.0    2  4.0  4.0 3.00
75%  4.0    3  4.5  4.5 4.00

Voici un court exemple d'application d'une fonction à chaque rangée d'une matrice. (Ici, la fonction appliquée normalise chaque ligne à 1.)

Remarque:. Le résultat du apply() devait être Transposée en utilisant t() pour obtenir la même disposition que la matrice d'entrée A

A <- matrix(c(
  0, 1, 1, 2,
  0, 0, 1, 3,
  0, 0, 1, 3
), nrow = 3, byrow = TRUE)

t(apply(A, 1, function(x) x / sum(x) ))

Résultat:

     [,1] [,2] [,3] [,4]
[1,]    0 0.25 0.25 0.50
[2,]    0 0.00 0.25 0.75
[3,]    0 0.00 0.25 0.75

La première étape serait faire l'objet de fonction, puis l'appliquer. Si vous voulez un objet matrice qui a le même nombre de lignes, vous pouvez prédéfinir et utiliser l'objet sous forme [] comme illustré (sinon la valeur retournée sera simplifiée à un vecteur):

bvnormdens <- function(x=c(0,0),mu=c(0,0), sigma=c(1,1), rho=0){
     exp(-1/(2*(1-rho^2))*(x[1]^2/sigma[1]^2+
                           x[2]^2/sigma[2]^2-
                           2*rho*x[1]*x[2]/(sigma[1]*sigma[2]))) * 
     1/(2*pi*sigma[1]*sigma[2]*sqrt(1-rho^2))
     }
 out=rbind(c(1,2),c(3,4),c(5,6));

 bvout<-matrix(NA, ncol=1, nrow=3)
 bvout[] <-apply(out, 1, bvnormdens)
 bvout
             [,1]
[1,] 1.306423e-02
[2,] 5.931153e-07
[3,] 9.033134e-15

Si vous voulez utiliser autre que vos paramètres par défaut, l'appel doit inclure les arguments nommés après la fonction:

bvout[] <-apply(out, 1, FUN=bvnormdens, mu=c(-1,1), rho=0.6)

appliquer () peut également être utilisé sur des réseaux de dimension supérieure et l'argument de la marge peut être un vecteur, ainsi qu'un seul entier.

Appliquer fait bien le travail, mais il est assez lent. L'utilisation sapply et pourrait vapply être utile. Le rowwise de dplyr pourrait également être utile Voyons voir un exemple de la façon de faire produit sage ligne de toute trame de données.

a = data.frame(t(iris[1:10,1:3]))
vapply(a, prod, 0)
sapply(a, prod)

Notez que l'affectation à la variable avant d'utiliser vapply / sapply / apply est une bonne pratique car il réduit le temps beaucoup. Voyons voir les résultats de microbenchmark

a = data.frame(t(iris[1:10,1:3]))
b = iris[1:10,1:3]
microbenchmark::microbenchmark(
    apply(b, 1 , prod),
    vapply(a, prod, 0),
    sapply(a, prod) , 
    apply(iris[1:10,1:3], 1 , prod),
    vapply(data.frame(t(iris[1:10,1:3])), prod, 0),
    sapply(data.frame(t(iris[1:10,1:3])), prod) ,
    b %>%  rowwise() %>%
        summarise(p = prod(Sepal.Length,Sepal.Width,Petal.Length))
)

Avoir un regard attentif à la façon dont t () est utilisé

Une autre approche si vous souhaitez utiliser une partie de l'ensemble de données variant au lieu d'une seule valeur est d'utiliser rollapply(data, width, FUN, ...). L'utilisation d'un vecteur de largeurs vous permet d'appliquer une fonction sur une fenêtre variable de l'ensemble de données. Je l'ai utilisé cela pour construire une routine de filtrage adaptatif, mais il est très efficace.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top