Basisvaardigheden in R: Gegevens binnen en buiten R krijgen
Omgaan met ontbrekende waarden (NA's) tijdens en na data import
NA en NaN: hoe kun je hiermee omgaan? Tot nu toe hebben we alleen gewerkt met datasets waarin alle gegeven compleet aanwezig waren. Maar dit is eerder uitzondering dan regel; veel vaker ontbreken er waarden in een dataset. Ontbrekende waarden worden in R aangeduid als NA (Not Available) in numerieke data sets en als <NA> in factoren. Let op NA is een andere aanduiding dan NaN ; het laatste is een acroniem voor Not a Number. Deling door nul levert zo'n waarde op in de volgende sessie:
> 0/0 [1] NaN > 1/0-1/0 [1] NaN
Ontbrekende waarden leiden tot problemen bij het uitvoeren van R functies. Bijvoorbeeld, in onderstaande sessie levert optelling van elementen van de vector y
geen getal op:
> y <- c(1,2, NA, 3)
> class(y)
[1] "numeric"
> sum(y)
[1] NA
Maar gelukkig hebben veel functies een optie na.rm=TRUE
om aan te geven dat ontbrekende waarden verwijderd mogen worden voordat de functie toegepast wordt:
> sum(y, na.rm=TRUE)
[1] 6
Het opsporen van ontbrekende waarden in een object kan met de functie is.na()
. In het resultaat van aanroepen van deze functie is een logisch object waarin de locatie(s) aangegeven worden waar waarden ontbreken. Het weghalen van ontbrekende waarde kan m.b.v. de functie na.omit()
.
> is.na(y) [1] FALSE FALSE TRUE FALSE
> which(is.na(y)) # welke positie heeft geen waarde? [1] 3
> na.omit(y) [1] 1 2 3 attr(,"na.action") [1] 3 attr(,"class") [1] "omit"
De eerste regel van de laatste uitvoer is een vector zonder ontbrekende waarden. De volgende twee regels geven de locatie aan waar een waarde ontbreekt. Wil je alleen maar een vector met waarden hebben, doe dan het volgende:
> opgeschoonde_y <- as.numeric(na.omit(y)) > str(opgeschoonde_y) num [1:3] 1 2 3
Sommatie van de waarden gaat nu zonder problemen:
> sum(opgeschoonde_y) [1] 6
Dataset voor voorbeelden Laten we kijken naar een voorbeeld van een incomplete dataset van tentamencijfers van studenten. We creëren een fictieve dataset met ontbrekende waarden en schrijven de gegevens met de functie write.table()
weg naar een csv bestand.:
> studentID <- c(101, 34, "", 104, 111, 83) > voornaam <- c("Jan", "Johan", "", "Daniel", "", "Nadia") > achternaam <- c("Jansen", "Peeters", "Jansen", "Smit", "Bakker", "Visser") > wiskunde <- c(7.5, 4.5, 8, "", 9, 10) > statistiek <- c(5, 5, 8.5, 6.5, 9, 9.5) > cijfers <- data.frame(studentID, voornaam, achternaam, wiskunde, statistiek) > cijfers studentID voornaam achternaam wiskunde statistiek 1 101 Jan Jansen 7.5 5.0 2 34 Johan Peeters 4.5 5.0 3 Jansen 8 8.5 4 104 Daniel Smit 6.5 5 111 Bakker 9 9.0 6 83 Nadia Visser 10 9.5 > setwd("C:/temp") > write.table(cijfers, file="cijfers.csv", sep = ",")
Importeren van een dataset met ontbrekende gegevens Wanneer data wordt geïmporteerd kunnen ontbrekende waarden op allerlei manieren in de tabel staan, bijvoorbeeld: "meting mislukt", "kwijt" of gewoon een leeg veld zoals in ons voorbeeld met tentamencijfers. Tijdens het importeren van data kan in de functie read.table()
via de optie na.strings=...
aangegeven worden op welke manier ontbrekende waarden in de dataset gemarkeerd zijn. De functie maakt vervolgens van deze missende waarden NA
en <NA>
waarden die door de meeste functies in R kunnen worden geïnterpreteerd. In ons voorbeeld waarin lege velden ontbrekende waarden aanduiden wordt de optie na.strings=""
, maar als we een liggende streepje - hadden gebruikt als aanduiding, dan zouden we na.strings="-"
gebruiken. Met na.strings=c("-", "?", "")
geef je aan dat een liggend streepje, een vraagteken en een leeg veld gebruikt kunnen zijn in het te importeren bestand voor ontbrekende waarden.
> df_cijfers <- read.table(file="cijfers.csv", header=TRUE, sep = ",", na.strings="") > df_cijfers studentID voornaam achternaam wiskunde statistiek 1 101 Jan Jansen 7.5 5.0 2 34 Johan Peeters 4.5 5.0 3 NA <NA> Jansen 8.0 8.5 4 104 Daniel Smit NA 6.5 5 111 <NA> Bakker 9.0 9.0 6 83 Nadia Visser 10.0 9.5
Omgaan met ontbrekende gegevens We willen vaak weten of een dataset missende waarde bevat. De functie na.fail()
geeft het object terug als er niks ontbreekt en geeft anders een waarschuwing. Soms kun je de ontbrekende gegevens omzeilen. Als we bijvoorbeeld het gemiddelde cijfer voor de wiskunde toets willen uitrekenen, dan kan dit door de ontbrekende waarden negeren:
> mean(df_cijfers$wiskunde, na.rm=TRUE)
[1] 7.8
In veel gevallen willen we verder werken met een subset van de data zonder de ontbrekende waarden. De locaties waar waarden ontbreken spoor je op met de functie is.na()
. De functie complete.cases()
levert een logische vector op die aangeeft welke rijen compleet zijn, d.w.z. die geen ontbrekende waarden bevatten. In ons voorbeeld zijn dit de eerste twee rijen en de laatste rij van de ingelezen tabel. Je kunt de rijen met ontbrekende gegevens weghalen met de functie na.omit()
.
> na.fail(df_cijfers) # komt er een ontbrekende waarde voor? Error in na.fail.default(df_cijfers) : missing values in object
> is.na(df_cijfers) # test op welke posities een waarde ontbreekt studentID voornaam achternaam wiskunde statistiek 1 FALSE FALSE FALSE FALSE FALSE 2 FALSE FALSE FALSE FALSE FALSE 3 TRUE TRUE FALSE FALSE FALSE 4 FALSE FALSE FALSE TRUE FALSE 5 FALSE TRUE FALSE FALSE FALSE 6 FALSE FALSE FALSE FALSE FALSE
> na.omit(df_cijfers) # haal rijen met een ontbrekende waarde weg studentID voornaam achternaam wiskunde statistiek 1 101 Jan Jansen 7.5 5.0 2 34 Johan Peeters 4.5 5.0 6 83 Nadia Visser 10.0 9.5
Wil je rijen weghalen met een ontbrekende waarde in een bepaalde kolom dan moet je specifieker zijn. Stel dat je de regels in de tabel wilt weghalen waarin een studentID-waarde ontbreekt, dan kan dat als volgt:
> df <- df_cijfers[!(is.na(df_cijfers$studentID)), ] > df # rij met ontbrekend studentID is weggehaald studentID voornaam achternaam wiskunde statistiek 1 101 Jan Jansen 7.5 5.0 2 34 Johan Peeters 4.5 5.0 4 104 Daniel Smit NA 6.5 5 111 <NA> Bakker 9.0 9.0 6 83 Nadia Visser 10.0 9.5
Stel dat je alle kolommen in het laatste dataframe wilt weghalen waarin waarden ontbreken transponeer de tabel dan eerst met de functie t()
, verwijder rijen met ontbrekende waarden, transponeer het tussenresultaat weer, maak er weer een dataframe van, en zorg dat kolommen een gewenst datatype hebben i.p.v. van Factor. In ons voorbeeld kunnen we dit als volgt doen voor de numerieke kolommen:
> opgeschoonde_df <- as.data.frame(t(na.omit(t(df)))) > with(opgeschoonde_df, { + studentID <- as.numeric(as.character(studentID)) + statistiek <- as.numeric(as.character(statistiek)) + }) > opgeschoonde_df # kolommen met ontbrekende waarde weggehaald studentID achternaam statistiek 1 101 Jansen 5.0 2 34 Peeters 5.0 4 104 Smit 6.5 5 111 Bakker 9.0 6 83 Visser 9.5
Hierna kunnen we bijvoorbeeld zonder problemen het gemiddelde cijfer voor het statistiekexamen berekenen uit bovenstaande tabel:
> mean(opgeschoonde_df$statistiek) # gemiddeld cijfer voor statistiekexamen [1] 7.25