Pregunta

Siempre que quiero hacer algo "mapa" py en R, por lo general tratan de utilizar una función en la familia apply.

Sin embargo, nunca he entendido bien las diferencias entre ellos - cómo {sapply, lapply, etc.} aplicar la función a la entrada de entrada / agrupados, lo que la salida se verá así, o incluso lo que puede ser la entrada -. así que a menudo acaba de pasar por todos ellos hasta que consigo lo que quiero

Puede alguien explicar cómo utilizar la que uno cuando?

Mi actual (incompleta probablemente incorrecta /) es la comprensión ...

  1. sapply(vec, f): de entrada es un vector. salida es un vector / matriz, donde el elemento i es f(vec[i]), que le da una matriz si f tiene una salida de múltiples elementos

  2. lapply(vec, f):? Mismo que sapply, pero la producción es una lista

  3. apply(matrix, 1/2, f): entrada es una matriz. salida es un vector, donde el elemento i es f (fila / col i de la matriz)
  4. tapply(vector, grouping, f): salida es una matriz / matriz, donde un elemento de la matriz / array es el valor de f a una g agrupación del vector, y g es empujado a los nombres de fila / COL
  5. by(dataframe, grouping, f): dejar que sea una agrupación g. aplicar f a cada columna del grupo / trama de datos. bastante imprimir la agrupación y el valor de f en cada columna.
  6. aggregate(matrix, grouping, f):. Similares a by, pero en lugar de imprimir la salida bastante, palos agregados todo en una trama de datos

pregunta al margen:? Todavía tengo plyr o la forma no se aprende - habría plyr o reshape reemplazar la totalidad de éstos por completo

¿Fue útil?

Solución

R ha muchos * aplicar funciones que se describen hábilmente en los archivos de ayuda (por ejemplo ?apply). Hay suficiente de ellos, sin embargo, que los usuarios principiantes pueden tener dificultades para decidir cuál es el adecuado para su situación o incluso recordar a todos ellos. Pueden tener una sensación general de que "que debería usar una función * aplican aquí", pero puede ser difícil de mantener a todos derecho al principio.

A pesar de (dicho en otras respuestas) que gran parte de la funcionalidad de la familia * aplicarán está cubierta por el paquete plyr extremadamente popular, las funciones de base siguen siendo útiles y vale la pena conocer.

