Inleiding Programmeren + R

Impliciete lus

» Start

Impliciete lus


Een van de sterke punten van R is dat je in veel gevallen zonder lus constructie toch alle elementen in een vector of een matrix kan bewerken. Je kunt bijvoorbeeld in 1 keer een getal optellen bij een matrix of een vector, zonder dat je een lus moet programmeren waarin je alle elementen van de matrix of vector 1 voor 1 bezoekt om er vervolgens 1 bij op te kunnen tellen, of met 10 te vermenigvuldigen:

    

    > x <- 1:10

    > y <- x * 10

    > y

    [1] 10 20 30 40 50 60 70 80 90 100 

    

Verder kent R nog de functie apply met behulp waarvan we een willekeurige functie (van R, of zelf geschreven) kunnen toepassen op de rijen of kolommen van een matrix. Stel we willen de getallen in de kolommen van matrix QQQ optellen. Het is niet nodig daarvoor een lus te schrijven. We kunnen apply gebruiken:

    

    # eerst even de data binnenhalen

    > QQQ<-read.table("http://www.mzandee.nl/ab07/data/data.txt")

    # som van alle elementen in elke kolom

    > kolsom <- apply(QQQ, 2, sum)

    > kolsom

         V1      V2      V3 

    11711.5  4860.0  1064.1

    # gemiddelde van alle elementen in elke kolom

    > kolgem <- apply(QQQ, 2, mean)

    kolgem

           V1        V2        V3 

    177.44697  73.63636  16.12273 

    

Om de functie sum op de rijen toe te passen i.p.v. de kolommen wijzigen we de het argument 2 van apply in een 1 [de eerste index van een matrix geeft de rijen aan, de tweede de kolommen].


Er bestaat ook een functie lapply die het zelfde werkt als apply, maar dan op een lijst in plaats van een matrix. En dan is er nog de functie tapply die op vectoren werkt. De functie tapply heeft een argument nodig waarmee de elementen in de vector worden gegroepeerd, een zg factor. We willen bijvoorbeeld de gemiddelde lichaamslengte weten van personen gegroepeerd op oogkleur:


    # eerst even de data binnenhalen

    > QQQ<-read.table("http://www.mzandee.nl/ab07/data/gegevens.txt")

    > attach(QQQ)

    > names(QQQ)

    [1] "lichaam"  "arm"      "pols"     "geslacht" "hand"     "ogen"    

    > tapply(lichaam, ogen, mean)

       blauw    bruin    grijs    groen    zwart 

    175.7500 178.0769 176.0000 180.6190 154.0000 


Het is dus niet nodig om een lus te schrijven waarin we de verschillende elementen in de vector lichaam bezoeken, en afhankelijk van hun waarde in de variabele ogen de gemiddelde lichaamslengte berekenen. Zoals bijvoorbeeld:

    

    > blauw<-bruin<-grijs<-groen<-zwart<-NULL

    > for(teller in 1:length(lichaam)){

    + if(ogen[teller]=="blauw") blauw<-c(blauw,lichaam[teller])

    + if(ogen[teller]=="bruin") bruin<-c(bruin,lichaam[teller])

    + if(ogen[teller]=="grijs") grijs<-c(grijs,lichaam[teller])

    + if(ogen[teller]=="groen") groen<-c(groen,lichaam[teller])

    + if(ogen[teller]=="zwart") zwart<-c(zwart,lichaam[teller])

    + }

    > c(mean(blauw),mean(bruin),mean(grijs),mean(groen),mean(zwart))

    [1] 175.7500 178.0769 176.0000 180.6190 154.0000

    

Een ander bijzonder krachtig instrument om impliciet lussen mee te programmeren is de functie replicate. Replicate heeft 2 argumenten: het eerste moet een positief geheel getal x zijn. Het tweede argument is de expressie die x keer zal worden uitgevoerd. 

We willen bijvoorbeeld een histogram maken van de uitkomst van 1000 experimenten in elk waarvan we de gemiddelde waarde berekenen van 100 worpen met een dobbelsteen:


hist(replicate(1000, mean(sample(1:6, 100, replace=TRUE))))


De functie sample trekt 100 keer random een getal uit de reeks 1, 2, 3, 4 , 5, 6,  met teruglegging. We berekenen voor elke 100 trekkingen het gemiddelde, en dat berekenen van het gemiddelde over 100 trekkingen herhalen we 1000 keer.