tl; dr: a partire da un set di dati generato sotto il null, ho ricampionato i casi con la sostituzione e ho condotto un test di ipotesi su ciascun set di dati ricampionato. Questi test di ipotesi respingono il nulla più del 5% delle volte.
Di seguito, una simulazione molto semplice, generi set di dati con e inserisco un modello OLS semplice per ciascuno. Quindi, per ogni set di dati, generi 1000 nuovi set di dati ricampionando le righe del set di dati originale con la sostituzione (un algoritmo specificamente descritto nel testo classico di Davison & Hinkley come appropriato per la regressione lineare). Per ognuno di questi, mi adatto allo stesso modello OLS. Alla fine, circa il 16% dei test di ipotesi all'interno dei campioni bootstrap respinge il valore nullo , mentre dovremmo ottenere il 5% (come facciamo nei set di dati originali).
Sospettavo che avesse a che fare con osservazioni ripetute che causavano associazioni gonfiate, quindi per confronto, ho provato altri due approcci nel codice qui sotto (commentato). Nel metodo 2, correggo , quindi sostituisco con residui ricampionati dal modello OLS sul set di dati originale. Nel metodo 3, disegno un sottocampione casuale senza sostituzione. Entrambe queste alternative funzionano, vale a dire che i loro test di ipotesi rifiutano il null 5% delle volte.
La mia domanda: ho ragione nel dire che il colpevole sono le osservazioni ripetute? In tal caso, dato che si tratta di un approccio standard al bootstrap, dove stiamo esattamente violando la teoria del bootstrap standard?
Aggiornamento n. 1: più simulazioni
Ho provato uno scenario ancora più semplice, un modello di regressione intercetta-solo per . Lo stesso problema si verifica.
# note: simulation takes 5-10 min on my laptop; can reduce boot.reps
# and n.sims.run if wanted
# set the number of cores: can change this to match your machine
library(doParallel)
registerDoParallel(cores=8)
boot.reps = 1000
n.sims.run = 1000
for ( j in 1:n.sims.run ) {
# make initial dataset from which to bootstrap
# generate under null
d = data.frame( X1 = rnorm( n = 1000 ), Y1 = rnorm( n = 1000 ) )
# fit OLS to original data
mod.orig = lm( Y1 ~ X1, data = d )
bhat = coef( mod.orig )[["X1"]]
se = coef(summary(mod.orig))["X1",2]
rej = coef(summary(mod.orig))["X1",4] < 0.05
# run all bootstrap iterates
parallel.time = system.time( {
r = foreach( icount( boot.reps ), .combine=rbind ) %dopar% {
# Algorithm 6.2: Resample entire cases - FAILS
# residuals of this model are repeated, so not normal?
ids = sample( 1:nrow(d), replace=TRUE )
b = d[ ids, ]
# # Method 2: Resample just the residuals themselves - WORKS
# b = data.frame( X1 = d$X1, Y1 = sample(mod.orig$residuals, replace = TRUE) )
# # Method 3: Subsampling without replacement - WORKS
# ids = sample( 1:nrow(d), size = 500, replace=FALSE )
# b = d[ ids, ]
# save stats from bootstrap sample
mod = lm( Y1 ~ X1, data = b )
data.frame( bhat = coef( mod )[["X1"]],
se = coef(summary(mod))["X1",2],
rej = coef(summary(mod))["X1",4] < 0.05 )
}
} )[3]
###### Results for This Simulation Rep #####
r = data.frame(r)
names(r) = c( "bhat.bt", "se.bt", "rej.bt" )
# return results of each bootstrap iterate
new.rows = data.frame( bt.iterate = 1:boot.reps,
bhat.bt = r$bhat.bt,
se.bt = r$se.bt,
rej.bt = r$rej.bt )
# along with results from original sample
new.rows$bhat = bhat
new.rows$se = se
new.rows$rej = rej
# add row to output file
if ( j == 1 ) res = new.rows
else res = rbind( res, new.rows )
# res should have boot.reps rows per "j" in the for-loop
# simulation rep counter
d$sim.rep = j
} # end loop over j simulation reps
##### Analyze results #####
# dataset with only one row per simulation
s = res[ res$bt.iterate == 1, ]
# prob of rejecting within each resample
# should be 0.05
mean(res$rej.bt); mean(s$rej)
Aggiornamento n. 2: la risposta
Diverse possibilità sono state proposte nei commenti e nelle risposte e ho fatto più simulazioni per testarle empiricamente. Si scopre che JWalker ha ragione sul fatto che il problema era che dovevamo centrare le statistiche bootstrap in base alla stima dei dati originali per ottenere la distribuzione di campionamento corretta sotto . Tuttavia, penso anche che anche il commento di Whuber sulla violazione dei presupposti del test parametrico sia corretto, anche se in questo caso riceviamo effettivamente falsi positivi nominali quando risolviamo il problema di JWalker.