Cursus
Deze data.table R-tutorial legt de basis uit van het DT[i, j, by]-commando, de kern van het data.table-pakket. Wil je meer leren over het data.table-pakket, dan biedt DataCamp een interactieve R-cursus over het data.table-pakket aan. De cursus bevat meer dan 35 interactieve R-oefeningen – allemaal in het comfort van je eigen browser – en verschillende video’s met Matt Dowle, hoofdauteur van het data.table-pakket, en Arun Srinivasan, een belangrijke bijdrager. Probeer het gratis.
Als je al met grote datasets in RAM hebt gewerkt (1 tot meer dan 100 GB), weet je dat een data.frame beperkend kan zijn: sommige bewerkingen duren simpelweg te lang. Data.table lost dit voor je op door de rekentijd te verkorten. Bovendien kun je er met minder typwerk meer mee doen. Zodra je de data.table-syntaxis uit deze data.table R-tutorial onder de knie hebt, zal de eenvoud waarmee je complexe operaties uitvoert je verbazen. Je verkort dus niet alleen de rekentijd, maar ook je programmeertijd.
Het DT[i,j,by]-commando heeft drie delen: i, j en by. In SQL-termen komt i overeen met WHERE, j met SELECT en by met GROUP BY. We beschrijven het commando als: “Neem DT, subset de rijen met ‘i’, bereken vervolgens ‘j’ gegroepeerd op ‘by’.” In een eenvoudig voorbeeld met de hflights-dataset (zodat je alle voorbeelden kunt reproduceren) geeft dit:
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
...
We hebben de data table gefilterd om alleen de rijen van de 10e maand van het jaar te behouden, de gemiddelde AirTime berekend van de vluchten die daadwerkelijk gevlogen hebben (daarom gebruiken we na.omit(); geannuleerde vluchten hebben geen waarde voor AirTime) en de resultaten vervolgens gegroepeerd op luchtvaartmaatschappij. Je ziet bijvoorbeeld dat AA (American Airlines) een veel kortere gemiddelde AirTime heeft dan AS (Alaska Airlines). Is het je ook opgevallen dat R-basispuncties in het j-gedeelte gebruikt kunnen worden? Daar komen we later op terug.
Het i-gedeelte
Het ‘i’-gedeelte gebruik je voor het subsetten van rijen, net zoals bij een data frame.
DT[2:5]
#selects the second to the fifth row of 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
Maar je kunt ook kolomnamen gebruiken, omdat ze in de scope van DT worden geëvalueerd.
DT[UniqueCarrier=="AA"]
#Returns all those rows where the Carrier is 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
Merk op dat je geen komma hoeft te gebruiken om rijen te subsetten in een data table. In een data.frame zou DF[2:5] alle rijen van de 2e t/m 5e kolom opleveren. In plaats daarvan (zoals iedereen die dit leest uiteraard weet) moeten we DF[2:5,] specificeren. Merk ook op dat DT[,2:5] niets betekent voor data tables, zoals uitgelegd in de eerste vraag van de FAQ’s van het data.table-pakket.
Vreemd maar handig: bij het subsetten van rijen kun je ook het symbool .N gebruiken in het DT[…]-commando; dit is het aantal rijen of de laatste rij. Je kunt het gebruiken om de laatste rij of een offset daarvan te selecteren.
DT[.N-1]
#Returns the penultimate row of 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
Het j-gedeelte
Het ‘j’-gedeelte gebruik je om kolommen te selecteren en er dingen mee te doen. En dingen kan echt van alles zijn. Allerlei functies zijn mogelijk; dat is een sterk punt van het data.table-pakket.
DT[, mean(na.omit(ArrDelay))]
[1] 7.094334
Let op dat het i-gedeelte leeg is gelaten, en dat het eerste teken in de haakjes een komma is. Dat lijkt in het begin misschien tegenintuïtief. Het betekent simpelweg dat we niet op rijen subselecteren, dus alle rijen zijn geselecteerd. In het j-gedeelte wordt de gemiddelde aankomstvertraging van alle vluchten berekend. Het blijkt dat het gemiddelde toestel in de hflights-dataset ruim 7 minuten vertraging had. Wees voorbereid als je je volgende vlucht haalt!
Als je meerdere kolommen selecteert en er dingen mee doet in het j-gedeelte, moet je de ‘.()’-notatie gebruiken. Deze notatie is eigenlijk gewoon een alias voor ‘list()’. Het resultaat is een data table, terwijl je zonder ‘.()’ alleen een vector terugkrijgt, zoals hierboven getoond.
DT[, .(mean(na.omit(DepDelay)), mean(na.omit(ArrDelay)))]
V1 V2
9.444951 7.094334
Een andere handige functie die de ‘.()’-notatie vereist, laat je kolommen hernoemen binnen het DT[…]-commando.
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
Natuurlijk zijn nieuwe kolomnamen niet verplicht.
Door het bovenstaande over ‘i’ en ‘j’ te combineren, krijg je:
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
Hier namen we DT, selecteerden in het i-gedeelte alle rijen waar de maatschappij AA was, berekenden de gemiddelde vertrek- en aankomstvertraging, en plotten in het j-gedeelte de vertrektijd tegen de vertrekvertraging.
Samengevat: het j-gedeelte gebruik je om berekeningen uit te voeren op kolommen die je daar specificeert. Omdat de kolommen van een data table als variabelen worden gezien, en de onderdelen van ‘j’ als expressies worden geëvalueerd, kun je in het j-gedeelte vrijwel alles doen. Dat verkort je programmeertijd aanzienlijk.
Het by-gedeelte
Het laatste deel van deze data.table R-tutorial richt zich op het ‘by’-gedeelte. Het ‘by’-gedeelte gebruik je wanneer je het ‘j’-gedeelte wilt berekenen, gegroepeerd op een specifieke variabele (of een bewerking daarop). Je zult zien dat de ‘j’-expressie wordt herhaald voor elke ‘by’-groep. Het is eenvoudig te gebruiken: je geeft in het ‘by’-argument gewoon de kolom op waarop je wilt groeperen.
DT[,mean(na.omit(DepDelay)),by=Origin]
Origin V1
IAH 8.436951
HOU 12.837873
Hier berekenden we de gemiddelde vertraging vóór vertrek, maar gegroepeerd op de luchthaven van vertrek. Het lijkt erop dat vluchten die vertrekken vanaf HOU een hogere gemiddelde vertraging hebben dan die vanaf IAH.
Net als in het j-gedeelte kun je ook in het ‘by’-gedeelte een hoop dingen doen. Functies kunnen in het ‘by’-gedeelte worden gebruikt, zodat de resultaten van de bewerkingen in het j-gedeelte worden gegroepeerd op iets dat we binnen het DT[…]-commando hebben gespecificeerd. Functies binnen DT[…] gebruiken maakt die ene regel erg krachtig. Evenzo moet je de ‘.()’-notatie gebruiken als je meerdere kolommen in het ‘by’-gedeelte gebruikt.
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
Hier is eerst de gemiddelde vertraging vóór vertrek van alle vluchten berekend (geen subsetting in het i-gedeelte, dus alle rijen zijn geselecteerd), en vervolgens gegroepeerd, eerst naar luchthaven van vertrek en daarna naar weekdag. Weekdays is False in het weekend. Het lijkt erop dat de gemiddelde vertrekvertraging groter was bij vertrek vanaf HOU dan vanaf IAH, en verrassend genoeg waren de vertragingen in het weekend kleiner.
Alles bij elkaar levert een typisch DT[i,j,by]-commando op:
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
Hier is de subset van vluchten uitgevoerd door Delta Air Lines (geselecteerd in ‘i’) gegroepeerd naar luchthaven van vertrek en naar Weekdays (in ‘by’). De tijd die in de lucht is gecompenseerd, is ook berekend (in ‘j’). Het lijkt erop dat in het weekend, ongeacht of het toestel uit IAH of HOU kwam, de in de lucht gecompenseerde tijd (dus door sneller te vliegen) groter is.
Er valt nog veel meer te ontdekken in het data.table-pakket, maar dit bericht illustreerde het basiscommando DT[i,j,by]. De DataCamp-cursus behandelt het hele data.table-pakket uitgebreid. Je kunt de oefeningen in je eigen tempo in je browser doen met hints en feedback, en de video’s en slides zo vaak terugkijken als je wilt. Deze interactieve manier van leren helpt je om grondige kennis en praktische ervaring met data tables op te doen. Probeer het gratis. Bekijk ook DataCamp’s data.table R Package Cheat Sheet.
Hopelijk begrijp je dankzij deze data.table R-tutorial nu de fundamentele syntaxis van data.table en ben je klaar om zelf te experimenteren. Als je vragen hebt over het data.table-pakket, kijk dan hier. Matt en Arun zijn erg actief. Een van de volgende blogposts over het data.table-pakket wordt technischer en zoomt in op de brede mogelijkheden met data tables. Blijf op de hoogte!


