Załóżmy, że mam dane z dwoma niezależnymi grupami:
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)
Oczywiste jest, że wielkość próby na grupę jest tendencyjna, gdy g1 ma 6 obserwacji, a g2 ma 22 . Tradycyjna ANOVA sugeruje, że grupy mają różne środki, gdy wartość krytyczna jest ustawiona na 0,05 (wartość p wynosi 0,0044 ).
summary (aov (lengths~group, data = lengths))
Biorąc pod uwagę, że moim celem jest porównanie średniej różnicy, takie niezrównoważone i małe próbki danych mogą dawać nieodpowiednie wyniki przy tradycyjnym podejściu. Dlatego chcę wykonać test permutacji i bootstrap.
BADANIE UPRAWNIENIA
Hipoteza zerowa (H0) stwierdza, że średnie grupy są takie same. To założenie w teście permutacji jest uzasadnione poprzez połączenie grup w jedną próbkę. Zapewnia to, że próbki dla dwóch grup zostały pobrane z identycznego rozkładu. Poprzez powtarzanie próbkowania (a ściślej - przetasowanie) z zebranych danych, obserwacje są ponownie przydzielane (tasowane) do próbek w nowy sposób i obliczana jest statystyka testu. Wykonanie tego n razy da rozkład próbkowania statystyk testowych przy założeniu, że H0 ma wartość PRAWDA. Na koniec, pod H0, wartość p jest prawdopodobieństwem, że statystyka testu jest równa lub przekracza wartość obserwowaną.
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)
Podana wartość p testu permutacji wynosi 0,0053 . OK, jeśli zrobiłem to poprawnie, permutacje i parametryczna ANOVA dają prawie identyczne wyniki.
BOOTSTRAP
Przede wszystkim mam świadomość, że bootstrap nie może pomóc, gdy próbki są zbyt małe. Ten post pokazał, że może być jeszcze gorzej i wprowadzać w błąd . Po drugie podkreślono, że test permutacji jest ogólnie lepszy niż bootstrap, gdy głównym celem jest testowanie hipotez. Niemniej jednak ten świetny post rozwiązuje ważne różnice między metodami intensywnie korzystającymi z komputera. Jednak tutaj chciałbym postawić (wierzę) inne pytanie.
Najpierw przedstawię najpopularniejsze podejście do ładowania początkowego (Bootstrap1: ponowne próbkowanie w próbce zbiorczej ):
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)
Wartość P wykonywanego w ten sposób ładowania początkowego wynosi 0,005 . Nawet jeśli brzmi to rozsądnie i prawie identycznie jak parametryczna ANOVA i test permutacji, czy właściwe jest uzasadnienie H0 w tym bootstrapie na podstawie tego, że właśnie zebraliśmy próbki, z których pobraliśmy kolejne próbki?
Inne podejście znalazłem w kilku artykułach naukowych. W szczególności widziałem, że badacze modyfikują dane w celu spełnienia H0 przed rozpoczęciem ładowania. Rozglądając się, znalazłem bardzo interesujący post w CV, w którym @ jan.s wyjaśnił niezwykłe wyniki bootstrap w pytaniu, w którym celem było porównanie dwóch średnich. Jednak w tym poście nie opisano, jak wykonać bootstrap, gdy dane są modyfikowane przed bootstrapem. Podejście, w którym dane są modyfikowane przed rozpoczęciem ładowania wygląda następująco:
- H0 stwierdza, że średnie dwóch grup są takie same
- H0 jest prawdą, jeśli odejmiemy indywidualne obserwacje od średniej próbki zbiorczej
W takim przypadku modyfikacja danych powinna wpływać na średnie grup, a zatem na ich różnicę, ale nie na zmienność w obrębie grup (i między nimi).
- Zmodyfikowane dane będą podstawą do dalszego ładowania, z zastrzeżeniami, że próbkowanie jest przeprowadzane w ramach każdej grupy osobno .
- Różnicę między wartością początkową g1 i g2 oblicza się i porównuje z zaobserwowaną (niemodyfikowaną) różnicą między grupami.
- Proporcja równych lub większej liczby wartości ekstremalnych niż obserwowana podzielona przez liczbę iteracji da wartość p.
Oto kod (Bootstrap2: ponowne próbkowanie w grupach po modyfikacji, że H0 ma wartość PRAWDA ):
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)
Tak wykonany bootstrap da wartość p 0,514, która jest ogromnie inna w porównaniu do poprzednich testów. Uważam, że ma to związek z wyjaśnieniem @ jan.s , ale nie mogę zrozumieć, gdzie jest klucz ...
H0 <- pool - mean (pool)
. Należy go zastąpić H0 <- c(g1.lengths - mean(g1.lengths), g2.lengths - mean(g2.lengths))
. Otrzymasz wartość p 0,0023. (To jest to samo, co Zenit wyjaśnił w swojej odpowiedzi.) To wszystko, tylko prosty błąd w kodzie. CC do @MichaelChernick