Aplicar una función a cada fila de una matriz o un dataframe

Supongamos que tengo una matriz por 2 y una función que toma un 2-vector como uno de sus argumentos. Me gustaría aplicar la función a cada fila de la matriz y obtener un n-vector. ¿Cómo hacer esto en R?

Por ejemplo, me gustaría calcular la densidad de una distribución Normal estándar 2D en tres puntos:

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)) 

¿Cómo aplicar la función a cada fila de out ?

¿Cómo pasar valores para los otros argumentos además de los puntos a la función en la forma que especifique?

    Simplemente usa la función 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> 

    Esto toma una matriz y aplica una función (tonta) a cada fila. Usted pasa argumentos adicionales a la función como cuarto, quinto, … argumentos para apply() .

    En caso de que quiera aplicar funciones comunes como sum o media, debería usar rowSums o rowMeans ya que son más rápidos que el rowMeans de apply(data, 1, sum) . De lo contrario, quédate con apply(data, 1, fun) . Puede pasar argumentos adicionales después del argumento FUN (como ya sugirió Dirk):

     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 

    Entonces puedes hacer algo como esto:

     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 

    Aquí hay un pequeño ejemplo de cómo aplicar una función a cada fila de una matriz. (Aquí, la función aplicada normaliza cada fila a 1.)

    Nota: El resultado de apply() tuvo que ser transpuesto utilizando t() para obtener el mismo diseño que la matriz de entrada 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) )) 

    Resultado:

      [,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 

    El primer paso sería hacer el objeto de función, luego aplicarlo. Si desea un objeto de matriz que tenga el mismo número de filas, puede predefinirlo y usar el formulario de objeto [] como se ilustra (de lo contrario, el valor devuelto se simplificará a un vector):

     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 desea utilizar otros parámetros que no sean los predeterminados, la llamada debe incluir argumentos con nombre después de la función:

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

    apply () también se puede usar en matrices dimensionales superiores y el argumento MARGIN puede ser un vector así como un entero único.

    Aplicar hace bien el trabajo, pero es bastante lento. Usar sapply y vapply podría ser útil. El rowwise de dplyr también podría ser útil. Veamos un ejemplo de cómo hacer filas producto de cualquier dataframe.

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

    Tenga en cuenta que asignar a la variable antes de usar vapply / sapply / apply es una buena práctica ya que reduce mucho el tiempo. Veamos los resultados 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)) ) 

    Observe cuidadosamente cómo se usa t ()

    Otro enfoque si desea usar una porción variable del conjunto de datos en lugar de un único valor es usar rollapply(data, width, FUN, ...) . El uso de un vector de anchuras le permite aplicar una función en una ventana variable del conjunto de datos. Lo he usado para crear una rutina de filtrado adaptativo, aunque no es muy eficiente.