Cada vez que quiero hacer algo "map" py en R, generalmente trato de usar una función en la apply
familia.
Sin embargo, nunca he entendido bien las diferencias entre ellos - cómo { sapply
, lapply
, etc.} se aplica a la función del / de entrada agrupados de entrada, lo que la salida se verá así, o incluso lo que puede ser la entrada - así que a menudo solo revísalos hasta que consiga lo que quiero.
¿Alguien puede explicar cómo usar cuál cuando?
Mi comprensión actual (probablemente incorrecta / incompleta) es ...
sapply(vec, f)
: la entrada es un vector. La salida es un vector / matriz, dondei
está el elementof(vec[i])
, dándole una matriz sif
tiene una salida de elementos múltipleslapply(vec, f)
: igual quesapply
, pero la salida es una lista?apply(matrix, 1/2, f)
: la entrada es una matriz. la salida es un vector, donde el elementoi
es f (fila / col i de la matriz)tapply(vector, grouping, f)
: la salida es una matriz / matriz, donde un elemento en la matriz / matriz es el valor def
una agrupacióng
del vector yg
se empuja a los nombres de fila / columnaby(dataframe, grouping, f)
: dejag
ser una agrupación. aplicarf
a cada columna del grupo / marco de datos. imprima bastante la agrupación y el valor def
en cada columna.aggregate(matrix, grouping, f)
: similar aby
, pero en lugar de imprimir bastante la salida, el agregado pega todo en un marco de datos.
Cuestión lado: Todavía tengo plyr o la forma no se aprende - habría plyr
o reshape
reemplazar todos ellos por completo?
*apply()
yby
. plyr (al menos para mí) parece mucho más coherente en el sentido de que siempre sé exactamente qué formato de datos espera y qué es lo que escupirá. Eso me ahorra mucha molestia.doBy
y las capacidades de selección y aplicación dedata.table
.sapply
es sololapply
con la adición desimplify2array
en la salida.apply
coacciona al vector atómico, pero la salida puede ser vector o lista.by
divide los marcos de datos en subcuadros de datos, pero no se usaf
en columnas por separado. Solo si hay un método para la clase 'data.frame' podríaf
aplicarse por columnaby
.aggregate
es genérico, por lo que existen diferentes métodos para diferentes clases del primer argumento.Respuestas:
R tiene muchas * funciones de aplicación que se describen hábilmente en los archivos de ayuda (por ejemplo
?apply
). Sin embargo, hay suficientes de ellos para que el uso inicial de los R tenga dificultades para decidir cuál es el adecuado para su situación o incluso para recordarlos a todos. Pueden tener un sentido general de que "Debería estar usando una función * apply aquí", pero puede ser difícil mantenerlos todos rectos al principio.A pesar del hecho (señalado en otras respuestas) de que gran parte de la funcionalidad de la familia * apply está cubierta por el
plyr
paquete extremadamente popular , las funciones básicas siguen siendo útiles y vale la pena conocerlas.Esta respuesta está destinada a actuar como una especie de señal para los nuevos useRs para ayudarlos a dirigirlos a la función * * correcta para su problema particular. ¡Tenga en cuenta que esto no pretende simplemente regurgitar o reemplazar la documentación de R! La esperanza es que esta respuesta lo ayude a decidir qué función de aplicación * se adapta a su situación y luego depende de usted investigarla más a fondo. Con una excepción, no se abordarán las diferencias de rendimiento.
aplicar : cuando desea aplicar una función a las filas o columnas de una matriz (y análogos de dimensiones superiores); generalmente no es aconsejable para marcos de datos, ya que primero se convertirá en una matriz.
Si desea que los medios de fila / columna o sumas de dinero por una matriz 2D, asegúrese de investigar la altamente optimizado, rápido como un rayo
colMeans
,rowMeans
,colSums
,rowSums
.lapply : cuando desea aplicar una función a cada elemento de una lista y recuperar una lista.
Este es el caballo de batalla de muchas de las otras * funciones de aplicación. Despegue su código y con frecuencia lo encontrará
lapply
debajo.sapply : cuando desea aplicar una función a cada elemento de una lista a la vez, pero desea recuperar un vector , en lugar de una lista.
Si te encuentras escribiendo
unlist(lapply(...))
, detente y considerasapply
.En usos más avanzados
sapply
, intentará forzar el resultado a una matriz multidimensional, si corresponde. Por ejemplo, si nuestra función devuelve vectores de la misma longitud,sapply
los usará como columnas de una matriz:Si nuestra función devuelve una matriz bidimensional,
sapply
hará esencialmente lo mismo, tratando cada matriz devuelta como un único vector largo:A menos que especifiquemos
simplify = "array"
, en cuyo caso usará las matrices individuales para construir una matriz multidimensional:Por supuesto, cada uno de estos comportamientos depende de que nuestra función devuelva vectores o matrices de la misma longitud o dimensión.
vapply : cuando desee usarlo,
sapply
pero tal vez necesite exprimir un poco más la velocidad de su código.Para
vapply
, que, básicamente, da R un ejemplo de qué tipo de cosa que su función devolverá, que puede ahorrar algunos valores devueltos coaccionar tiempo para encajar en un único vector atómica.mapply : para cuando tiene varias estructuras de datos (por ejemplo, vectores, listas) y desea aplicar una función a los primeros elementos de cada uno, y luego a los segundos elementos de cada uno, etc., coaccionando el resultado a un vector / matriz como en
sapply
.Esto es multivariante en el sentido de que su función debe aceptar múltiples argumentos.
Mapa : un contenedor
mapply
con elSIMPLIFY = FALSE
que se garantiza que devolverá una lista.rapply : para cuando desea aplicar una función a cada elemento de una estructura de lista anidada , de forma recursiva.
Para darle una idea de lo poco común que
rapply
es, ¡lo olvidé la primera vez que publiqué esta respuesta! Obviamente, estoy seguro de que muchas personas lo usan, pero YMMV.rapply
se ilustra mejor con una función definida por el usuario para aplicar:tapply : para cuando desea aplicar una función a subconjuntos de un vector y los subconjuntos están definidos por algún otro vector, generalmente un factor.
Las ovejas negras de la * familia aplican, de algún tipo. El uso del archivo de ayuda de la frase "matriz irregular" puede ser un poco confuso , pero en realidad es bastante simple.
Un vector:
Un factor (¡de la misma longitud!) Que define grupos:
Sume los valores
x
dentro de cada subgrupo definido pory
:Se pueden manejar ejemplos más complejos donde los subgrupos están definidos por las combinaciones únicas de una lista de varios factores.
tapply
es similar en espíritu a la fracción de aplicar-combinar funciones que son comunes en R (aggregate
,by
,ave
,ddply
, etc.) Por lo tanto su estado ovejas negro.fuente
by
es puramente dividido yaggregate
estátapply
en sus núcleos. Creo que las ovejas negras son un excelente tejido.aggregate
yby
también? (Por fin entiendo ellos después de su descripción !, pero son bastante comunes, por lo que podría ser útil para separar y tienen algunos ejemplos específicos para esas dos funciones.)aggregate
, si bien ,by
etc. se basan en * aplicar funciones, la forma en que enfoca su uso es lo suficientemente diferente desde la perspectiva de los usuarios que deberían resumirse en una respuesta separada. Puedo intentarlo si tengo tiempo, o tal vez alguien más me gane y gane mi voto positivo.?Map
como pariente demapply
data.frame
s son una parte absolutamente central de R y, comolist
objeto, se manipulan con frecuencia utilizandolapply
particularmente. También actúan como contenedores para agrupar vectores / factores de muchos tipos en un conjunto de datos rectangular tradicional. Si biendata.table
yplyr
podrían agregar un cierto tipo de sintaxis que algunos podrían encontrar más cómodo, se están extendiendo y actuando sobredata.frame
s respectivamente.En la nota al margen, así es como las diversas
plyr
funciones corresponden a las*apply
funciones base (de la introducción al documento de plyr de la página web de plyr http://had.co.nz/plyr/ )Uno de los objetivos de
plyr
es proporcionar convenciones de nomenclatura consistentes para cada una de las funciones, codificando los tipos de datos de entrada y salida en el nombre de la función. También proporciona consistencia en la salida, ya que la salida dedlply()
es fácilmente transitableldply()
para producir resultados útiles, etc.Conceptualmente, el aprendizaje
plyr
no es más difícil que comprender las*apply
funciones básicas .plyr
y lasreshape
funciones han reemplazado a casi todas estas funciones en mi uso diario. Pero, también del documento de Introducción a Plyr:fuente
*apply()
familia de funciones. Para mí,ddply()
era muy intuitivo ya que estaba familiarizado con las funciones de agregación de SQL.ddply()
se convirtió en mi martillo para resolver muchos problemas, algunos de los cuales podrían haberse resuelto mejor con otros comandos.plyr
funciones es similar a las*apply
funciones, por lo que si puedes hacer una, puedes hacer la otra, pero lasplyr
funciones son más fáciles de recordar. ¡Pero estoy totalmente de acuerdo con elddply()
martillo!join()
función que realiza tareas similares a fusionar. Quizás sea más importante mencionarlo en el contexto de plyr.eapply
vapply
y las desventajas desapply
. Una de las principales ventajasvapply
es que impone el tipo y la longitud de salida, por lo que terminará con la salida esperada exacta o un error informativo. Por otro lado,sapply
intentaremos simplificar el resultado siguiendo reglas que no siempre son obvias, y de lo contrario recurrirán a una lista. Por ejemplo, tratar de predecir el tipo de salida de esto producirá:sapply(list(1:5, 6:10, matrix(1:4, 2)), function(x) head(x, 1))
. ¿Qué hay desapply(list(matrix(1:4, 2), matrix(1:4, 2)), ...)
?De la diapositiva 21 de http://www.slideshare.net/hadley/plyr-one-data-analytic-strategy :
(Con suerte, está claro que
apply
corresponde a @ Hadleyaaply
yaggregate
corresponde a @ Hadley,ddply
etc. La diapositiva 20 de la misma diapositiva se aclarará si no la obtiene de esta imagen).(a la izquierda se ingresa, en la parte superior se emite)
fuente
Primero comience con la excelente respuesta de Joran : dudoso cualquier cosa puede mejorar eso.
Entonces, los siguientes mnemónicos pueden ayudar a recordar las distinciones entre cada uno. Si bien algunos son obvios, otros pueden ser menos: para estos, encontrará justificación en las discusiones de Joran.
Mnemotécnica
lapply
es una aplicación de lista que actúa en una lista o vector y devuelve una lista.sapply
es simplelapply
(la función predeterminada es devolver un vector o matriz cuando sea posible)vapply
es una aplicación verificada (permite especificar previamente el tipo de objeto de retorno)rapply
es una solicitud recursiva para listas anidadas, es decir, listas dentro de listastapply
es una aplicación etiquetada donde las etiquetas identifican los subconjuntosapply
es genérico : aplica una función a las filas o columnas de una matriz (o, más generalmente, a las dimensiones de una matriz)Construyendo el fondo correcto
Si usar la
apply
familia todavía te resulta un poco extraño, entonces es posible que te estés perdiendo un punto de vista clave.Estos dos artículos pueden ayudar. Proporcionan los antecedentes necesarios para motivar las técnicas de programación funcional que proporciona la
apply
familia de funciones.Los usuarios de Lisp reconocerán el paradigma de inmediato. Si no está familiarizado con Lisp, una vez que comprenda FP, habrá obtenido un poderoso punto de vista para usar en R, y
apply
tendrá mucho más sentido.fuente
Desde que me di cuenta de que (los muy excelentes) respuestas de esta entrada falta de
by
yaggregate
explicaciones. Aquí está mi contribución.POR
Sin
by
embargo, la función, como se indica en la documentación, puede ser un "contenedor" paratapply
. El poder deby
surge cuando queremos calcular una tarea quetapply
no puede manejar. Un ejemplo es este código:Si imprimimos estos dos objetos,
ct
ycb
"esencialmente" tenemos los mismos resultados y las únicas diferencias están en cómo se muestran y los diferentesclass
atributos, respectivamenteby
paracb
yarray
paract
.Como he dicho, el poder de
by
surge cuando no podemos usarlotapply
; El siguiente código es un ejemplo:R dice que los argumentos deben tener las mismas longitudes, digamos "queremos calcular el
summary
de todas las variables a loiris
largo del factorSpecies
": pero R simplemente no puede hacer eso porque no sabe cómo manejarlo.Con la
by
función R, despache un método específico para ladata frame
clase y luego deje que lasummary
función funcione incluso si la longitud del primer argumento (y el tipo también) son diferentes.funciona de hecho y el resultado es muy sorprendente. Es un objeto de clase
by
que a lo largoSpecies
(por ejemplo, para cada uno de ellos) calcula elsummary
de cada variable.Tenga en cuenta que si el primer argumento es a
data frame
, la función despachada debe tener un método para esa clase de objetos. Por ejemplo, si usamos este código con lamean
función, tendremos este código que no tiene ningún sentido:AGREGAR
aggregate
puede verse como otra forma diferente de usotapply
si la usamos de esa manera.Las dos diferencias inmediatas son que el segundo argumento de
aggregate
debe ser una lista mientras quetapply
puede (no obligatorio) ser una lista y que la salida deaggregate
es un marco de datos mientras que el detapply
es unarray
.El poder de esto
aggregate
es que puede manejar fácilmente subconjuntos de datos consubset
argumentos y que también tiene métodos parats
objetosformula
.Estos elementos hacen que
aggregate
sea más fácil trabajar con esotapply
en algunas situaciones. Aquí hay algunos ejemplos (disponibles en la documentación):Podemos lograr lo mismo con,
tapply
pero la sintaxis es un poco más difícil y la salida (en algunas circunstancias) menos legible:Hay otros momentos en que no podemos usar
by
otapply
y tenemos que usaraggregate
.No podemos obtener el resultado anterior con
tapply
una sola llamada, pero tenemos que calcular la mediaMonth
para cada elemento y luego combinarlos (también tenga en cuenta que tenemos que llamar ana.rm = TRUE
, porque losformula
métodos de laaggregate
función tienen por defecto elna.action = na.omit
):mientras que con
by
simplemente no podemos lograr eso, de hecho, la siguiente llamada de función devuelve un error (pero lo más probable es que esté relacionado con la función suministradamean
):Otras veces, los resultados son los mismos y las diferencias son solo en el objeto de clase (y luego cómo se muestra / imprime y no solo - por ejemplo, cómo subconjunto):
El código anterior logra el mismo objetivo y resultados, en algunos puntos qué herramienta usar es solo una cuestión de gustos y necesidades personales; Los dos objetos anteriores tienen necesidades muy diferentes en términos de subconjunto.
fuente
data.frame(tapply(unlist(iris[,-5]),list(rep(iris[,5],ncol(iris[-5])),col(iris[-5])),summary))
este es un uso de tapply. With the right splitting there is nothing you cant do with
tapply. The only thing is it returns a matrix. Please be careful by saying we cant use
tapply`Hay muchas respuestas excelentes que analizan las diferencias en los casos de uso para cada función. Ninguna de las respuestas discute las diferencias en el rendimiento. Eso es razonable porque varias funciones esperan diversas entradas y producen varias salidas, aunque la mayoría de ellas tienen un objetivo común general para evaluar por series / grupos. Mi respuesta se centrará en el rendimiento. Debido a lo anterior, la creación de entrada a partir de los vectores se incluye en el tiempo, tampoco
apply
se mide la función.He probado dos funciones diferentes
sum
ylength
a la vez. El volumen probado es 50M en entrada y 50K en salida. También he incluido dos paquetes actualmente populares que no se usaban ampliamente en el momento en que se hicieron las preguntas,data.table
ydplyr
. Definitivamente vale la pena mirar ambos si buscas un buen rendimiento.fuente
A pesar de todas las excelentes respuestas aquí, hay 2 funciones básicas más que merecen ser mencionadas, la
outer
función útil y laeapply
función oscuraexterior
outer
Es una función muy útil oculta como una más mundana. Si lees la ayuda paraouter
su descripción dice:lo que hace que parezca que esto solo es útil para cosas de tipo álgebra lineal. Sin embargo, se puede usar de manera muy parecida
mapply
a la aplicación de una función a dos vectores de entradas. La diferencia es quemapply
aplicará la función a los dos primeros elementos y luego a los segundos dos, etc., mientrasouter
que aplicará la función a cada combinación de un elemento del primer vector y uno del segundo. Por ejemplo:Personalmente, he usado esto cuando tengo un vector de valores y un vector de condiciones y deseo ver qué valores cumplen con qué condiciones.
aplicar
eapply
es como,lapply
excepto que, en lugar de aplicar una función a cada elemento de una lista, aplica una función a cada elemento en un entorno. Por ejemplo, si desea encontrar una lista de funciones definidas por el usuario en el entorno global:Francamente, no uso mucho esto, pero si está creando muchos paquetes o creando muchos entornos, puede ser útil.
fuente
Quizás valga la pena mencionarlo
ave
.ave
Estapply
el primo amigable. Devuelve los resultados en un formulario que puede volver a conectar directamente a su marco de datos.No hay nada en el paquete base que funcione como
ave
para marcos de datos completos (comoby
estapply
para marcos de datos). Pero puedes evitarlo:fuente
Recientemente descubrí la
sweep
función bastante útil y la agregué aquí por completo:barrer
La idea básica es barrer a través de una matriz en fila o columna y devolver una matriz modificada. Un ejemplo aclarará esto (fuente: campo de datos ):
Digamos que tiene una matriz y desea estandarizarla en columnas:
NB: para este ejemplo simple, por supuesto, se puede lograr el mismo resultado más fácilmente
apply(dataPoints, 2, scale)
fuente
sweep
es una función de orden superior como todas las demás mencionadas aquí, p. ejapply
.sapply
, porlapply
lo que se podría hacer la misma pregunta sobre la respuesta aceptada con más de 1,000 votos a favor y los ejemplos dados en ella. Solo eche un vistazo al ejemplo dadoapply
allí.sweep(matrix(1:6,nrow=2),2,7:9,list)
. Por lo general, es más eficiente queapply
porque whereapply
buclessweep
puede utilizar funciones vectorizadas.En el paquete de colapso lanzado recientemente en CRAN, he intentado comprimir la mayor parte de la funcionalidad de aplicación común en solo 2 funciones:
dapply
(Aplicar datos) aplica funciones a filas o columnas (por defecto) de matrices y datos. Marcos y (por defecto) devuelve un objeto del mismo tipo y con los mismos atributos (a menos que el resultado de cada cálculo sea atómico ydrop = TRUE
). El rendimiento es comparable allapply
de las columnas data.frame y aproximadamente 2 veces más rápido queapply
para las filas o columnas de matriz. El paralelismo está disponible a través demclapply
(solo para MAC).Sintaxis:
Ejemplos:
BY
es un genérico S3 para computación dividida-aplicada-combinada con vector, matriz y método data.frame. Es significativamente más rápido quetapply
,by
yaggregate
( aunque también es más rápido queplyr
, en datos grandesdplyr
es más rápido).Sintaxis:
Ejemplos:
También se pueden suministrar listas de variables de agrupación
g
.Hablando sobre el rendimiento: un objetivo principal del colapso es fomentar la programación de alto rendimiento en R y avanzar más allá de dividir, aplicar y combinar por completo. Para ello, el paquete tiene un conjunto completo de funciones de C ++ basadas rápida genéricos:
fmean
,fmedian
,fmode
,fsum
,fprod
,fsd
,fvar
,fmin
,fmax
,ffirst
,flast
,fNobs
,fNdistinct
,fscale
,fbetween
,fwithin
,fHDbetween
,fHDwithin
,flag
,fdiff
yfgrowth
. Realizan cálculos agrupados en una sola pasada a través de los datos (es decir, sin división y recombinación).Sintaxis:
Ejemplos:
En las viñetas del paquete proporciono puntos de referencia. La programación con las funciones rápidas es significativamente más rápida que la programación con dplyr o data.table , especialmente en datos más pequeños, pero también en datos grandes.
fuente