Debo invertir mi esfuerzo de aprendizaje para los datos de bregar en R, concretamente entre dplyr
, dtplyr
y data.table
?
Lo uso
dplyr
principalmente, pero cuando los datos son demasiado grandes para eso lo usarédata.table
, lo cual es una ocurrencia rara. Entonces, ahora quedtplyr
v1.0 está disponible como interfazdata.table
, en la superficie parece que nunca tendré que preocuparme por usar ladata.table
interfaz nunca más.Entonces, ¿cuáles son las características o aspectos más útiles
data.table
que no se pueden usardtplyr
en este momento y que probablemente nunca se puedan hacerdtplyr
?A primera vista,
dplyr
con los beneficios dedata.table
hace que suene comodtplyr
si fuera a superardplyr
. ¿Habrá alguna razón para usardplyr
una vez quedtplyr
haya madurado completamente?
Nota: no estoy preguntando sobre dplyr
vs data.table
(como en data.table vs dplyr: ¿puede uno hacer algo bien que el otro no puede o hace mal? ), Pero dado que uno es preferido sobre el otro para un problema en particular, ¿por qué no t dtplyr
ser la herramienta para su uso.
fuente
dplyr
que no puedas hacerlo biendata.table
? Si no, cambiardata.table
a será mejor quedtplyr
.dtplyr
archivo Léame, 'Algunasdata.table
expresiones no tienendplyr
equivalente directo . Por ejemplo, no hay forma de expresar uniones cruzadas o continuasdplyr
''. y 'Para coincidir con ladplyr
semántica,mutate
() no se modifica en su lugar de forma predeterminada. Esto significa que la mayoría de las expresiones involucradasmutate()
deben hacer una copia que no sería necesaria si estuviera usandodata.table
directamente '. Hay una forma de evitar esa segunda parte, pero teniendo en cuenta la frecuencia con la quemutate
se usa, es un gran inconveniente para mí.Respuestas:
Intentaré dar mis mejores guías, pero no es fácil porque uno debe estar familiarizado con todos los {data.table}, {dplyr}, {dtplyr} y también {base R}. Utilizo {data.table} y muchos paquetes {tidy-world} (excepto {dplyr}). Me encantan ambos, aunque prefiero la sintaxis de data.table a la de dplyr. Espero que todos los paquetes de tidy-world usen {dtplyr} o {data.table} como backend cuando sea necesario.
Al igual que con cualquier otra traducción (piense en dplyr-to-sparkly / SQL), hay cosas que pueden o no pueden traducirse, al menos por ahora. Quiero decir, quizás algún día {dtplyr} pueda traducirlo al 100%, quién sabe. La lista a continuación no es exhaustiva ni es 100% correcta, ya que haré todo lo posible para responder en función de mi conocimiento sobre temas / paquetes / problemas relacionados, etc.
Es importante destacar que, para aquellas respuestas que no son del todo precisas, espero que le brinde algunas guías sobre los aspectos de {data.table} a los que debe prestar atención y, compárelos con {dtplyr} y descubra las respuestas usted mismo. No tome estas respuestas por sentado.
Y espero que esta publicación se pueda utilizar como uno de los recursos para todos los usuarios / creadores de {dplyr}, {data.table} o {dtplyr} para debates y colaboraciones, y mejorar aún más las #RStats.
{data.table} no solo se usa para operaciones rápidas y eficientes en memoria. Hay muchas personas, incluido yo mismo, que prefieren la elegante sintaxis de {data.table}. También incluye otras operaciones rápidas como funciones de series de tiempo como la familia rodante (es decir,
frollapply
) escritas en C. Se puede usar con cualquier función, incluido tidyverse. ¡Utilizo mucho {data.table} + {purrr}!Complejidad de operaciones
Esto se puede traducir fácilmente
{data.table} es muy rápido y eficiente en memoria porque (¿casi?) todo está construido desde cero desde C con los conceptos clave de actualización por referencia , clave (piense en SQL) y su implacable optimización en todas partes del paquete (es decir
fifelse
, elfread/fread
orden de clasificación de radix adoptado por la base R), mientras se asegura de que la sintaxis es concisa y consistente, por eso creo que es elegante.Desde Introducción a data.table , las operaciones de manipulación de datos principales como subconjunto, grupo, actualización, unión, etc. se mantienen juntas durante
sintaxis concisa y consistente ...
realizar análisis de manera fluida sin la carga cognitiva de tener que mapear cada operación ...
optimizando automáticamente las operaciones internamente y de manera muy efectiva, al conocer con precisión los datos requeridos para cada operación, lo que lleva a un código muy rápido y eficiente en la memoria
El último punto, como ejemplo,
Dado que, para obtener los beneficios de {data.table}, la traducción de {dtplr} debe ser correcta en ese sentido. Cuanto más complejas son las operaciones, más difíciles son las traducciones. Para operaciones simples como las anteriores, ciertamente se puede traducir fácilmente. Para los complejos, o aquellos que no son compatibles con {dtplyr}, debe averiguarlo como se mencionó anteriormente, uno tiene que comparar la sintaxis traducida y el punto de referencia y estar familiarizado con los paquetes relacionados.
Para operaciones complejas u operaciones no admitidas, podría proporcionar algunos ejemplos a continuación. De nuevo, solo estoy haciendo lo mejor que puedo. Se gentil conmigo.
Actualización por referencia
No entraré en la introducción / detalles, pero aquí hay algunos enlaces
Recurso principal: semántica de referencia
Más detalles: Comprender exactamente cuándo un data.table es una referencia a (frente a una copia de) otro data.table
Actualización por referencia , en mi opinión, la característica más importante de {data.table} y eso es lo que la hace tan rápida y eficiente en memoria.
dplyr::mutate
no lo admite por defecto. Como no estoy familiarizado con {dtplyr}, no estoy seguro de cuánto y qué operaciones pueden o no ser compatibles con {dtplyr}. Como se mencionó anteriormente, también depende de la complejidad de las operaciones, lo que a su vez afecta las traducciones.Hay dos formas de usar la actualización por referencia en {data.table}
operador de asignación de {data.table}
:=
set
-family:set
,setnames
,setcolorder
,setkey
,setDT
,fsetdiff
, y muchos más:=
se usa más comúnmente en comparación conset
. Para conjuntos de datos complejos y grandes, la actualización por referencia es la clave para obtener la máxima velocidad y eficiencia de memoria. La forma fácil de pensar (no es 100% precisa, ya que los detalles son mucho más complicados que esto, ya que implica una copia impresa / superficial y muchos otros factores), dicen que se trata de un gran conjunto de datos de 10 GB, con 10 columnas y 1 GB cada una . Para manipular una columna, debe tratar solo con 1 GB.El punto clave es que, con la actualización por referencia , solo necesita lidiar con los datos requeridos. Es por eso que cuando usamos {data.table}, especialmente cuando tratamos con grandes conjuntos de datos, usamos actualización por referencia todo el tiempo siempre que sea posible. Por ejemplo, manipular grandes conjuntos de datos de modelado
Es
list(.SD)
posible que {dtlyr} no admita la operación de anidamiento como usan los usuarios tidyversetidyr::nest
? Por lo tanto, no estoy seguro de si las operaciones posteriores se pueden traducir ya que la forma de {data.table} es más rápida y menos memoria.NOTA: el resultado de data.table está en "milisegundos", dplyr en "minutos"
Hay muchos casos de uso de actualización por referencia e incluso los usuarios de {data.table} no usarán la versión avanzada de ella todo el tiempo, ya que requieren más códigos. Si {dtplyr} es compatible con estos productos listos para usar, debe averiguarlo usted mismo.
Actualización múltiple por referencia para las mismas funciones
Recurso principal: asignación elegante de múltiples columnas en data.table con lapply ()
Esto implica ya sea el más comúnmente utilizado
:=
oset
.Según el creador de {data.table} Matt Dowle
Unirse + setkey + actualizar por referencia
Necesitaba una unión rápida con datos relativamente grandes y patrones de unión similares recientemente, por lo que utilizo el poder de actualización por referencia , en lugar de combinaciones normales. Como requieren más códigos, los envuelvo en un paquete privado con una evaluación no estándar de reutilización y legibilidad donde lo llamo
setjoin
.Hice algunos puntos de referencia aquí: data.table join + update-by-reference + setkey
Resumen
NOTA:
dplyr::left_join
también se probó y es el más lento con ~ 9,000 ms, usa más memoria que las dos {data.table}update_by_reference
ysetkey_n_update
, pero usa menos memoria que las normales de {data.table}. Consumió aproximadamente ~ 2.0GB de memoria. No lo incluí porque quiero centrarme únicamente en {data.table}.Resultados clave
setkey + update
yupdate
son ~ 11 y ~ 6.5 veces más rápidos quenormal join
, respectivamentesetkey + update
es similar a laupdate
sobrecarga desetkey
compensa en gran medida sus propias ganancias de rendimientosetkey
no es necesario,setkey + update
es más rápido queupdate
~ 1.8 veces (o más rápido quenormal join
~ 11 veces)Ejemplos
Para combinaciones eficaces y de memoria eficiente, use uno
update
osetkey + update
, donde este último es más rápido a costa de más códigos.Veamos algunos pseudocódigos , por brevedad. Las lógicas son las mismas.
Para una o algunas columnas
Para muchas columnas
Envoltorio para uniones rápidas y eficientes en memoria ... muchos de ellos ... con un patrón de unión similar, envuélvalos como
setjoin
arriba - conupdate
- con o sinsetkey
Con
setkey
, el argumentoon
puede ser omitido. También se puede incluir para facilitar la lectura, especialmente para colaborar con otros.Operación de hileras grandes
set
setkey
)Recurso relacionado: agregue una fila por referencia al final de un objeto data.table
Resumen de actualización por referencia
Estos son solo algunos casos de uso de actualización por referencia . Hay muchos más.
Como puede ver, para el uso avanzado de lidiar con datos de gran tamaño, existen muchos casos de uso y técnicas que utilizan la actualización por referencia para un gran conjunto de datos. No es tan fácil de usar en {data.table} y si {dtplyr} lo admite, puede averiguarlo usted mismo.
Me concentro en la actualización por referencia en esta publicación, ya que creo que es la característica más poderosa de {data.table} para operaciones rápidas y eficientes en memoria. Dicho esto, hay muchos, muchos otros aspectos que también lo hacen tan eficiente y creo que {dtplyr} no lo admite de forma nativa.
Otros aspectos clave
Lo que es / no es compatible, también depende de la complejidad de las operaciones y si involucra la característica nativa de data.table como actualización por referencia o
setkey
. Y si el código traducido es el más eficiente (uno que escribirían los usuarios de data.table) también es otro factor (es decir, el código se traduce, pero ¿es la versión eficiente?). Muchas cosas están interconectadas.setkey
. Ver claves y subconjunto basado en búsqueda binaria rápidafrollapply
. funciones rodantes, agregados rodantes, ventana deslizante, promedio móvili
,j
oby
las operaciones (se puede utilizar casi cualquier expresión de allí), creo que los más difíciles las traducciones, sobre todo cuando se combinan con la actualización por referencia ,setkey
y otra data.table nativa funciones comofrollapply
stringr::str_*
funciones de familia contra base R y encuentro que la base R es más rápida hasta cierto punto y las uso. El punto es, no te limites a tidyverse o data.table o ..., explora otras opciones para hacer el trabajo.Muchos de estos aspectos están relacionados entre sí con los puntos mencionados anteriormente.
complejidad de las operaciones
actualización por referencia
Puede averiguar si {dtplyr} admite estas operaciones, especialmente cuando se combinan.
Otro truco útil cuando se trata de conjuntos de datos pequeños o grandes, durante la sesión interactiva, {data.table} realmente cumple con su promesa de reducir enormemente el tiempo de programación y computación .
Clave de configuración para la variable utilizada repetidamente tanto para la velocidad como para los 'nombres de fila sobrealimentados' (subconjunto sin especificar el nombre de la variable).
Si sus operaciones involucran solo las simples como en el primer ejemplo, {dtplyr} puede hacer el trabajo. Para los complejos / no compatibles, puede usar esta guía para comparar los traducidos de {dtplyr} con la forma en que los usuarios experimentados de data.table codificarían de manera rápida y eficiente en la memoria con la elegante sintaxis de data.table. La traducción no significa que sea la forma más eficiente, ya que puede haber diferentes técnicas para lidiar con diferentes casos de datos grandes. Para un conjunto de datos aún más grande, puede combinar {data.table} con {disk.frame} , {fst} y {drake} y otros paquetes increíbles para obtener lo mejor. También hay un {big.data.table} pero actualmente está inactivo.
Espero que ayude a todos. Que tengas un buen día ☺☺
fuente
Me vienen a la mente uniones no equitativas y uniones rodantes. No parece haber planes para incluir funciones equivalentes en dplyr, por lo que no hay nada que dtplyr pueda traducir.
También hay remodelación (dcast optimizado y fusión equivalente a las mismas funciones en reshape2) que tampoco está en dplyr.
Todas las funciones * _if y * _at actualmente no se pueden traducir con dtplyr también, pero están en proceso.
fuente
Actualice una columna al unirse Algunos trucos .SD Muchas funciones f Y dios sabe qué más porque #rdatatable es más que una simple biblioteca y no se puede resumir con pocas funciones
Es un ecosistema completo por sí solo
Nunca he necesitado dplyr desde el día en que comencé R. Porque data.table es muy bueno
fuente