Programmeren in R: de basis: Introductie
Functies toepassen op datastructuren
Alle functies hieronder met "apply" in hun naam bieden een vorm van impliciete herhaling: ze passen allemaal een functie herhaaldelijk toe op onderdelen van een invoerobject en verzamelen de resultaten in een enkele structuur.
apply De R functie apply
() stelt je in staat om een functie toe te passen op een array, matrix of dataframe. Dit kun je op verschillende manieren doen, afhankelijk van de waarde die je opgeeft voor het argument MARGIN
:
1
voor toepassing per rij,2
voor toepassing per kolom,c(1,2)
voor toepassing per rij en kolom (vooral voor meerdimensionale arrays).
Afhankelijk van het type invoerobject en de gebruikte functie geeft apply()
een vector, een lijst, een matrix of een array als uitvoer. De functie die wordt doorgegeven kan een ingebouwde R-functie zijn of een functie die je zelf hebt gedefinieerd.
Een voorbeeld met een matrix zal verduidelijken wat er met het bovenstaande wordt bedoeld. Bekijk de instructies en de resultaten goed.
> M <- matrix((1:12), nrow = 3); M [,1] [,2] [,3] [,4] [1,] 1 4 7 10 [2,] 2 5 8 11 [3,] 3 6 9 12 > mean(M) # gemiddelde van alle matrixelementen [1] 6.5 > mean(1:12) # gemiddelde van alle natuurlijke getallen van 1 t/m 12 [1] 6.5 > apply(M, MARGIN = 1, FUN = mean) # gemiddelde per rij [1] 5.5 6.5 7.5 > apply(M, MARGIN = 2, FUN = mean) # gemiddelde per kolom [1] 2 5 8 11
> apply(M[, c(1,3)], MARGIN = 2, FUN = mean) # gemiddelde van kolom 1 en van kolom 3 [1] 2 8
> apply(M, MARGIN = 2, FUN = cumsum) # cumulatieve kolsommen [,1] [,2] [,3] [,4] [1,] 1 4 7 10 [2,] 3 9 15 21 [3,] 6 15 24 33
> apply(M, MARGIN = 1, FUN = range) # minimum en maximum van rijen [,1] [,2] [,3] [1,] 1 2 3 [2,] 10 11 12
> F <- function(x) { x + sample(c(-1,0,1), size = 1)}
> set.seed(123)
> F(M) # bij alle matrixelement wordt een vast willekeurig gegenereerd getal opgeteld [,1] [,2] [,3] [,4] [1,] 2 5 8 11 [2,] 3 6 9 12 [3,] 4 7 10 13
> set.seed(123)
> apply(M, MARGIN = c(1,2), FUN = F) - M # willekeurige verandering van elke matrixelement [,1] [,2] [,3] [,4] [1,] 1 0 0 -1 [2,] 1 1 0 0 [3,] 1 0 1 0
lapply De functie lapply()
is een variant van apply()
die een vector, lijst of dataframe als invoer accepteert en altijd een lijst retourneert de letter "l" in de functienaam staat voor "lijst"). De gespecificeerde functie wordt toegepast op elk element van het invoerobject, waardoor de lengte van de resulterende lijst altijd gelijk is aan de lengte van het invoerobject. Je kunt zo'n lijst omzetten in een vector met behulp van de functie unlist()
.
De syntax van de functie lapply()
is vergelijkbaar met de syntax van apply()
, alleen is hier geen behoefte aan de parameter
MARGIN
omdat de functie elementgewijs wordt toegepast voor lijsten en vectoren, en kolomsgewijs voor dataframes.
We presenteren twee eenvoudige voorbeelden, maar let goed op de instructies en hun resultaten..
> filmtitels <- c("ALIENS", "FROZEN", "GRAVITY", "MALEFICENT") > filmtitels_kleingeletterd <- lapply(movie_titles, FUN = tolower) > str(filmtitels_kleingeletterd) List of 4 $ : chr "aliens" $ : chr "frozen" $ : chr "gravity" $ : chr "maleficent" > unlist(filmtitels_kleingeletterd) [1] "aliens" "frozen" "gravity" "maleficent"
> v <- c(1,2,3); w <- c(4,5,6); df <- data.frame(v,w)
> df v w 1 1 4 2 2 5 3 3 6 > lapply(df, FUN = mean) # bereken het gemiddelde van v en van w $v [1] 2 $w [1] 5 > lapply(df, FUN = cumsum) # bereken de cummulatieve som van v en van w $v [1] 1 3 6 $w [1] 4 9 15
sapply en vapply De functie sapply()
is een gebruiksvriendelijke versie en een zogenaamde wrapper van de functie lapply()
en retourneert standaard een vector, matrix of, indien het argument simplify = "array"
is gespecificeerd, indien van toepassing, een array. Deze functie accepteert dus een lijst, vector of gegevensframe als invoer en geeft een uitvoer als een vector, matrix of array.
De functie vapply()
lijkt op sapply()
, maar heeft een vooraf getypeerde retourwaarde, en dus kan het veiliger (en soms sneller) zijn om deze functie te gebruiken.
Laten we dezelfde voorbeelden gebruiken als in de uitleg van lapply()
:
> filmtitels <- c("ALIENS", "FROZEN", "GRAVITY", "MALEFICENT") > filmtitels_kleingeletterd <- sapply(filmtitels, FUN = tolower) > str(filmtitels_kleingeletterd) Named chr [1:4] "aliens" "frozen" "gravity" "maleficent" - attr(*, "names")= chr [1:4] "ALIENS" "FROZEN" "GRAVITY" "MALEFICENT" > filmtitels_kleingeletterd ALIENS FROZEN GRAVITY MALEFICENT "aliens" "frozen" "gravity" "maleficent"
> vapply(filmtitels, FUN = tolower, FUN.VALUE = "chr") ALIENS FROZEN GRAVITY MALEFICENT "aliens" "frozen" "gravity" "maleficent"
> v <- c(1,2,3); w <- c(4,5,6); df <- data.frame(v,w) > df v w 1 1 4 2 2 5 3 3 6 > sapply(df, FUN = mean) # bereken het gemiddelde van v en van w v w 2 5 > sapply(df, FUN = cumsum) # bereken de cummulatieve som van v en van w v w [1,] 1 4 [2,] 3 9 [3,] 6 15
tapply De functie tapply(X = ..., INDEX = ..., FUN = ...)
splitst de gegevens van het invoerargument X
, gebaseerd op de levels van het invoerargument INDEX
, en past vervolgens de opgegeven functie toe die is gespecificeerd in het invoerargument FUN
. In het geval INDEX
een lijst van twee factoren is, dan wordt een kruistabel gemaakt; in het geval \(n\ge 3\) factoren is opgegeven, dan wordt een \(n\)-weg contingentietabel geconstrueerd. Dit verklaart de "t" als het eerste karakter in de functienaam: het kan worden gebruikt om een tabel te maken."
Een eenvoudig voorbeeld van het gebruik van tapply()
betreft gegevens van een team van acht universiteitsdocenten, waarvan het maandsalaris en functieniveau bekend zijn. We gebruiken de functie tapply()
om het gemiddelde maandsalaris per functieniveau te berekenen. We laten ook zien hoe het gemiddelde maandsalaris en de standaarddeviatie per functieniveau kunnen worden berekend voor dit team van universiteitsdocenten.
> maandsalaris <- c(7305, 3877, 4786, 4494, 6002, 5705, 6305, 5705) > functieniveau <- c("D1", "D4", "D4", "D3", "D1", "D2", "D2", "D3") > tapply(X = maandsalaris, INDEX = functieniveau, FUN = mean) D1 D2 D3 D4 6653.5 6005.0 5099.5 4331.5
> # Hierna, het gemiddelde maandsalaris en de standaarddeviatie per functieniveau
> tapply(X = maandsalaris, INDEX = functionniveau, FUN = function(x) {c(mean(x), sd(x))}) $D1 [1] 6653.5000 921.3601 $D2 [1] 6005.0000 424.2641 $D3 [1] 5099.5000 856.3063 $D4 [1] 4331.5000 642.7601
In het tweede voorbeeld gebruiken we de ingebouwde dataset mtcars
en berekenen we het gemiddelde vermogen van auto's (paardenkracht hp
) met een bepaald aantal versnellingen (gears
). We maken ook een kruistabel van het gemiddelde vermogen van auto's ten opzichte van het aantal cilinders (cyl
) en het aantal versnellingen. De waarde NA
in de uitvoer betekent dat er geen auto in de dataset is met 8 cilinders en 4 versnellingen.
> with(mtcars, tapply(X = hp, INDEX = gear, FUN = mean)) 3 4 5 176.1333 89.5000 195.6000 > with(mtcars, tapply(X = hp, INDEX = list(cyl, gear), FUN = mean)) 3 4 5 4 97.0000 76.0 102.0 6 107.5000 116.5 175.0 8 194.1667 NA 299.5