Cada vez que quiero hacer algo "map" py en R, generalmente trato de usar una función en la applyfamilia.
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, dondeiestá el elementof(vec[i]), dándole una matriz siftiene 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 elementoies 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 defuna agrupacióngdel vector ygse empuja a los nombres de fila / columnaby(dataframe, grouping, f): dejagser una agrupación. aplicarfa cada columna del grupo / marco de datos. imprima bastante la agrupación y el valor defen 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 plyro reshapereemplazar 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.doByy las capacidades de selección y aplicación dedata.table.sapplyes sololapplycon la adición desimplify2arrayen la salida.applycoacciona al vector atómico, pero la salida puede ser vector o lista.bydivide los marcos de datos en subcuadros de datos, pero no se usafen columnas por separado. Solo si hay un método para la clase 'data.frame' podríafaplicarse por columnaby.aggregatees 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
plyrpaquete 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á
lapplydebajo.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,sapplylos usará como columnas de una matriz:Si nuestra función devuelve una matriz bidimensional,
sapplyhará 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,
sapplypero 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
mapplycon elSIMPLIFY = FALSEque 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
rapplyes, ¡lo olvidé la primera vez que publiqué esta respuesta! Obviamente, estoy seguro de que muchas personas lo usan, pero YMMV.rapplyse 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
xdentro 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.
tapplyes 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
byes puramente dividido yaggregateestátapplyen sus núcleos. Creo que las ovejas negras son un excelente tejido.aggregateybytambié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 ,byetc. 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.?Mapcomo pariente demapplydata.frames son una parte absolutamente central de R y, comolistobjeto, se manipulan con frecuencia utilizandolapplyparticularmente. También actúan como contenedores para agrupar vectores / factores de muchos tipos en un conjunto de datos rectangular tradicional. Si biendata.tableyplyrpodrían agregar un cierto tipo de sintaxis que algunos podrían encontrar más cómodo, se están extendiendo y actuando sobredata.frames respectivamente.En la nota al margen, así es como las diversas
plyrfunciones corresponden a las*applyfunciones 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
plyres 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
plyrno es más difícil que comprender las*applyfunciones básicas .plyry lasreshapefunciones 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.plyrfunciones es similar a las*applyfunciones, por lo que si puedes hacer una, puedes hacer la otra, pero lasplyrfunciones 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.eapplyvapplyy las desventajas desapply. Una de las principales ventajasvapplyes 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,sapplyintentaremos 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
applycorresponde a @ Hadleyaaplyyaggregatecorresponde a @ Hadley,ddplyetc. 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
lapplyes una aplicación de lista que actúa en una lista o vector y devuelve una lista.sapplyes simplelapply(la función predeterminada es devolver un vector o matriz cuando sea posible)vapplyes una aplicación verificada (permite especificar previamente el tipo de objeto de retorno)rapplyes una solicitud recursiva para listas anidadas, es decir, listas dentro de listastapplyes una aplicación etiquetada donde las etiquetas identifican los subconjuntosapplyes 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
applyfamilia 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
applyfamilia 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
applytendrá mucho más sentido.fuente
Desde que me di cuenta de que (los muy excelentes) respuestas de esta entrada falta de
byyaggregateexplicaciones. Aquí está mi contribución.POR
Sin
byembargo, la función, como se indica en la documentación, puede ser un "contenedor" paratapply. El poder debysurge cuando queremos calcular una tarea quetapplyno puede manejar. Un ejemplo es este código:Si imprimimos estos dos objetos,
ctycb"esencialmente" tenemos los mismos resultados y las únicas diferencias están en cómo se muestran y los diferentesclassatributos, respectivamentebyparacbyarrayparact.Como he dicho, el poder de
bysurge 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
summaryde todas las variables a loirislargo del factorSpecies": pero R simplemente no puede hacer eso porque no sabe cómo manejarlo.Con la
byfunción R, despache un método específico para ladata frameclase y luego deje que lasummaryfunció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
byque a lo largoSpecies(por ejemplo, para cada uno de ellos) calcula elsummaryde 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 lameanfunción, tendremos este código que no tiene ningún sentido:AGREGAR
aggregatepuede verse como otra forma diferente de usotapplysi la usamos de esa manera.Las dos diferencias inmediatas son que el segundo argumento de
aggregatedebe ser una lista mientras quetapplypuede (no obligatorio) ser una lista y que la salida deaggregatees un marco de datos mientras que el detapplyes unarray.El poder de esto
aggregatees que puede manejar fácilmente subconjuntos de datos consubsetargumentos y que también tiene métodos paratsobjetosformula.Estos elementos hacen que
aggregatesea más fácil trabajar con esotapplyen algunas situaciones. Aquí hay algunos ejemplos (disponibles en la documentación):Podemos lograr lo mismo con,
tapplypero 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
byotapplyy tenemos que usaraggregate.No podemos obtener el resultado anterior con
tapplyuna sola llamada, pero tenemos que calcular la mediaMonthpara cada elemento y luego combinarlos (también tenga en cuenta que tenemos que llamar ana.rm = TRUE, porque losformulamétodos de laaggregatefunción tienen por defecto elna.action = na.omit):mientras que con
bysimplemente 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 withtapply. The only thing is it returns a matrix. Please be careful by saying we cant usetapply`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
applyse mide la función.He probado dos funciones diferentes
sumylengtha 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.tableydplyr. 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
outerfunción útil y laeapplyfunción oscuraexterior
outerEs una función muy útil oculta como una más mundana. Si lees la ayuda paraoutersu 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
mapplya la aplicación de una función a dos vectores de entradas. La diferencia es quemapplyaplicará la función a los dos primeros elementos y luego a los segundos dos, etc., mientrasouterque 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
eapplyes como,lapplyexcepto 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.aveEstapplyel 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
avepara marcos de datos completos (comobyestapplypara marcos de datos). Pero puedes evitarlo:fuente
Recientemente descubrí la
sweepfunció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
sweepes una función de orden superior como todas las demás mencionadas aquí, p. ejapply.sapply, porlapplylo 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 dadoapplyallí.sweep(matrix(1:6,nrow=2),2,7:9,list). Por lo general, es más eficiente queapplyporque whereapplybuclessweeppuede 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 allapplyde las columnas data.frame y aproximadamente 2 veces más rápido queapplypara las filas o columnas de matriz. El paralelismo está disponible a través demclapply(solo para MAC).Sintaxis:
Ejemplos:
BYes 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,byyaggregate( aunque también es más rápido queplyr, en datos grandesdplyres 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,fdiffyfgrowth. 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