Esta respuesta es la intención de actuar como una especie de señal para los nuevos usuarios para ayudarles a dirigir a la correcta * aplicar la función para su problema particular. Tenga en cuenta, esto es no la intención de simplemente regurgitan o reemplazar la documentación R! La esperanza es que esta respuesta le ayuda a decidir qué * se aplica trajes función de su situación y entonces le corresponde a usted para investigar más a fondo. Con una excepción, no se abordarán las diferencias de rendimiento.

  • solicite - Cuando se desea aplicar una función a las filas o columnas de una matriz (y análogos de dimensiones superiores); No aconsejable en general para las tramas de datos, ya que coaccionar a una primera matriz.

    # Two dimensional matrix
    M <- matrix(seq(1,16), 4, 4)
    
    # apply min to rows
    apply(M, 1, min)
    [1] 1 2 3 4
    
    # apply max to columns
    apply(M, 2, max)
    [1]  4  8 12 16
    
    # 3 dimensional array
    M <- array( seq(32), dim = c(4,4,2))
    
    # Apply sum across each M[*, , ] - i.e Sum across 2nd and 3rd dimension
    apply(M, 1, sum)
    # Result is one-dimensional
    [1] 120 128 136 144
    
    # Apply sum across each M[*, *, ] - i.e Sum across 3rd dimension
    apply(M, c(1,2), sum)
    # Result is two-dimensional
         [,1] [,2] [,3] [,4]
    [1,]   18   26   34   42
    [2,]   20   28   36   44
    [3,]   22   30   38   46
    [4,]   24   32   40   48
    

    Si desea medios fila / columna o sumas para una matriz 2D, asegúrese de investigar la altamente optimizado, colMeans rápido como un rayo, rowMeans, colSums, rowSums.

  • lapply - Cuando se desea aplicar una función a cada elemento de una Lista a su vez y obtener una copia de la lista.

    Este es el caballo de batalla de muchos de los otros * Aplicar funciones. Pelar copias de su código y usted encontrará a menudo por debajo lapply.

    x <- list(a = 1, b = 1:3, c = 10:100) 
    lapply(x, FUN = length) 
    $a 
    [1] 1
    $b 
    [1] 3
    $c 
    [1] 91
    lapply(x, FUN = sum) 
    $a 
    [1] 1
    $b 
    [1] 6
    $c 
    [1] 5005
    
  • sapply - Cuando se desea aplicar una función a cada elemento de una Lista a su vez, pero desea un vector espalda, en lugar de una lista.

    Si usted se encuentra escribiendo unlist(lapply(...)), detenerse y considerar sapply.

    x <- list(a = 1, b = 1:3, c = 10:100)
    # Compare with above; a named vector, not a list 
    sapply(x, FUN = length)  
    a  b  c   
    1  3 91
    
    sapply(x, FUN = sum)   
    a    b    c    
    1    6 5005 
    

    En usos más avanzados de sapply intentará coaccionar a la dar lugar a una matriz multi-dimensional, si es apropiado. Por ejemplo, si nuestros devuelve las vectores de la misma longitud, sapply los utilizarán como columnas de una matriz:

    sapply(1:5,function(x) rnorm(3,x))
    

    Si nuestra función devuelve una matriz de 2 dimensiones, sapply hará esencialmente la misma cosa, el tratamiento de cada matriz devuelta como un único vector de largo:

    sapply(1:5,function(x) matrix(x,2,2))
    

    A menos que especificamos simplify = "array", en cuyo caso se utilizará las matrices individuales para construir una matriz multidimensional:

    sapply(1:5,function(x) matrix(x,2,2), simplify = "array")
    

    Cada uno de estos comportamientos es de contingente curso en nuestra función que devuelve vectores o matrices de la misma longitud o dimensión.

  • vapply - Cuando se desea utilizar sapply pero quizás necesita exprimir un poco más de velocidad de su código.

    Para vapply, que, básicamente, da R un ejemplo de qué clase de cosa su función devolverá, lo que puede ahorrar algo de tiempo coaccionar volvió valores para caber en un único vector atómica.

    x <- list(a = 1, b = 1:3, c = 10:100)
    #Note that since the advantage here is mainly speed, this
    # example is only for illustration. We're telling R that
    # everything returned by length() should be an integer of 
    # length 1. 
    vapply(x, FUN = length, FUN.VALUE = 0L) 
    a  b  c  
    1  3 91
    
  • mapply - Para cuando se tiene varias estructuras de datos (por ejemplo, vectores, listas) y que desea aplicar una función a los elementos 1st de cada uno, y luego la 2ª elementos de cada uno, etc., coaccionando el resultado a un vector / matriz como en sapply.

    Este es multivariado en el sentido de que su función debe aceptar múltiples argumentos.

    #Sums the 1st elements, the 2nd elements, etc. 
    mapply(sum, 1:5, 1:5, 1:5) 
    [1]  3  6  9 12 15
    #To do rep(1,4), rep(2,3), etc.
    mapply(rep, 1:4, 4:1)   
    [[1]]
    [1] 1 1 1 1
    
    [[2]]
    [1] 2 2 2
    
    [[3]]
    [1] 3 3
    
    [[4]]
    [1] 4
    
  • Mapa -. Una envoltura de mapply con SIMPLIFY = FALSE, por lo que está garantizado para devolver una lista

    Map(sum, 1:5, 1:5, 1:5)
    [[1]]
    [1] 3
    
    [[2]]
    [1] 6
    
    [[3]]
    [1] 9
    
    [[4]]
    [1] 12
    
    [[5]]
    [1] 15
    
  • rapply - Paracuando se desea aplicar una función a cada elemento de un lista anidada estructura, de forma recursiva.

    Para darle una idea de cómo es rapply raro, me olvidé del asunto al publicar por primera vez esta respuesta! Obviamente, estoy seguro que muchas personas lo utilizan, pero tu caso es distinto. rapply se ilustra mejor con una función definida por el usuario para aplicar:

    # Append ! to string, otherwise increment
    myFun <- function(x){
        if(is.character(x)){
          return(paste(x,"!",sep=""))
        }
        else{
          return(x + 1)
        }
    }
    
    #A nested list structure
    l <- list(a = list(a1 = "Boo", b1 = 2, c1 = "Eeek"), 
              b = 3, c = "Yikes", 
              d = list(a2 = 1, b2 = list(a3 = "Hey", b3 = 5)))
    
    
    # Result is named vector, coerced to character          
    rapply(l, myFun)
    
    # Result is a nested list like l, with values altered
    rapply(l, myFun, how="replace")
    
  • tapply - Para cuando se desea aplicar una función a subconjuntos de un vector y los subconjuntos están definidos por algún otro vector, por lo general una factor.

    El garbanzo negro de la familia * aplicar, de todo tipo. el uso del archivo de ayuda de la frase "matriz irregular" puede ser un poco confuso , pero en realidad es bastante simple.

    A vector:

    x <- 1:20
    

    factor A (de la misma longitud!) Grupos que definen:

    y <- factor(rep(letters[1:5], each = 4))
    

    Sume los valores en x dentro de cada subgrupo definido por y:

    tapply(x, y, sum)  
     a  b  c  d  e  
    10 26 42 58 74 
    

    ejemplos más complejos puede ser manejado donde se definen los subgrupos por las combinaciones únicas de una lista de varios factores. tapply es similar en espíritu a los split-aplicarán combinar funciones que son común en R (aggregate, by, ave, ddply, etc.) Por lo tanto su estado de ovejas negro.

