Basisvaardigheden in R: Werken met functies
Wat is een functie in R?
Wat is een functie? De eenvoudigste manier om een functie te begrijpen is als een machientje die invoer verwerkt en uitvoer produceert. We kunnen deze machientje als volgt visualiseren::
Hierbij is het wel belangrijk dat het machientje bij een gegeven invoer maar één uitvoer oplevert. Het is niet vereist dat dezelfde uitvoer wordt gegenereerd wanneer dezelfde invoer wordt aangeboden; alleen de verwerking in het machientje moet hetzelfde zijn. Bijvoorbeeld, in de instructie zelf is enige randomisatie toegestaan. Het voorschrift kun je als etiket op het machinetje beschouwen waarop beschreven staat wat het machientje doet.
Voorbeeld van een wiskundig functie Onderstaande twee plaatjes met specifieke invoer tonen hoe het functiemachientje met als voorschrift "verdubbel de invoer" werkt:
Het voorschrift in dit functiemachientje kan als volgt in een formule-achtige vorm gegoten en van een naam voorzien worden:Dit functiemachientje levert bij invoer van het getal \(3\) als uitvoer het getal \(6\) op. Een willekeurige invoer, zeg \(x\), levert de uitvoer \(2x\) op. Met andere woorden \(f(3)=6\) en \(f(x)=2x\). Wiskundigen plakken dan liever als etiket op het machientje de definitie \(f(x)=2x\). De wiskundige notatie \(f: x\mapsto 2x\) lijkt een beetje op hoe de functie in R wordt gedefinieerd:
> f <- function(x) { 2*x } > f(3) [1] 6 > f(1:6) [1] 2 4 6 8 10 12
Voorbeeld van een wiskundig algoritme Een functie in R hoeft geen wiskundige functie te zijn. Soms is het gewoon een algoritme om een waarde te berekenen. Bijvoorbeeld, de functie \(e^x\) heeft de volgende machtreeksontwikkeling: \[\begin{aligned}e^x &= 1+x+\frac{x^2}{2!}+\frac{x^3}{3!}+\frac{x^4}{4!}+\cdots\\ &= \sum_{k=0}^{\infty}\frac{x^k}{k!}\end{aligned}\] Stel nu dat we veeltermfuncties \(F_n(x)\) ) het functievoorschrift geven dat het de veelterm is die je zou krijgen als je de machtreeks na \(n\) termen afkapt. Dus: \[F_n(x)=\sum_{k=0}^{n}\frac{x^k}{k!}\] Op deze manier krijgen we een reeks functies \(F_1, F_2, \cdots\) Omdat we niet elke functie afzonderlijk willen definiëren, construeren we een R-functie F
met twee argumenten, namelijk \(x\) and \(n\):
F <- function(x, n = 5) {
som_van_getallen <- 0
for (k in 0:n) {
som_van_getallen <- som_van_getallen + x^k/factorial(k)
}
return(som_van_getallen)
}
print(F(1, n = 3)) # ruwe benadering van het getal e
print(F(1)) # benadering met verstekwaarde n = 5
print(F(1, n = 8)) # goede benadering van het getal e
print(F(1, n = 10)) # nog betere benadering van het getal e
Je krijgt vier getallen als uitvoer, namelijk 2.66667, 2.716667, 2.718279 en 2.718282. De laatste instructie laat zien dat de functie voor \(n=10\) en \(x=1\) een numeriek resultaat oplevert dat de exacte waarde van \(e\), de basis van de natuurlijke logaritme, benadert met een nauwkeurigheid van 6 decimalen. De afwijking van de reeksbenadering van de exacte waarde wordt de afbreekfout van de benadering genoemd.
Voorbeeld van een functie met interactie en neveneffecten Functies in R kunnen veelzijdig van aard zijn. Ze kunnen bijvoorbeeld neveneffecten hebben, zoals het afdrukken van een bericht of het plotten van een grafiek. Bovendien kunnen ze interactief zijn, wat betekent dat er een menselijke operator is die met de functie kan communiceren, bijvoorbeeld door invoer te geven voor de uit te voeren instructies.
Als voorbeeld laten we een R-script zien waarin een functie wordt gedefinieerd die de gebruiker vraagt om drie positieve reële getallen in te voeren en vervolgens controleert of er een driehoek bestaat met de drie ingevoerde getallen als lengtes van de zijden. In beide gevallen (waar, onwaar) wordt een passend bericht afgedrukt, en wanneer zo'n driehoek bestaat, wordt een voorbeeld van een driehoek getekend. Merk op dat drie positieve reële getallen de creatie van een driehoek met de opgegeven zijden toelaten als en alleen als de som van elk paar opgegeven getallen groter is dan het andere opgegeven getal.
Stel dat je een R-bestand hebt met de naam "driehoek.R" in de map "C:/temp" op een Windows-computer. Hier is het script:
zijden_van_driehoek_Q <- function() {
p <- as.numeric(readline(prompt = 'Toets een positief getal p in: '))
q <- as.numeric(readline(prompt = 'Toets een positief getal q in: '))
r <- as.numeric(readline(prompt = 'Toets een positief getal r in: '))
if (p > 0 & q > 0 & r > 0 & p < (q + r) & q < (r + p) & r < (p + q)) {
print("Een driehoek met de gegeven lengtes van zijden is mogelijk.")
x <- (q^2 + r^2 - p^2) / (2*r)
y <- sqrt(2*p^2*(q^2 + r^2) -(q^2-r^2)^2 - p^4) / (2*r)
plot(c(0,r,x,0), c(0,0,y,0), type="l", lwd=3, xlab="", ylab="", asp=1)
} else {
print("Er bestaat geen driehoek met de gegeven lengtes van zijden.")
}
}
if(interactive()) zijden_van_driehoek_Q()
Wanneer je de instructie source("C:/temp/driehoek.R")
In de sessie hieronder geeft de uitvoer aan dat er geen driehoek bestaat met lengtes van 1, 2 en 3 voor de zijden. Dit klopt, omdat de som van de lengtes van de eerste twee zijden (1 en 2) niet groter is dan de lengte van de derde zijde (3), waardoor een geldige driehoek onmogelijk is.
> source("C:/temp/driehoek.R") Toets een positief getal p in: 3 Toets een positief getal q in: 2 Toets een positief getal r in: 1 [1] "Er bestaat geen driehoek met de gegeven lengtes van zijden."Als je de bovenstaande instructie opnieuw uitvoert en de getallen 3, 4 en 5 invoert als mogelijke lengtes van de zijden van een driehoek wanneer daarom wordt gevraagd, ontvang je een bevestiging dat de constructie van een driehoek mogelijk is en wordt er een driehoek getekend die aan de voorwaarden voldoet. Dit kan omdat de opgegeven zijden voldoen aan de regel dat de som van de lengtes van elk paar zijden groter is dan de lengte van de derde zijde.
> source("C:/temp/driehoek.R")
Toets een positief getal p in: 5
Toets een positief getal q in: 4
Toets een positief getal r in: 3
[1] "Een driehoek met de gegeven lengtes van zijden is mogelijk."