Curso
Este tutorial de data.table en R explica los fundamentos del comando DT[i, j, by], que es el núcleo del paquete data.table. Si quieres profundizar en el paquete, DataCamp ofrece un curso interactivo de R sobre el paquete data.table. El curso incluye más de 35 ejercicios interactivos de R —todo desde tu navegador— y varios vídeos con Matt Dowle, autor principal del paquete data.table, y Arun Srinivasan, uno de sus principales contribuidores. Pruébalo gratis.
Si ya has trabajado con conjuntos de datos grandes en RAM (de 1 a más de 100 GB), sabrás que un data.frame puede quedarse corto: hay operaciones que tardan demasiado. Data.table resuelve este problema reduciendo los tiempos de cómputo. Además, te permite hacer más con menos tecleo. Una vez domines la sintaxis de data.table con este tutorial, te sorprenderá lo sencillo que es realizar operaciones complejas. Así que no solo reducirás el tiempo de cómputo, sino también el tiempo de programación.
El comando DT[i,j,by] tiene tres partes: i, j y by. Si piensas en términos de SQL, i equivale a WHERE, j a SELECT y by a GROUP BY. Solemos describir el comando así: “Toma DT, selecciona filas con ‘i’, luego calcula ‘j’ agrupando por ‘by’”. Con un ejemplo sencillo y usando el conjunto de datos hflights (para que puedas reproducirlo), quedaría así:
library(hflights)
library(data.table)
DT <- as.data.table(hflights)
DT[Month==10,mean(na.omit(AirTime)), by=UniqueCarrier]
UniqueCarrier V1
AA 68.76471
AS 255.29032
B6 176.93548
CO 141.52861
...
Aquí filtramos la tabla para quedarnos solo con las filas del mes 10, calculamos el tiempo medio en aire de los vuelos que realmente despegaron (por eso usamos na.omit(): los vuelos cancelados no tienen valor en AirTime) y agrupamos los resultados por aerolínea. Vemos, por ejemplo, que AA (American Airlines) tiene un AirTime medio mucho menor que AS (Alaska Airlines). ¿Te has fijado también en que puedes usar funciones base de R en la parte j? Llegaremos a eso enseguida.
La parte i
La parte ‘i’ se usa para filtrar filas, igual que en un data frame.
DT[2:5]
#selecciona de la segunda a la quinta fila de DT
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime AirTime
2011 1 2 7 1401 1501 AA 428 N557AA 60 45
2011 1 3 1 1352 1502 AA 428 N541AA 70 48
2011 1 4 2 1403 1513 AA 428 N403AA 70 39
2011 1 5 3 1405 1507 AA 428 N492AA 62 44
ArrDelay DepDelay Origin Dest Distance TaxiIn TaxiOut Cancelled CancellationCode Diverted
-9 1 IAH DFW 224 6 9 0 0
-8 -8 IAH DFW 224 5 17 0 0
3 3 IAH DFW 224 9 22 0 0
-3 5 IAH DFW 224 9 9 0 0
Pero también puedes usar nombres de columnas, ya que se evalúan en el ámbito de DT.
DT[UniqueCarrier=="AA"]
#Devuelve todas las filas donde la aerolínea es American Airlines
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime
2011 1 1 6 1400 1500 AA 428 N576AA 60
2011 1 2 7 1401 1501 AA 428 N557AA 60
2011 1 3 1 1352 1502 AA 428 N541AA 70
2011 1 4 2 1403 1513 AA 428 N403AA 70
2011 1 5 3 1405 1507 AA 428 N492AA 62
---
2011 12 27 2 1021 1333 AA 2234 N3ETAA 132
2011 12 28 3 1015 1329 AA 2234 N3FJAA 134
2011 12 29 4 1023 1335 AA 2234 N3GSAA 132
2011 12 30 5 1024 1334 AA 2234 N3BAAA 130
2011 12 31 6 1024 1343 AA 2234 N3HNAA 139
AirTime ArrDelay DepDelay Origin Dest Distance TaxiIn TaxiOut Cancelled CancellationCode Diverted
40 -10 0 IAH DFW 224 7 13 0 0
45 -9 1 IAH DFW 224 6 9 0 0
48 -8 -8 IAH DFW 224 5 17 0 0
39 3 3 IAH DFW 224 9 22 0 0
44 -3 5 IAH DFW 224 9 9 0 0
---
112 -12 1 IAH MIA 964 8 12 0 0
112 -16 -5 IAH MIA 964 9 13 0 0
110 -10 3 IAH MIA 964 12 10 0 0
110 -11 4 IAH MIA 964 9 11 0 0
119 -2 4 IAH MIA 964 8 12 0 0
Fíjate en que no necesitas coma para filtrar filas en una data table. En un data.frame, hacer DF[2:5] devolvería todas las filas de las columnas 2 a 5. En su lugar (como ya sabrás), debemos escribir DF[2:5,]. También ten en cuenta que DT[,2:5] no significa nada para data.table, como se explica en la primera pregunta de las FAQs del paquete.
Curioso y útil: al filtrar filas también puedes usar el símbolo .N en el comando DT[…], que representa el número de filas o la última fila. Puedes emplearlo para seleccionar la última fila o un desplazamiento desde ella.
DT[.N-1]
#Devuelve la penúltima fila de DT
Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum TailNum ActualElapsedTime AirTime
2011 12 6 2 656 812 WN 621 N727SW 76 64
ArrDelay DepDelay Origin Dest Distance TaxiIn TaxiOut Cancelled CancellationCode Diverted
-13 -4 HOU TUL 453 3 9 0 0
La parte j
La parte ‘j’ se usa para seleccionar columnas y hacer cosas con ellas. Y cosas puede ser prácticamente cualquier cosa. Puedes usar todo tipo de funciones, lo que es una gran ventaja de data.table.
DT[, mean(na.omit(ArrDelay))]
[1] 7.094334
Observa que la parte ‘i’ está vacía y lo primero dentro de los corchetes es una coma. Puede resultar contraintuitivo al principio, pero solo indica que no filtramos filas: se seleccionan todas. En ‘j’ calculamos el retraso medio a la llegada de todos los vuelos. Parece que, de media, los vuelos del conjunto hflights llegan con más de 7 minutos de retraso. ¡Ténlo en cuenta para tu próximo vuelo!
Cuando seleccionas varias columnas y haces cosas con ellas en ‘j’, necesitas la notación ‘.()’. Esta notación es simplemente un alias de ‘list()’. Devuelve una data table, mientras que no usar ‘.()’ devuelve solo un vector, como se ve arriba.
DT[, .(mean(na.omit(DepDelay)), mean(na.omit(ArrDelay)))]
V1 V2
9.444951 7.094334
Otra función útil que requiere la notación ‘.()’ te permite renombrar columnas dentro del propio comando DT[…].
DT[, .(Avg_ArrDelay =
mean(na.omit(ArrDelay)))]
Avg_ArrDelay
7.094334
DT[, .(Avg_DepDelay = mean(na.omit(DepDelay)),
avg_ArrDelay = mean(na.omit(ArrDelay)))]
Avg_DepDelay Avg_ArrDelay
9.444951 7.094334
Por supuesto, no es obligatorio poner nombres nuevos.
Combinando lo anterior sobre ‘i’ y ‘j’ obtenemos:
DT[UniqueCarrier=="AA", .(Avg_DepDelay =
mean(na.omit(DepDelay)),
Avg_ArrDelay = mean(na.omit(ArrDelay)),
plot(DepTime,DepDelay,ylim=c(-15,200)),
abline(h=0))]
Avg_DepDelay Avg_ArrDelay V3 V4
6.390144 0.8917558 NULL NULL
Aquí tomamos DT, seleccionamos en ‘i’ todas las filas donde la aerolínea era AA, calculamos el retraso medio en salida y llegada, y representamos en ‘j’ la hora de salida frente al retraso en salida.
En resumen, la parte ‘j’ se usa para hacer cálculos sobre las columnas que especifiques ahí. Como las columnas de una data table se tratan como variables y las partes de ‘j’ se evalúan como expresiones, prácticamente puedes hacer cualquier cosa en ‘j’. Esto reduce significativamente tu tiempo de programación.
La parte by
La última sección de este tutorial de data.table se centra en la parte ‘by’. Se utiliza cuando queremos calcular la parte ‘j’ agrupando por una variable concreta (o alguna transformación de esa variable). Verás que la expresión de ‘j’ se repite para cada grupo de ‘by’. Su uso es sencillo: indica en el argumento ‘by’ la columna por la que quieres agrupar.
DT[,mean(na.omit(DepDelay)),by=Origin]
Origin V1
IAH 8.436951
HOU 12.837873
Aquí calculamos el retraso medio antes de la salida, pero agrupado por el aeropuerto de origen. Parece que los vuelos que salen de HOU tienen un retraso medio mayor que los que salen de IAH.
Igual que en ‘j’, puedes hacer muchas cosas en ‘by’. Puedes usar funciones en ‘by’ para que los resultados de las operaciones realizadas en ‘j’ se agrupen por algo que especifiques dentro del comando DT[…]. Usar funciones dentro de DT[…] hace que esa única línea sea muy potente. Del mismo modo, debes usar la notación ‘.()’ cuando agrupes por varias columnas.
DT[,.(Avg_DepDelay_byWeekdays = mean(na.omit(DepDelay))), by=.(Origin,Weekdays = DayOfWeek<6)]
Origin Weekdays Avg_DepDelay_byWeekdays
IAH FALSE 8.286543
IAH TRUE 8.492484
HOU FALSE 10.965384
HOU TRUE 13.433994
Aquí, primero calculamos el retraso medio antes de la salida de todos los vuelos (sin filtrado en ‘i’, así que se seleccionan todas las filas) y después lo agrupamos, primero por el origen y luego por día laborable. Weekdays es False en fin de semana. Parece que el retraso medio antes de la salida fue mayor cuando el vuelo partía de HOU que de IAH y, sorprendentemente, los retrasos fueron menores en fin de semana.
Juntándolo todo, un comando típico DT[i,j,by] quedaría así:
DT[UniqueCarrier=="DL", .(Avg_DepDelay =
mean(na.omit(DepDelay)),
Avg_ArrDelay = mean(na.omit(ArrDelay)),
Compensation = mean(na.omit(ArrDelay - DepDelay))), by = .(Origin, Weekdays = DayOfWeek&lt;6)]
Origin Weekdays Avg_DepDelay Avg_ArrDelay Compensation
IAH FALSE 8.979730 4.116751 -4.825719
HOU FALSE 7.120000 2.656566 -4.555556
IAH TRUE 9.270948 6.281941 -2.836609
HOU TRUE 11.631387 10.406593 -1.278388
Aquí, el subconjunto de vuelos operados por Delta Air Lines (seleccionado en ‘i’) se agrupó por origen y por Weekdays (en ‘by’). También se calculó el tiempo compensado en el aire (en ‘j’). Parece que en fin de semana, independientemente de si el vuelo salía de IAH o HOU, el tiempo compensado en el aire (volando más rápido) es mayor.
Hay mucho más que descubrir en el paquete data.table, pero esta entrada ha ilustrado el comando básico DT[i,j,by]. El curso de DataCamp recorre el paquete en detalle. Puedes hacer los ejercicios a tu ritmo desde el navegador con pistas y feedback, y revisar los vídeos y diapositivas tantas veces como quieras. Este enfoque interactivo te permite adquirir un conocimiento sólido y experiencia práctica con data.table. Pruébalo gratis. Echa un vistazo a la chuleta del paquete data.table en R de DataCamp.
Esperamos que, gracias a este tutorial de data.table en R, hayas entendido la sintaxis fundamental de data.table y estés listo para experimentar por tu cuenta. Si tienes dudas sobre el paquete, échales un vistazo a las preguntas aquí. Matt y Arun están muy activos. Una de las próximas entradas sobre data.table será más técnica y profundizará en todo lo que se puede hacer con este paquete. ¡Permanece atento!