Otros consejos

En la nota al margen, aquí es cómo las diversas funciones plyr corresponden a las funciones de base *apply (de la intro de documento plyr del plyr página web http://had.co.nz/plyr/ )

Base function   Input   Output   plyr function 
---------------------------------------
aggregate        d       d       ddply + colwise 
apply            a       a/l     aaply / alply 
by               d       l       dlply 
lapply           l       l       llply  
mapply           a       a/l     maply / mlply 
replicate        r       a/l     raply / rlply 
sapply           l       a       laply 

Uno de los objetivos de plyr es proporcionar convenciones de nomenclatura coherentes para cada una de las funciones, la codificación de los tipos de datos de entrada y de salida en el nombre de la función. También proporciona la consistencia de la producción, en que la producción de dlply() es fácilmente aceptable para ldply() para producir una salida útil, etc.

Conceptualmente, el aprendizaje plyr es más difícil que la comprensión de las funciones *apply base.

funciones

plyr y reshape han reemplazado casi todas estas funciones en cada uno de mis días utilización. Pero, también a partir del documento Introducción a plyr:

  

funciones relacionadas tapply y sweep haber función en plyr no correspondiente, y siguen siendo útiles. merge es útil para combinar resúmenes con los datos originales.

A partir de la diapositiva 21 de http://www.slideshare.net/ -analítico-estrategia plyr-one-datos Hadley / :

aplicar, sapply, lapply, por, agregado

(Con suerte, está claro que corresponde a apply @ aaply y aggregate corresponde de Hadley a @ diapositivas de Hadley ddply etc. 20 de la misma slideshare aclarará si no la obtiene de esta imagen.)

(a la izquierda es la entrada, en la parte superior es de salida)

En primer lugar empezar con excelente respuesta de Joran -. Nada dudoso que pueda mejor

A continuación, los siguientes pueden ayudar mnemotécnicos para recordar las diferencias entre cada uno. Mientras que algunos son obvios, otros pueden ser menos --- para estos encontrará justificación en las discusiones de Joran.

Mnemónicos

  • lapply es una lista solicite que actúa en una lista o vector y devuelve una lista.
  • sapply es un sencilla lapply (por defecto de función para devolver un vector o matriz cuando sea posible)
  • vapply es un verified aplicar (permite que el tipo de objeto de retorno que se especificó previamente)
  • rapply es un recursiva solicitar listas anidadas, listas es decir, dentro de las listas
  • tapply es un etiquetada de aplicación cuando las etiquetas identifican los subconjuntos
  • apply es genérico : se aplica una función a las filas o columnas de una matriz (o, más generalmente, a las dimensiones de una matriz)

Construyendo el derecho de fondo

Si se utiliza la familia apply todavía se siente un poco ajeno a ti, entonces podría ser que se está perdiendo un punto clave de vista.

Estos dos artículos pueden ayudar. Ellos proporcionan los antecedentes necesarios para motivar a los técnicas de programación funcionales que están siendo proporcionados por la familia apply de funciones.

Los usuarios de Lisp reconocerá el paradigma de inmediato. Si no está familiarizado con Lisp, una vez que su cabeza alrededor de FP, se le han ganado un punto de vista para su uso en investigación de gran alcance -. apply y hará mucho más sentido

Desde que me di cuenta de que (los muy excelentes) respuestas de esta entrada falta de by y aggregate explicaciones. Aquí está mi contribución.

por

La función by, como se indica en la documentación puede ser, sin embargo, como un "contenedor" para tapply. El poder de by surge cuando queremos calcular una tarea que tapply no puede manejar. Un ejemplo es este código:

ct <- tapply(iris$Sepal.Width , iris$Species , summary )
cb <- by(iris$Sepal.Width , iris$Species , summary )

 cb
iris$Species: setosa
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.300   3.200   3.400   3.428   3.675   4.400 
-------------------------------------------------------------- 
iris$Species: versicolor
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.000   2.525   2.800   2.770   3.000   3.400 
-------------------------------------------------------------- 
iris$Species: virginica
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.200   2.800   3.000   2.974   3.175   3.800 


ct
$setosa
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.300   3.200   3.400   3.428   3.675   4.400 

$versicolor
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.000   2.525   2.800   2.770   3.000   3.400 

$virginica
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.200   2.800   3.000   2.974   3.175   3.800 

Si es la impresión de estos dos objetos, ct y cb, que "esencialmente" tiene los mismos resultados y las únicas diferencias están en la forma en que se muestran y los diferentes atributos class, by, respectivamente, para cb y array para ct.

Como he dicho, el poder de by surge cuando no podemos utilizar tapply; El código siguiente es un ejemplo:

 tapply(iris, iris$Species, summary )
Error in tapply(iris, iris$Species, summary) : 
  arguments must have same length

R dice que los argumentos deben tener las mismas longitudes, decir "queremos calcular la summary de toda variable en iris a lo largo del factor de Species":. R, pero no pueden hacerlo porque no sabe cómo manejar

Con la función by R despachar un método específico para la clase data frame y luego dejar que la función summary funciona incluso si la longitud del primer argumento (y el tipo también) son diferentes.

bywork <- by(iris, iris$Species, summary )

bywork
iris$Species: setosa
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width          Species  
 Min.   :4.300   Min.   :2.300   Min.   :1.000   Min.   :0.100   setosa    :50  
 1st Qu.:4.800   1st Qu.:3.200   1st Qu.:1.400   1st Qu.:0.200   versicolor: 0  
 Median :5.000   Median :3.400   Median :1.500   Median :0.200   virginica : 0  
 Mean   :5.006   Mean   :3.428   Mean   :1.462   Mean   :0.246                  
 3rd Qu.:5.200   3rd Qu.:3.675   3rd Qu.:1.575   3rd Qu.:0.300                  
 Max.   :5.800   Max.   :4.400   Max.   :1.900   Max.   :0.600                  
-------------------------------------------------------------- 
iris$Species: versicolor
  Sepal.Length    Sepal.Width     Petal.Length   Petal.Width          Species  
 Min.   :4.900   Min.   :2.000   Min.   :3.00   Min.   :1.000   setosa    : 0  
 1st Qu.:5.600   1st Qu.:2.525   1st Qu.:4.00   1st Qu.:1.200   versicolor:50  
 Median :5.900   Median :2.800   Median :4.35   Median :1.300   virginica : 0  
 Mean   :5.936   Mean   :2.770   Mean   :4.26   Mean   :1.326                  
 3rd Qu.:6.300   3rd Qu.:3.000   3rd Qu.:4.60   3rd Qu.:1.500                  
 Max.   :7.000   Max.   :3.400   Max.   :5.10   Max.   :1.800                  
-------------------------------------------------------------- 
iris$Species: virginica
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width          Species  
 Min.   :4.900   Min.   :2.200   Min.   :4.500   Min.   :1.400   setosa    : 0  
 1st Qu.:6.225   1st Qu.:2.800   1st Qu.:5.100   1st Qu.:1.800   versicolor: 0  
 Median :6.500   Median :3.000   Median :5.550   Median :2.000   virginica :50  
 Mean   :6.588   Mean   :2.974   Mean   :5.552   Mean   :2.026                  
 3rd Qu.:6.900   3rd Qu.:3.175   3rd Qu.:5.875   3rd Qu.:2.300                  
 Max.   :7.900   Max.   :3.800   Max.   :6.900   Max.   :2.500     

funciona de hecho y el resultado es muy sorprendente. Es un objeto de la clase by que junto Species (por ejemplo, para cada uno de ellos) calcula la summary de cada variable.

Tenga en cuenta que si el primer argumento es un data frame, la función despachada debe tener un método para esa clase de objetos. Por ejemplo, es que utilice este código con la función mean tendremos el código que no tiene ningún sentido en absoluto:

 by(iris, iris$Species, mean)
iris$Species: setosa
[1] NA
------------------------------------------- 
iris$Species: versicolor
[1] NA
------------------------------------------- 
iris$Species: virginica
[1] NA
Warning messages:
1: In mean.default(data[x, , drop = FALSE], ...) :
  argument is not numeric or logical: returning NA
2: In mean.default(data[x, , drop = FALSE], ...) :
  argument is not numeric or logical: returning NA
3: In mean.default(data[x, , drop = FALSE], ...) :
  argument is not numeric or logical: returning NA

TOTAL

aggregate puede ser visto como otro de una manera diferente de uso tapply si lo usamos de tal manera.

at <- tapply(iris$Sepal.Length , iris$Species , mean)
ag <- aggregate(iris$Sepal.Length , list(iris$Species), mean)

 at
    setosa versicolor  virginica 
     5.006      5.936      6.588 
 ag
     Group.1     x
1     setosa 5.006
2 versicolor 5.936
3  virginica 6.588

Las dos diferencias inmediatos son que el segundo argumento de aggregate debe es una lista mientras tapply puede (no es obligatorio) una lista y que la salida de aggregate es una trama de datos mientras que el uno de tapply es un array.

El poder de aggregate es que se puede manejar fácilmente subconjuntos de los datos con argumento subset y que tiene métodos para objetos ts y formula también.

Estos elementos hacen aggregate más fácil de trabajar que tapply en algunas situaciones. He aquí algunos ejemplos (disponibles en la documentación):

ag <- aggregate(len ~ ., data = ToothGrowth, mean)

 ag
  supp dose   len
1   OJ  0.5 13.23
2   VC  0.5  7.98
3   OJ  1.0 22.70
4   VC  1.0 16.77
5   OJ  2.0 26.06
6   VC  2.0 26.14

puede lograr lo mismo con tapply pero la sintaxis es un poco más difícil y la salida (en algunas circunstancias) menos legible:

att <- tapply(ToothGrowth$len, list(ToothGrowth$dose, ToothGrowth$supp), mean)

 att
       OJ    VC
0.5 13.23  7.98
1   22.70 16.77
2   26.06 26.14

Hay otros momentos en los que no podemos utilizar by o tapply y tenemos que utilizar aggregate.

 ag1 <- aggregate(cbind(Ozone, Temp) ~ Month, data = airquality, mean)

 ag1
  Month    Ozone     Temp
1     5 23.61538 66.73077
2     6 29.44444 78.22222
3     7 59.11538 83.88462
4     8 59.96154 83.96154
5     9 31.44828 76.89655

No podemos obtener el resultado anterior con tapply en una llamada, pero tenemos que calcular la media a lo largo de Month para cada elemento y luego combinarlas (también en cuenta que tenemos que llamar a la na.rm = TRUE, debido a que los métodos formula de la función aggregate tiene por defecto, el na.action = na.omit):

ta1 <- tapply(airquality$Ozone, airquality$Month, mean, na.rm = TRUE)
ta2 <- tapply(airquality$Temp, airquality$Month, mean, na.rm = TRUE)

 cbind(ta1, ta2)
       ta1      ta2
5 23.61538 65.54839
6 29.44444 79.10000
7 59.11538 83.90323
8 59.96154 83.96774
9 31.44828 76.90000

mientras que con by que simplemente no podemos lograr que, de hecho, la siguiente llamada a la función devuelve un error (pero muy probablemente se relaciona con la función suministrado, mean):

by(airquality[c("Ozone", "Temp")], airquality$Month, mean, na.rm = TRUE)

Otras veces los resultados son los mismos y las diferencias son sólo en la clase (y luego la forma en que se muestra / impreso y no sólo - ejemplo, cómo al subconjunto IT) objeto:

byagg <- by(airquality[c("Ozone", "Temp")], airquality$Month, summary)
aggagg <- aggregate(cbind(Ozone, Temp) ~ Month, data = airquality, summary)

El código anterior lograr el mismo objetivo y resultados, lo que en algunos puntos herramienta a utilizar es sólo una cuestión de gustos y necesidades personales; los dos objetos anteriores tienen necesidades muy diferentes en términos de creación de subconjuntos.

Hay un montón de grandes respuestas que discuten las diferencias en los casos de uso para cada función. Ninguno de la respuesta discutir las diferencias en el rendimiento. Eso causa razonable diversas funciones espera que varios terminales de entrada y de salida produce diversos, pero la mayoría de ellos tienen un objetivo general común para evaluar por ciclos / grupos. Mi respuesta va a centrarse en el rendimiento. Debido a por encima de la creación de entrada a partir de los vectores se incluye en el tiempo, también la función apply no se mide.

I han probado dos funciones diferentes sum y length a la vez. Volumen evaluados es de 50M en la entrada y en la salida 50K. También he incluido dos paquetes actualmente populares que no han sido ampliamente utilizados en el momento cuando se le preguntó pregunta, data.table y dplyr. Ambos son definitivamente vale la pena mirar si está destinado para un rendimiento bueno.

library(dplyr)
library(data.table)
set.seed(123)
n = 5e7
k = 5e5
x = runif(n)
grp = sample(k, n, TRUE)

timing = list()

# sapply
timing[["sapply"]] = system.time({
    lt = split(x, grp)
    r.sapply = sapply(lt, function(x) list(sum(x), length(x)), simplify = FALSE)
})

# lapply
timing[["lapply"]] = system.time({
    lt = split(x, grp)
    r.lapply = lapply(lt, function(x) list(sum(x), length(x)))
})

# tapply
timing[["tapply"]] = system.time(
    r.tapply <- tapply(x, list(grp), function(x) list(sum(x), length(x)))
)

# by
timing[["by"]] = system.time(
    r.by <- by(x, list(grp), function(x) list(sum(x), length(x)), simplify = FALSE)
)

# aggregate
timing[["aggregate"]] = system.time(
    r.aggregate <- aggregate(x, list(grp), function(x) list(sum(x), length(x)), simplify = FALSE)
)

# dplyr
timing[["dplyr"]] = system.time({
    df = data_frame(x, grp)
    r.dplyr = summarise(group_by(df, grp), sum(x), n())
})

# data.table
timing[["data.table"]] = system.time({
    dt = setnames(setDT(list(x, grp)), c("x","grp"))
    r.data.table = dt[, .(sum(x), .N), grp]
})

# all output size match to group count
sapply(list(sapply=r.sapply, lapply=r.lapply, tapply=r.tapply, by=r.by, aggregate=r.aggregate, dplyr=r.dplyr, data.table=r.data.table), 
       function(x) (if(is.data.frame(x)) nrow else length)(x)==k)
#    sapply     lapply     tapply         by  aggregate      dplyr data.table 
#      TRUE       TRUE       TRUE       TRUE       TRUE       TRUE       TRUE 

# print timings
as.data.table(sapply(timing, `[[`, "elapsed"), keep.rownames = TRUE
              )[,.(fun = V1, elapsed = V2)
                ][order(-elapsed)]
#          fun elapsed
#1:  aggregate 109.139
#2:         by  25.738
#3:      dplyr  18.978
#4:     tapply  17.006
#5:     lapply  11.524
#6:     sapply  11.326
#7: data.table   2.686

Es quizás vale la pena mencionar ave. ave es el primo de usar de tapply. Devuelve resultados en una forma que se puede conectar la espalda recta en su trama de datos.

dfr <- data.frame(a=1:20, f=rep(LETTERS[1:5], each=4))
means <- tapply(dfr$a, dfr$f, mean)
##  A    B    C    D    E 
## 2.5  6.5 10.5 14.5 18.5 

## great, but putting it back in the data frame is another line:

dfr$m <- means[dfr$f]

dfr$m2 <- ave(dfr$a, dfr$f, FUN=mean) # NB argument name FUN is needed!
dfr
##   a f    m   m2
##   1 A  2.5  2.5
##   2 A  2.5  2.5
##   3 A  2.5  2.5
##   4 A  2.5  2.5
##   5 B  6.5  6.5
##   6 B  6.5  6.5
##   7 B  6.5  6.5
##   ...

No hay nada en el paquete base que funciona como ave de tramas de datos enteros (como by es como tapply de tramas de datos). Pero se puede eludir que:

dfr$foo <- ave(1:nrow(dfr), dfr$f, FUN=function(x) {
    x <- dfr[x,]
    sum(x$m*x$m2)
})
dfr
##     a f    m   m2    foo
## 1   1 A  2.5  2.5    25
## 2   2 A  2.5  2.5    25
## 3   3 A  2.5  2.5    25
## ...

A pesar de todas las grandes respuestas aquí, hay 2 funciones más básicas que merecen ser mencionados, la función outer útil y la función eapply oscura

exterior

outer es una función muy útil oculta como uno más mundanas. Si usted lee la ayuda de outer su descripción dice:

The outer product of the arrays X and Y is the array A with dimension  
c(dim(X), dim(Y)) where element A[c(arrayindex.x, arrayindex.y)] =   
FUN(X[arrayindex.x], Y[arrayindex.y], ...).

, que hace que parezca que esto sólo es útil para las cosas de tipo de álgebra lineal. Sin embargo, puede ser utilizado tanto como mapply para aplicar una función de dos vectores de insumos. La diferencia es que mapply se aplicará la función de los dos primeros elementos y luego el segundo dos etc, mientras que outer se aplicará la función para cada combinación de un elemento del primer vector y una de la segunda. Por ejemplo:

 A<-c(1,3,5,7,9)
 B<-c(0,3,6,9,12)

mapply(FUN=pmax, A, B)

> mapply(FUN=pmax, A, B)
[1]  1  3  6  9 12

outer(A,B, pmax)

 > outer(A,B, pmax)
      [,1] [,2] [,3] [,4] [,5]
 [1,]    1    3    6    9   12
 [2,]    3    3    6    9   12
 [3,]    5    5    6    9   12
 [4,]    7    7    7    9   12
 [5,]    9    9    9    9   12

Yo personalmente he utilizado esto cuando tengo un vector de valores y un vector de condiciones y deseo de ver que cumplen las condiciones de la cual los valores.

eapply

eapply es como lapply excepto que en lugar de aplicar una función a cada elemento en una lista, se aplica una función a cada elemento en un entorno. Por ejemplo, si usted quiere encontrar una lista de funciones definidas por el usuario en el entorno global:

A<-c(1,3,5,7,9)
B<-c(0,3,6,9,12)
C<-list(x=1, y=2)
D<-function(x){x+1}

> eapply(.GlobalEnv, is.function)
$A
[1] FALSE

$B
[1] FALSE

$C
[1] FALSE

$D
[1] TRUE 

Francamente yo no uso mucho esto, pero si usted está construyendo una gran cantidad de paquetes o crear una gran cantidad de ambientes que puede ser útil.

Recientemente he descubierto la función sweep más útil y agregarlo aquí en aras de la exhaustividad:

barrido

La idea básica es la de barrido a través de una serie de fila o columna-sabia y devolver una matriz modificada. Un ejemplo aclarará esto (fuente: datacamp ) :

Digamos que usted tiene una matriz y desea estandarizar que por columnas:

dataPoints <- matrix(4:15, nrow = 4)

# Find means per column with `apply()`
dataPoints_means <- apply(dataPoints, 2, mean)

# Find standard deviation with `apply()`
dataPoints_sdev <- apply(dataPoints, 2, sd)

# Center the points 
dataPoints_Trans1 <- sweep(dataPoints, 2, dataPoints_means,"-")
print(dataPoints_Trans1)
##      [,1] [,2] [,3]
## [1,] -1.5 -1.5 -1.5
## [2,] -0.5 -0.5 -0.5
## [3,]  0.5  0.5  0.5
## [4,]  1.5  1.5  1.5
# Return the result
dataPoints_Trans1
##      [,1] [,2] [,3]
## [1,] -1.5 -1.5 -1.5
## [2,] -0.5 -0.5 -0.5
## [3,]  0.5  0.5  0.5
## [4,]  1.5  1.5  1.5
# Normalize
dataPoints_Trans2 <- sweep(dataPoints_Trans1, 2, dataPoints_sdev, "/")

# Return the result
dataPoints_Trans2
##            [,1]       [,2]       [,3]
## [1,] -1.1618950 -1.1618950 -1.1618950
## [2,] -0.3872983 -0.3872983 -0.3872983
## [3,]  0.3872983  0.3872983  0.3872983
## [4,]  1.1618950  1.1618950  1.1618950

Nota: para este ejemplo sencillo el mismo resultado, por supuesto, puede lograrse más fácilmente por
apply(dataPoints, 2, scale)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top