Supponiamo che io abbia un dato con due gruppi indipendenti:
g1.lengths <- c (112.64, 97.10, 84.18, 106.96, 98.42, 101.66)
g2.lengths <- c (84.44, 82.10, 83.26, 81.02, 81.86, 86.80,
85.84, 97.08, 79.64, 83.32, 91.04, 85.92,
73.52, 85.58, 97.70, 89.72, 88.92, 103.72,
105.02, 99.48, 89.50, 81.74)
group = rep (c ("g1", "g2"), c (length (g1.lengths), length (g2.lengths)))
lengths = data.frame( lengths = c(g1.lengths, g2.lengths), group)
È evidente che la dimensione del campione per gruppo è distorta in cui g1 ha 6 osservazioni e g2 ha 22 . L'ANOVA tradizionale suggerisce che i gruppi hanno mezzi diversi quando il valore critico è impostato su 0,05 (il valore p è 0,0044 ).
summary (aov (lengths~group, data = lengths))
Dato che il mio obiettivo è confrontare la differenza media, dati sbilanciati e così piccoli campionati potrebbero dare risultati inappropriati con un approccio tradizionale. Pertanto, voglio eseguire il test di permutazione e il bootstrap.
TEST DI PERMUTAZIONE
L'ipotesi nulla (H0) afferma che i mezzi del gruppo sono gli stessi. Questa ipotesi nel test di permutazione è giustificata raggruppando i gruppi in un campione. Ciò garantisce che i campioni per due gruppi siano stati estratti dalla distribuzione identica. Ripetendo il campionamento (o più precisamente - rimescolamento) dai dati aggregati, le osservazioni vengono riallocate (mescolate) ai campioni in modo nuovo e viene calcolata la statistica del test. Eseguendo questa operazione n volte, verrà fornita la distribuzione campionaria delle statistiche del test partendo dal presupposto che H0 sia VERO. Alla fine, sotto H0, il valore p è probabilità che la statistica del test sia uguale o superiore al valore osservato.
s.size.g1 <- length (g1.lengths)
s.size.g2 <- length (g2.lengths)
pool <- lengths$lengths
obs.diff.p <- mean (g1.lengths) - mean (g2.lengths)
iterations <- 10000
sampl.dist.p <- NULL
set.seed (5)
for (i in 1 : iterations) {
resample <- sample (c(1:length (pool)), length(pool))
g1.perm = pool[resample][1 : s.size.g1]
g2.perm = pool[resample][(s.size.g1+1) : length(pool)]
sampl.dist.p[i] = mean (g1.perm) - mean (g2.perm)
}
p.permute <- (sum (abs (sampl.dist.p) >= abs(obs.diff.p)) + 1)/ (iterations+1)
Il valore p riportato del test di permutazione è 0,0053 . OK, se l'ho fatto correttamente, permutazioni e ANOVA parametrico danno risultati quasi identici.
BOOTSTRAP
Prima di tutto, sono consapevole che bootstrap non può essere d'aiuto quando le dimensioni del campione sono troppo piccole. Questo post ha dimostrato che può essere anche peggio e fuorviante . Inoltre, il secondo ha evidenziato che il test di permutazione è generalmente migliore del bootstrap quando il test di ipotesi è l'obiettivo principale. Tuttavia, questo grande post affronta importanti differenze tra i metodi ad alta intensità di computer. Tuttavia, qui voglio sollevare (credo) una domanda diversa.
Consentitemi di introdurre innanzitutto l'approccio bootstrap più comune (Bootstrap1: ricampionamento all'interno dell'esempio in pool ):
s.size.g1 <- length (g1.lengths)
s.size.g2 <- length (g2.lengths)
pool <- lengths$lengths
obs.diff.b1 <- mean (g1.lengths) - mean (g2.lengths)
iterations <- 10000
sampl.dist.b1 <- NULL
set.seed (5)
for (i in 1 : iterations) {
resample <- sample (c(1:length (pool)), length(pool), replace = TRUE)
# "replace = TRUE" is the only difference between bootstrap and permutations
g1.perm = pool[resample][1 : s.size.g1]
g2.perm = pool[resample][(s.size.g1+1) : length(pool)]
sampl.dist.b1[i] = mean (g1.perm) - mean (g2.perm)
}
p.boot1 <- (sum (abs (sampl.dist.b1) >= obs.diff.b1) + 1)/ (iterations+1)
Il valore P del bootstrap eseguito in questo modo è 0,005 . Anche se questo sembra ragionevole e quasi identico all'ANOVA parametrico e al test di permutazione, è appropriato giustificare H0 in questo bootstrap sulla base del fatto che abbiamo appena unito i campioni da cui abbiamo estratto campioni successivi?
Approccio diverso che ho trovato in diversi articoli scientifici. In particolare, ho visto che i ricercatori modificano i dati per soddisfare H0 prima del bootstrap. Cercando in giro, ho trovato post molto interessanti in CV dove @ jan.s ha spiegato risultati insoliti di bootstrap nella domanda post in cui l'obiettivo era quello di confrontare due mezzi. Tuttavia, in quel post non è spiegato come eseguire bootstrap quando i dati vengono modificati prima di bootstrap. L'approccio in cui i dati vengono modificati prima del bootstrap è simile al seguente:
- H0 afferma che i mezzi di due gruppi sono gli stessi
- H0 è vero se sottraggiamo singole osservazioni dalla media del campione aggregato
In questo caso, la modifica dei dati dovrebbe influenzare i mezzi dei gruppi, e quindi la loro differenza, ma non la variazione all'interno (e tra) dei gruppi.
- I dati modificati saranno la base per ulteriori bootstrap, con avvertenze che il campionamento viene effettuato all'interno di ciascun gruppo separatamente .
- La differenza tra la media bootstpped di g1 e g2 viene calcolata e confrontata con la differenza osservata (non modificata) tra i gruppi.
- La proporzione di valori uguali o più estremi di quella osservata divisa per il numero di iterazioni darà valore p.
Ecco il codice (Bootstrap2: ricampionamento all'interno dei gruppi dopo la modifica che H0 è VERO ):
s.size.g1 <- length (g1.lengths)
s.size.g2 <- length (g2.lengths)
pool <- lengths$lengths
obs.diff.b2 <- mean (g1.lengths) - mean (g2.lengths)
# make H0 to be true (no difference between means of two groups)
H0 <- pool - mean (pool)
# g1 from H0
g1.H0 <- H0[1:s.size.g1]
# g2 from H0
g2.H0 <- H0[(s.size.g1+1):length(pool)]
iterations <- 10000
sampl.dist.b2 <- NULL
set.seed (5)
for (i in 1 : iterations) {
# Sample with replacement in g1
g1.boot = sample (g1.H0, replace = T)
# Sample with replacement in g2
g2.boot = sample (g2.H0, replace = T)
# bootstrapped difference
sampl.dist.b2[i] <- mean (g1.boot) - mean (g2.boot)
}
p.boot2 <- (sum (abs (sampl.dist.b2) >= obs.diff.b2) + 1)/ (iterations+1)
Tale bootstrap eseguito darà un valore di p di 0,514 che è tremendamente diverso rispetto ai test precedenti. Credo che questo abbia a che fare con la spiegazione di @ jan.s , ma non riesco a capire dove sia la chiave ...
H0 <- pool - mean (pool)
. Deve essere sostituito con H0 <- c(g1.lengths - mean(g1.lengths), g2.lengths - mean(g2.lengths))
. Quindi otterrai un valore p di 0,0023. (Questa è la stessa cosa che Zenit ha spiegato nella sua risposta.) Questo è tutto ciò che c'è da fare, solo un semplice bug nel codice. CC a @MichaelChernick