De meeste tijd en moeite gaat zitten in het manipuleren en “cleanen” van data. Als je R gebruikt als onderdeel van je workflow, dan is dplyr het go-to package.
Dplyr is gemaakt om efficiënte manipulatie van gegevens mogelijk te maken op een met weinig en simpele code. Bovendien is dplyr onderdeel van Tidyverse. Dit is een samenstelling van belangrijke data science packages voor R, hieronder valt ook bijvoorbeeld gpplot2 waarmee je ongeveer alle gewenste visualisaties kunt maken zoals bijvoorbeeld boxplots of een histogram.
Stel, je hebt een geweldige dataset gevonden en je wilt er meer over te weten komen. Hoe kun je beginnen met het beantwoorden van de vragen die je hebt over de gegevens? Je kunt dplyr gebruiken om die vragen te beantwoorden. Bovendien helpt dplyr je ook met het transformeren van je data. Zo kun je gegevens aggregeren, variabelen toevoegen, variabelen verwijderen of variabelen wijzigen.
Dplyr werkt aan de hand van een paar belangrijke werkwoorden, die aan elkaar gekoppeld worden met de zogenaamde “piping operator”. De vier belangrijkste werkwoorden zijn degenen die je kunt gebruiken om data te selecteren, filteren, ordenen en muteren, en de “piping operator” (%>%
) wordt gebruikt om deze werkwoorden aan elkaar te linken.
Met de werkwoorden en %>%
van dplyr is het makkelijker om complexe operaties van datamanipulatie uit te voeren. Voordat we in de details duiken, laten we een snel voorbeeld bekijken om de mogelijkheden van dplyr te benadrukken.
dplyr Pipeline
Stel we hebben een dataset die data van alle aankomende en vertrekkende vluchten vanaf van een bepaald vliegveld bevat. Vervolgens willen wij op deze data de volgende operaties uitvoeren:
Stap 1: Filter op alle vluchten met als oorsprong de luchthaven met code “LAX”
Stap 2: Tel het totaal aantal vluchten en vertraagde vluchten per luchtvaartmaatschappij
Stap 3: Converteer het naar de metriek “vertraagd per duizend”
Stap 4: Sorteer het resultaat op deze metriek in aflopende volgorde
Een typische dplyr “pipeline” om deze vragen te beantwoorden zou er dan als volgt uitzien:
hflights %>%
filter(Oorsprong == "LAX") %>%
mutate(Vertraagd =if_else(Vertraging>0,TRUE,FALSE,missing=NULL)) %>%
group_by(Airline) %>%
summarise(Aantal=n(),AantalVertraagd=sum(Vertraagd,na.rm=TRUE)) %>%
mutate(perDuizend=100*(AantalVertraagd/Aantal)) %>%
arrange(desc(perDuizend))
We gebruiken in dit blog de software R. Heb je R nog niet geïnstalleerd, volg dan deze pagina over R installeren
Zoals je kunt zien, hebben we in slechts 5 regels code snel de antwoorden gekregen op al onze vragen. Zie ook hoe aan het eind van elke regel de ‘piping operator’ elke afzonderlijke operatie aan de volgende koppelt. Zo wordt de kenmerkende “chain” of “pipeline” gecreëerd waar het package dplyr zo bekend om is.
Laten we nu eens een stapje terug doen en afzonderlijk kijken naar elk van de belangrijke werkwoorden.
Deze 4 belangrijkste werkwoorden voor data transformaties zijn :
select()
filter()
arrange()
mutate()
Dataset Counties
Om goed uit te kunnen leggen wat elk van de vier werkwoorden precies uitvoert, nemen we de dataset counties. Deze specifieke dataset is afkomstig van de volkstelling van de Verenigde Staten in 2015. Een staat is een van de 50 regio's binnen de Verenigde Staten, zoals New York, Californië, of Texas. Een county is een subregio binnen een van die staten, zoals Los Angeles county in Californië.
Je krijgt toegang tot deze data door counties
in te typen in je R console. Hieronder nemen wij de head()
van counties, wat wil zeggen dat R ons maar de eerste paar regels van de data laat zien.
Belangrijk: Alle code die wij hier gebruiken kun je vanuit de console uitvoeren. Wij raden echter aan om het in een R Script te bewaren. Zo kun je goed elke stap bijhouden. Begrijp je niet goed wat we hiermee bedoelen, lees dan eerst onze handleiding over werken met R in RStudio.
head(counties)
census_id | state | county | region | metro | population | men | women | hispanic | white | black | native | asian | pacific | citizens | income | income_err | income_per_cap | income_per_cap_err | poverty | child_poverty | professional | service | office | construction | production | drive | carpool | transit | walk | other_transp | work_at_home | mean_commute | employed | private_work | public_work | self_employed | family_work | unemployment | land_area |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1001 | Alabama | Autauga | South | Metro | 55221 | 26745 | 28476 | 2.6 | 75.8 | 18.5 | 0.4 | 1.0 | 0 | 40725 | 51281 | 2391 | 24974 | 1080 | 12.9 | 18.6 | 33.2 | 17.0 | 24.2 | 8.6 | 17.1 | 87.5 | 8.8 | 0.1 | 0.5 | 1.3 | 1.8 | 26.5 | 23986 | 73.6 | 20.9 | 5.5 | 0.0 | 7.6 | 594.44 |
1003 | Alabama | Baldwin | South | Metro | 195121 | 95314 | 99807 | 4.5 | 83.1 | 9.5 | 0.6 | 0.7 | 0 | 147695 | 50254 | 1263 | 27317 | 711 | 13.4 | 19.2 | 33.1 | 17.7 | 27.1 | 10.8 | 11.2 | 84.7 | 8.8 | 0.1 | 1.0 | 1.4 | 3.9 | 26.4 | 85953 | 81.5 | 12.3 | 5.8 | 0.4 | 7.5 | 1589.78 |
1005 | Alabama | Barbour | South | Nonmetro | 26932 | 14497 | 12435 | 4.6 | 46.2 | 46.7 | 0.2 | 0.4 | 0 | 20714 | 32964 | 2973 | 16824 | 798 | 26.7 | 45.3 | 26.8 | 16.1 | 23.1 | 10.8 | 23.1 | 83.8 | 10.9 | 0.4 | 1.8 | 1.5 | 1.6 | 24.1 | 8597 | 71.8 | 20.8 | 7.3 | 0.1 | 17.6 | 884.88 |
1007 | Alabama | Bibb | South | Metro | 22604 | 12073 | 10531 | 2.2 | 74.5 | 21.4 | 0.4 | 0.1 | 0 | 17495 | 38678 | 3995 | 18431 | 1618 | 16.8 | 27.9 | 21.5 | 17.9 | 17.8 | 19.0 | 23.7 | 83.2 | 13.5 | 0.5 | 0.6 | 1.5 | 0.7 | 28.8 | 8294 | 76.8 | 16.1 | 6.7 | 0.4 | 8.3 | 622.58 |
1009 | Alabama | Blount | South | Metro | 57710 | 28512 | 29198 | 8.6 | 87.9 | 1.5 | 0.3 | 0.1 | 0 | 42345 | 45813 | 3141 | 20532 | 708 | 16.7 | 27.2 | 28.5 | 14.1 | 23.9 | 13.5 | 19.9 | 84.9 | 11.2 | 0.4 | 0.9 | 0.4 | 2.3 | 34.9 | 22189 | 82.0 | 13.5 | 4.2 | 0.4 | 7.7 | 644.78 |
1011 | Alabama | Bullock | South | Nonmetro | 10678 | 5660 | 5018 | 4.4 | 22.2 | 70.7 | 1.2 | 0.2 | 0 | 8057 | 31938 | 5884 | 17580 | 2055 | 24.6 | 38.4 | 18.8 | 15.0 | 19.7 | 20.1 | 26.4 | 74.9 | 14.9 | 0.7 | 5.0 | 1.7 | 2.8 | 27.5 | 3865 | 79.5 | 15.1 | 5.4 | 0.0 | 18.0 | 622.81 |
Deze dataset bevat heel veel informatie, maar maak je geen zorgen, we gaan maar met een paar variabelen tegelijk werken!
Deze tabel bevat informatie over de mensen die in elke county wonen, zoals de bevolking, het werkloosheidspercentage, hun inkomen, en de verdeling naar ras en geslacht. Dit betekent dat er heel wat vragen zijn die we aan onze data kunnen stellen.
Select
Me de functie select()
van dplyr verfijn je je kolomselecties. Meestal zijn lang niet alle kolommen in een dataset relevant en zorgen te veel kolommen voor een slecht overzicht. Met select()
specificeer je simpelweg welke kolommen je wilt selecteren. Bovendien kun je ook kolomnamen veranderen binnen de select functie.
counties %>%
select(state, county, population, unemployment)
state | county | population | unemployment |
---|---|---|---|
Alabama | Autauga | 55221 | 7.6 |
Alabama | Baldwin | 195121 | 7.5 |
Alabama | Barbour | 26932 | 17.6 |
Alabama | Bibb | 22604 | 8.3 |
Alabama | Blount | 57710 | 7.7 |
Alabama | Bullock | 10678 | 18.0 |
Alabama | Butler | 20354 | 10.9 |
Alabama | Calhoun | 116648 | 12.3 |
Alabama | Chambers | 34079 | 8.9 |
Alabama | Cherokee | 26008 | 7.9 |
... | ... | ... | ... |
Opslaan als nieuw dataframe
counties_selected <- counties %>%
select(state, county, population, unemployment)
head(counties_selected)
state | county | population | unemployment |
---|---|---|---|
Alabama | Autauga | 55221 | 7.6 |
Alabama | Baldwin | 195121 | 7.5 |
Alabama | Barbour | 26932 | 17.6 |
Alabama | Bibb | 22604 | 8.3 |
Alabama | Blount | 57710 | 7.7 |
Arrange
De functie arrange()
sorteert rijen in het dataframe op basis van een de waarde in een specifieke kolom die je als argument meegeeft met de functie. Dit is vergelijkbaar met "order by" in SQL.
Oplopend
counties_selected %>%
arrange(population)
state | county | population | unemployment |
---|---|---|---|
Hawaii | Kalawao | 85 | 0 |
Texas | King | 267 | 5.1 |
Nebraska | McPherson | 433 | 0.9 |
Montana | Petroleum | 443 | 6.6 |
Nebraska | Arthur | 448 | 4 |
Nebraska | Loup | 548 | 0.7 |
... | ... | ... | ... |
Aflopend
counties %>%
arrange(desc(population))
state | county | population | unemployment |
---|---|---|---|
California | Los Angeles | 10038388 | 10 |
Illinois | Cook | 5236393 | 10.7 |
Texas | Harris | 4356362 | 7.5 |
Arizona | Maricopa | 4018143 | 7.7 |
California | San Diego | 3223096 | 8.7 |
California | Orange | 3116069 | 7.6 |
... | ... | ... | ... |
Filter
De filter()
functie lijkt op de SQL "where"-clausule. Het returned alle rijen die aan het gegeven filtercriterium voldoen. Binnen de functie filter() worden logische en booleaanse operatoren gebruikt, zoals (<
, >
, !=
,==
, |
,&
, is.na()
, !is.na()
, %in%
) om condities en expressies binnen de filter aan te geven.
Verwar deze functie niet met select()
. Hoewel beide functies data selecteren, selecteert filter()
rijen. Daarentegen selecteert select()
juist kolommen.
counties_selected %>%
arrange(desc(population)) %>%
filter(state == "New York")
state | county | population | unemployment |
---|---|---|---|
New York | Kings | 2595259 | 10 |
New York | Queens | 2301139 | 8.6 |
New York | New York | 1629507 | 7.5 |
New York | Suffolk | 1501373 | 6.4 |
New York | Bronx | 1428357 | 14 |
New York | Nassau | 1354612 | 6.4 |
... | ... | ... | ... |
Meerdere Condities
counties_selected %>%
arrange(desc(population)) %>%
filter(state == "New York", unemployment < 6)
state | county | population | unemployment |
---|---|---|---|
New York | Tompkins | 103855 | 5.9 |
New York | Chemung | 88267 | 5.4 |
New York | Madison | 72427 | 5.1 |
New York | Livingston | 64801 | 5.4 |
New York | Seneca | 35144 | 5.5 |
Mutate
Met de mutate()
functie maak je een nieuwe kolom in je dataframe op basis van andere kolommen in je dataframe. Zo maken wij bijvoorbeeld een nieuwe kolom aan doordat wij het percentage van werkloosheid per county vermenigvuldigen met de bevolkingsgrootte van elke county. Zo krijgen we een nieuwe kolom die het aantal mensen dat werkloos is per county bevat.
counties_selected %>%
mutate(unemployed_population = population * unemployment / 100)
state | county | population | unemployment | unemployed_population |
---|---|---|---|---|
Alabama | Autauga | 55221 | 7.6 | 4196.796 |
Alabama | Baldwin | 195121 | 7.5 | 14634.075 |
Alabama | Barbour | 26932 | 17.6 | 4740.032 |
Alabama | Bibb | 22604 | 8.3 | 1876.132 |
Alabama | Blount | 57710 | 7.7 | 4443.67 |
Alabama | Bullock | 10678 | 18 | 1922.04 |
... | ... | ... | ... | ... |
Combineren met Arrange()
counties_selected %>%
mutate(unemployed_population = population * unemployment / 100) %>%
arrange(desc(unemployed_population))
state | county | population | unemployment | unemployed_population |
---|---|---|---|---|
California | Los Angeles | 10038388 | 10 | 1003838.8 |
Illinois | Cook | 5236393 | 10.7 | 560294.051 |
Texas | Harris | 4356362 | 7.5 | 326727.15 |
Arizona | Maricopa | 4018143 | 7.7 | 309397.011 |
California | Riverside | 2298032 | 12.9 | 296446.128 |
California | San Diego | 3223096 | 8.7 | 280409.352 |
... | ... | ... | ... | ... |
Samenvatting
Door commando's aan elkaar te "pipen" met dplyr ontstaat R code die beknopt is, waardoor het gemakkelijker te schrijven én gemakkelijker te begrijpen is.
Je vraagt je misschien af, 'Hoe werkt dit?'. Het resultaat van elke operatie (select
,filter
, arrange
,mutate
) wordt doorgegeven aan de volgende "gepipte" functie eronder. Op deze manier hoef je de gegevens van elke stap niet op te slaan in een nieuw dataframe.
In het begin is dit waarschijnlijk vreemd, maar door te oefenen krijg je de functionaliteit van dplyr snel onder de knie. Je zult merken dat elk R script dat je in de toekomst schrijft beter zal zijn door gebruik te maken van dplyr. Je R dataverwerking zal beknopter en begrijpelijker zijn, en je zult merker dat je aanzienlijk minder tijd nodig hebt.
Wil jij goed leren werken in R? Tijdens onze Opleiding R leer je alles wat je nodig hebt om zelfstandig analyses uit te voeren in R en RStudio.
Peter is een ervaren data scientist en python trainer. Na zijn studie aan de Technische Universiteit Delft heeft hij zich altijd bezig gehouden met data en diverse programmeertalen. Peter heeft veel data analyses uitgevoerd en processen geautomatiseerd met Python in productieomgevingen.