Bootstrap is een methode om uitspraken te doen over een populatie op basis van steekproefdata. Bradley Efron introduceerde het voor het eerst in dit artikel in 1979. Bootstrap berust op steekproeven met teruglegging uit de steekproefdata. Met deze techniek kun je de standaardfout van om het even welke statistiek schatten en er een betrouwbaarheidsinterval (CI) voor verkrijgen. Bootstrap is vooral nuttig wanneer een CI geen gesloten vorm heeft, of wanneer die erg ingewikkeld is.
Stel, we hebben een steekproef van n elementen: X = {x1, x2, …, xn} en we zijn geïnteresseerd in een CI voor een of andere statistiek T = t(X). Het bootstrap-kader is rechttoe rechtaan. We herhalen R keer het volgende schema: Neem bij de i-de herhaling een steekproef met teruglegging van n elementen uit de beschikbare steekproef (sommige worden meer dan eens gekozen). Noem deze nieuwe steekproef de i-de bootstrapsteekproef, Xi, en bereken de gewenste statistiek Ti = t(Xi).
Als resultaat krijgen we R waarden van onze statistiek: T1, T2, …, TR. We noemen dit bootstraprealisaties van T of een bootstrapverdeling van T. Op basis daarvan kunnen we een CI voor T berekenen. Er zijn verschillende manieren om dit te doen. Percentielen nemen lijkt de eenvoudigste.
Bootstrap in de praktijk
Laten we (weer eens) de bekende iris-dataset gebruiken. Kijk even naar de eerste paar rijen:
Stel dat we CIs willen vinden voor de mediaan van Sepal.Length, de mediaan van Sepal.Width en Spearmans rangcorrelatiecoëfficiënt tussen deze twee. We gebruiken het boot-pakket van R en een functie genaamd... boot. Om die kracht te benutten, moeten we een functie maken die onze statistiek(en) uit de geresamplede data berekent. Die moet minstens twee argumenten hebben: een dataset en een vector met indices van de elementen uit de dataset die gekozen zijn om een bootstrapsteekproef te vormen.
Als we CIs voor meer dan één statistiek tegelijk willen berekenen, moet onze functie ze als één enkele vector teruggeven.
Voor ons voorbeeld kan dat er zo uitzien:
library(boot)
foo <-function(data, indices){
dt<-data[indices,]
c(
cor(dt[,1], dt[,2], method='s'),
median(dt[,1]),
median(dt[,2]))}Mogelijk gemaakt door
foo kiest de gewenste elementen (welke nummers in indices staan) uit data en berekent de correlatiecoëfficiënt van de eerste twee kolommen (method='s' kiest Spearmans rangcoëfficiënt, method='p' geeft Pearsons coëfficiënt) en hun medianen.
We kunnen ook extra argumenten toevoegen, bv. de gebruiker het type correlatiecoëfficiënt laten kiezen:
foo <-function(data, indices, cor.type){
dt<-data[indices,]
c(
cor(dt[,1], dt[,2], method=cor.type),
median(dt[,1]),
median(dt[,2]))}Mogelijk gemaakt door
Om deze tutorial algemener te maken, gebruik ik de laatste versie van foo.
Nu kunnen we de functie boot gebruiken. We moeten de naam van de dataset meegeven, de zojuist gemaakte functie, het aantal herhalingen (R) en extra argumenten van onze functie (zoals cor.type). Hieronder gebruik ik set.seed om dit voorbeeld reproduceerbaar te maken.
set.seed(12345)
myBootstrap <- boot(iris, foo, R=1000, cor.type='s')Mogelijk gemaakt door
De functie boot geeft een object terug van de klasse... (ja, je raadt het al!) boot. Het heeft twee interessante elementen. $t bevat R waarden van onze statistiek(en) die door de bootstrapprocedure zijn gegenereerd (bootstraprealisaties van T):
Het printen van het boot-object naar de console geeft nog wat extra informatie:
myBootstrap
#### ORDINARY NONPARAMETRIC BOOTSTRAP###### Call:## boot(data = iris, statistic = foo, R = 1000, cor.type = "s")###### Bootstrap Statistics :## original bias std. error## t1* -0.1667777 0.002546391 0.07573983## t2* 5.8000000 -0.013350000 0.10295571## t3* 3.0000000 0.007900000 0.02726414Mogelijk gemaakt door
original is hetzelfde als $t0. bias is het verschil tussen het gemiddelde van de bootstraprealisaties (die uit $t), de zogeheten bootstrapschatting van T, en de waarde in de oorspronkelijke dataset (die uit $t0).
colMeans(myBootstrap$t)-myBootstrap$t0
## [1] 0.002546391 -0.013350000 0.007900000Mogelijk gemaakt door
std. error is de standaardfout van de bootstrapschatting, gelijk aan de standaarddeviatie van de bootstraprealisaties.
apply(myBootstrap$t,2,sd)## [1] 0.07573983 0.10295571 0.02726414Mogelijk gemaakt door
Verschillende types bootstrap-CI's
Voordat we met CI aan de slag gaan, is het altijd de moeite waard om naar de verdeling van de bootstraprealisaties te kijken. We kunnen de functie plot gebruiken, met index die aangeeft naar welke van de in foo berekende statistieken we willen kijken. Hier is index=1 Spearmans correlatiecoëfficiënt tussen kelklengte en -breedte, index=2 is de mediaan van kelklengte en index=3 is de mediaan van kelkbreedte.
De verdeling van de bootstrapcorrelatiecoëfficiënten lijkt vrij normaal. Laten we er een CI voor vinden. We kunnen boot.ci gebruiken. Standaard geeft het 95%-CI's, maar dat kun je aanpassen met de parameter conf.
boot.ci(myBootstrap, index=1)## Warning in boot.ci(myBootstrap, index = 1): bootstrap variances needed for## studentized intervals## BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS## Based on 1000 bootstrap replicates#### CALL :## boot.ci(boot.out = myBootstrap, index = 1)#### Intervals :## Level Normal Basic ## 95% (-0.3178, -0.0209 ) (-0.3212, -0.0329 ) #### Level Percentile BCa ## 95% (-0.3007, -0.0124 ) (-0.3005, -0.0075 ) ## Calculations and Intervals on Original ScaleMogelijk gemaakt door
boot.ci levert 5 types bootstrap-CI's. Eén daarvan, het studentized interval, is uniek. Het heeft een schatting van de bootstrapvariantie nodig. Die hebben we niet aangeleverd, dus R geeft een waarschuwing: bootstrap variances needed for studentized intervals. Variantieschattingen kunnen verkregen worden met een bootstrap op tweede niveau of (makkelijker) met de jackknife-techniek. Dat valt enigszins buiten de scope van deze tutorial, dus we focussen op de overige vier types bootstrap-CI's.
Als we ze niet allemaal willen zien, kunnen we relevante kiezen in het argument type. Mogelijke waarden zijn norm, basic, stud, perc, bca of een vector hiervan.
boot.ci(myBootstrap, index=1, type=c('basic','perc'))## BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS## Based on 1000 bootstrap replicates#### CALL :## boot.ci(boot.out = myBootstrap, type = c("basic", "perc"), index = 1)#### Intervals :## Level Basic Percentile ## 95% (-0.3212, -0.0329 ) (-0.3007, -0.0124 ) ## Calculations and Intervals on Original ScaleMogelijk gemaakt door
De functie boot.ci maakt een object van klasse... (ja, je hebt het geraden!) bootci. De elementen heten precies zoals de types CI die in het argument type zijn gebruikt. $norm is een vector met 3 elementen die het betrouwbaarheidsniveau en de CI-grenzen bevat.
boot.ci(myBootstrap, index=1, type='norm')$norm
## conf ## [1,] 0.95 -0.3177714 -0.02087672Mogelijk gemaakt door
$basic, $stud, $perc en $bca zijn vectoren met 5 elementen die ook de percentielen bevatten die zijn gebruikt om het CI te berekenen (daar komen we zo op terug):
boot.ci(myBootstrap, index=1, type='basic')$basic
## conf ## [1,] 0.95 975.98 25.03 -0.3211981 -0.03285178Mogelijk gemaakt door
Een beetje notatie (sorry!)
Om gevoel te krijgen bij wat de verschillende types CI zijn, moeten we wat notatie introduceren. Laat dus:
t⋆ de bootstrapschatting zijn (het gemiddelde van de bootstraprealisaties),
t0 de waarde van onze statistiek in de oorspronkelijke dataset zijn,
se⋆ de standaardfout van de bootstrapschatting zijn,
b de bias van de bootstrapschatting zijn b = t⋆ − t0
α het betrouwbaarheidsniveau zijn, typisch α = 0.95,
zα de $1-\frac \alpha 2$-kwantiel van de standaardnormale verdeling zijn,
θα het α-percentiel van de verdeling van bootstraprealisaties zijn.
Percentiel-CI
Met bovenstaande notatie is het percentiel-CI:
(θ(1 − α)/2, θ1 − (1 − α)/2)
dus dit neemt simpelweg de relevante percentielen. Niet meer dan dat.
Normaal CI
Een typisch Wald-CI zou zijn:
t0 ± zα ⋅ se⋆
maar in het bootstrapgeval moeten we het corrigeren voor bias. Het wordt dan:
Het percentiel-CI wordt over het algemeen niet aanbevolen omdat het slecht presteert bij vreemd-gedaante staartverdelingen. Het basic CI (ook wel pivotal of empirical CI genoemd) is hier veel robuuster tegen. Het idee erachter is om de verschillen te berekenen tussen elke bootstraprealisatie en t0 en de percentielen van hun verdeling te gebruiken. Volledige details vind je bijvoorbeeld in L. Wassermans All of Statistics
De uiteindelijke formule voor het basic CI is:
(2t0 − θ1 − (1 − α)/2, 2t0 − θ(1 − α)/2)
BCα-CI
BCα staat voor bias-corrected, accelerated. De formule is niet heel ingewikkeld maar wel enigszins onintuïtief, dus ik sla die over. Zie het artikel van Thomas J. DiCiccio en Bradley Efron als je de details wilt.
De acceleratie in de naam van de methode vereist het gebruik van specifieke percentielen van de bootstraprealisaties. Soms kan het gebeuren dat dit extreme percentielen zijn, mogelijk uitschieters. BCα kan in zulke gevallen instabiel zijn.
Laten we naar het BCα-CI voor de mediaan van kelkbreedte kijken. In de oorspronkelijke dataset is deze mediaan precies 3.
boot.ci(myBootstrap, index=3)## Warning in boot.ci(myBootstrap, index = 3): bootstrap variances needed for## studentized intervals## Warning in norm.inter(t, adj.alpha): extreme order statistics used as## endpoints## BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS## Based on 1000 bootstrap replicates#### CALL :## boot.ci(boot.out = myBootstrap, index = 3)#### Intervals :## Level Normal Basic ## 95% ( 2.939, 3.046 ) ( 2.900, 3.000 ) #### Level Percentile BCa ## 95% ( 3.0, 3.1 ) ( 2.9, 2.9 ) ## Calculations and Intervals on Original Scale## Warning : BCa Intervals used Extreme Quantiles## Some BCa intervals may be unstableMogelijk gemaakt door
We krijgen het BCα-CI (2,9, 2,9). Dat is vreemd, maar gelukkig waarschuwde R ons dat extreme order statistics used as endpoints. Laten we precies zien wat hier gebeurde:
De verdeling van de bootstraprealisaties is ongebruikelijk. Een overgrote meerderheid (meer dan 90%) is 3.
table(myBootstrap$t[,3])#### 2.9 2.95 3 3.05 3.1 3.15 3.2## 1 1 908 24 63 1 2Mogelijk gemaakt door
In zo'n situatie springt de "acceleratie" in de BCα-methode gemakkelijk naar extreme waarden. Hier is het percentiel-CI, dat de basis vormt voor het BCα-CI, (3, 3,1). Wanneer we het nu "naar links" uitbreiden, moeten we het 0,002-percentiel gebruiken. De uitbreiding "naar rechts" gaat ook naar extremen: het 0,997-percentiel.
Reproductie van resultaten
Soms moeten we bootstraprealisaties opnieuw creëren. Als we daarvoor R kunnen gebruiken, is dat geen probleem. De functie set.seed lost het op. Het reproduceren van bootstraprealisaties in andere software zou een stuk ingewikkelder zijn. Bovendien kan voor grote R herberekenen in R ook geen optie zijn (bijvoorbeeld wegens tijdgebrek).
We kunnen dit aanpakken door de indices op te slaan van de elementen uit de oorspronkelijke dataset die elke bootstrapsteekproef vormden. Dat is wat de functie boot.array (met argument indices=T) doet.
Door indices=F te zetten (de standaard) krijgen we antwoord op de vraag: "Hoe vaak kwam elk element van de oorspronkelijke dataset voor in elke bootstrapsteekproef?". Bijvoorbeeld, in de eerste steekproef: het 1e element van de dataset kwam één keer voor, het 2e element kwam helemaal niet voor, het 3e element één keer, het 4e twee keer, enzovoort.
Een dergelijke tabel stelt ons in staat om een bootstraprealisatie buiten R te reconstrueren. Of in R zelf wanneer we set.seed niet willen gebruiken en alles opnieuw willen uitrekenen.
onceAgain<-apply(tableOfIndices,1, foo, data=iris, cor.type='s')Mogelijk gemaakt door
Laten we controleren of de resultaten hetzelfde zijn:
Wat is bootstrap?
Bootstrap is een methode om uitspraken te doen over een populatie op basis van steekproefdata. Bradley Efron introduceerde het voor het eerst in dit artikel in 1979. Bootstrap berust op steekproeven met teruglegging uit de steekproefdata. Met deze techniek kun je de standaardfout van om het even welke statistiek schatten en er een betrouwbaarheidsinterval (CI) voor verkrijgen. Bootstrap is vooral nuttig wanneer een CI geen gesloten vorm heeft, of wanneer die erg ingewikkeld is.
Stel, we hebben een steekproef van n elementen: X = {x1, x2, …, xn} en we zijn geïnteresseerd in een CI voor een of andere statistiek T = t(X). Het bootstrap-kader is rechttoe rechtaan. We herhalen R keer het volgende schema: Neem bij de i-de herhaling een steekproef met teruglegging van n elementen uit de beschikbare steekproef (sommige worden meer dan eens gekozen). Noem deze nieuwe steekproef de i-de bootstrapsteekproef, Xi, en bereken de gewenste statistiek Ti = t(Xi).
Als resultaat krijgen we R waarden van onze statistiek: T1, T2, …, TR. We noemen dit bootstraprealisaties van T of een bootstrapverdeling van T. Op basis daarvan kunnen we een CI voor T berekenen. Er zijn verschillende manieren om dit te doen. Percentielen nemen lijkt de eenvoudigste.
Bootstrap in de praktijk
Laten we (weer eens) de bekende
iris-dataset gebruiken. Kijk even naar de eerste paar rijen:Stel dat we CIs willen vinden voor de mediaan van
Sepal.Length, de mediaan vanSepal.Widthen Spearmans rangcorrelatiecoëfficiënt tussen deze twee. We gebruiken hetboot-pakket vanRen een functie genaamd...boot. Om die kracht te benutten, moeten we een functie maken die onze statistiek(en) uit de geresamplede data berekent. Die moet minstens twee argumenten hebben: eendataseten een vector metindicesvan de elementen uit de dataset die gekozen zijn om een bootstrapsteekproef te vormen.Als we CIs voor meer dan één statistiek tegelijk willen berekenen, moet onze functie ze als één enkele vector teruggeven.
Voor ons voorbeeld kan dat er zo uitzien:
fookiest de gewenste elementen (welke nummers inindicesstaan) uitdataen berekent de correlatiecoëfficiënt van de eerste twee kolommen (method='s'kiest Spearmans rangcoëfficiënt,method='p'geeft Pearsons coëfficiënt) en hun medianen.We kunnen ook extra argumenten toevoegen, bv. de gebruiker het type correlatiecoëfficiënt laten kiezen:
Om deze tutorial algemener te maken, gebruik ik de laatste versie van
foo.Nu kunnen we de functie
bootgebruiken. We moeten de naam van de dataset meegeven, de zojuist gemaakte functie, het aantal herhalingen (R) en extra argumenten van onze functie (zoalscor.type). Hieronder gebruik ikset.seedom dit voorbeeld reproduceerbaar te maken.De functie
bootgeeft een object terug van de klasse... (ja, je raadt het al!)boot. Het heeft twee interessante elementen.$tbevat R waarden van onze statistiek(en) die door de bootstrapprocedure zijn gegenereerd (bootstraprealisaties van T):$t0bevat de waarden van onze statistiek(en) in de oorspronkelijke, volledige dataset:Het printen van het
boot-object naar de console geeft nog wat extra informatie:originalis hetzelfde als$t0.biasis het verschil tussen het gemiddelde van de bootstraprealisaties (die uit$t), de zogeheten bootstrapschatting van T, en de waarde in de oorspronkelijke dataset (die uit$t0).std. erroris de standaardfout van de bootstrapschatting, gelijk aan de standaarddeviatie van de bootstraprealisaties.Verschillende types bootstrap-CI's
Voordat we met CI aan de slag gaan, is het altijd de moeite waard om naar de verdeling van de bootstraprealisaties te kijken. We kunnen de functie
plotgebruiken, metindexdie aangeeft naar welke van de infooberekende statistieken we willen kijken. Hier isindex=1Spearmans correlatiecoëfficiënt tussen kelklengte en -breedte,index=2is de mediaan van kelklengte enindex=3is de mediaan van kelkbreedte.De verdeling van de bootstrapcorrelatiecoëfficiënten lijkt vrij normaal. Laten we er een CI voor vinden. We kunnen
boot.cigebruiken. Standaard geeft het 95%-CI's, maar dat kun je aanpassen met de parameterconf.boot.cilevert 5 types bootstrap-CI's. Eén daarvan, het studentized interval, is uniek. Het heeft een schatting van de bootstrapvariantie nodig. Die hebben we niet aangeleverd, dusRgeeft een waarschuwing:bootstrap variances needed for studentized intervals. Variantieschattingen kunnen verkregen worden met een bootstrap op tweede niveau of (makkelijker) met de jackknife-techniek. Dat valt enigszins buiten de scope van deze tutorial, dus we focussen op de overige vier types bootstrap-CI's.Als we ze niet allemaal willen zien, kunnen we relevante kiezen in het argument
type. Mogelijke waarden zijnnorm,basic,stud,perc,bcaof een vector hiervan.De functie
boot.cimaakt een object van klasse... (ja, je hebt het geraden!)bootci. De elementen heten precies zoals de types CI die in het argumenttypezijn gebruikt.$normis een vector met 3 elementen die het betrouwbaarheidsniveau en de CI-grenzen bevat.$basic,$stud,$percen$bcazijn vectoren met 5 elementen die ook de percentielen bevatten die zijn gebruikt om het CI te berekenen (daar komen we zo op terug):Een beetje notatie (sorry!)
Om gevoel te krijgen bij wat de verschillende types CI zijn, moeten we wat notatie introduceren. Laat dus:
Percentiel-CI
Met bovenstaande notatie is het percentiel-CI:
dus dit neemt simpelweg de relevante percentielen. Niet meer dan dat.
Normaal CI
Een typisch Wald-CI zou zijn:
maar in het bootstrapgeval moeten we het corrigeren voor bias. Het wordt dan:
$$ t_0 - b \pm z_\alpha \cdot se^\star \\ 2t_0 - t^\star \pm z_\alpha \cdot se^\star$$
Basic CI
Het percentiel-CI wordt over het algemeen niet aanbevolen omdat het slecht presteert bij vreemd-gedaante staartverdelingen. Het basic CI (ook wel pivotal of empirical CI genoemd) is hier veel robuuster tegen. Het idee erachter is om de verschillen te berekenen tussen elke bootstraprealisatie en t0 en de percentielen van hun verdeling te gebruiken. Volledige details vind je bijvoorbeeld in L. Wassermans All of Statistics
De uiteindelijke formule voor het basic CI is:
BCα-CI
BCα staat voor bias-corrected, accelerated. De formule is niet heel ingewikkeld maar wel enigszins onintuïtief, dus ik sla die over. Zie het artikel van Thomas J. DiCiccio en Bradley Efron als je de details wilt.
De acceleratie in de naam van de methode vereist het gebruik van specifieke percentielen van de bootstraprealisaties. Soms kan het gebeuren dat dit extreme percentielen zijn, mogelijk uitschieters. BCα kan in zulke gevallen instabiel zijn.
Laten we naar het BCα-CI voor de mediaan van kelkbreedte kijken. In de oorspronkelijke dataset is deze mediaan precies 3.
We krijgen het BCα-CI (2,9, 2,9). Dat is vreemd, maar gelukkig waarschuwde
Rons datextreme order statistics used as endpoints. Laten we precies zien wat hier gebeurde:De verdeling van de bootstraprealisaties is ongebruikelijk. Een overgrote meerderheid (meer dan 90%) is 3.
In zo'n situatie springt de "acceleratie" in de BCα-methode gemakkelijk naar extreme waarden. Hier is het percentiel-CI, dat de basis vormt voor het BCα-CI, (3, 3,1). Wanneer we het nu "naar links" uitbreiden, moeten we het 0,002-percentiel gebruiken. De uitbreiding "naar rechts" gaat ook naar extremen: het 0,997-percentiel.
Reproductie van resultaten
Soms moeten we bootstraprealisaties opnieuw creëren. Als we daarvoor
Rkunnen gebruiken, is dat geen probleem. De functieset.seedlost het op. Het reproduceren van bootstraprealisaties in andere software zou een stuk ingewikkelder zijn. Bovendien kan voor grote R herberekenen inRook geen optie zijn (bijvoorbeeld wegens tijdgebrek).We kunnen dit aanpakken door de indices op te slaan van de elementen uit de oorspronkelijke dataset die elke bootstrapsteekproef vormden. Dat is wat de functie
boot.array(met argumentindices=T) doet.Elke rij is één bootstrapsteekproef. Bijv., onze eerste steekproef bevat de volgende elementen:
Door
indices=Fte zetten (de standaard) krijgen we antwoord op de vraag: "Hoe vaak kwam elk element van de oorspronkelijke dataset voor in elke bootstrapsteekproef?". Bijvoorbeeld, in de eerste steekproef: het 1e element van de dataset kwam één keer voor, het 2e element kwam helemaal niet voor, het 3e element één keer, het 4e twee keer, enzovoort.Een dergelijke tabel stelt ons in staat om een bootstraprealisatie buiten
Rte reconstrueren. Of inRzelf wanneer weset.seedniet willen gebruiken en alles opnieuw willen uitrekenen.Laten we controleren of de resultaten hetzelfde zijn:
Ja, dat zijn ze!
Wil je meer leren over Machine Learning in R? Volg dan de DataCamp-cursus Machine Learning Toolbox en bekijk de tutorial Machine Learning in R voor beginners.