Bootstrapping hierarchischer / mehrstufiger Daten (Resampling-Cluster)

9

Ich erstelle ein Skript zum Erstellen von Bootstrap-Beispielen aus dem catsDataset (aus dem -MASS-Paket).

Nach dem Lehrbuch von Davidson und Hinkley [1] führte ich eine einfache lineare Regression durch und übernahm ein grundlegendes nichtparametrisches Verfahren für das Bootstrapping von iid-Beobachtungen, nämlich das Resampling von Paaren .

Das Originalmuster hat folgende Form:

Bwt   Hwt

2.0   7.0
2.1   7.2

...

1.9    6.8

Durch ein univariates lineares Modell wollen wir das Herdgewicht von Katzen durch ihr Gehirngewicht erklären.

Der Code lautet:

library(MASS)
library(boot)


##################
#   CATS MODEL   #
##################

cats.lm <- glm(Hwt ~ Bwt, data=cats)
cats.diag <- glm.diag.plots(cats.lm, ret=T)


#######################
#   CASE resampling   #
#######################

cats.fit <- function(data) coef(glm(data$Hwt ~ data$Bwt)) 
statistic.coef <- function(data, i) cats.fit(data[i,]) 

bootl <- boot(data=cats, statistic=statistic.coef, R=999)

Angenommen, es gibt jetzt eine Clustervariable cluster = 1, 2,..., 24(zum Beispiel gehört jede Katze zu einem bestimmten Wurf). Nehmen wir zur Vereinfachung an, dass die Daten ausgewogen sind: Wir haben 6 Beobachtungen für jeden Cluster. Daher besteht jeder der 24 Würfe aus 6 Katzen (dh n_cluster = 6und n = 144).

Es ist möglich, eine gefälschte clusterVariable zu erstellen durch:

q <- rep(1:24, times=6)
cluster <- sample(q)
c.data <- cbind(cats, cluster)

Ich habe zwei verwandte Fragen:

Wie simuliere ich Proben gemäß der (gruppierten) Datensatzstruktur? Das heißt, wie kann ein Resample auf Clusterebene durchgeführt werden? Ich möchte die Cluster mit Ersetzung abtasten und die Beobachtungen innerhalb jedes ausgewählten Clusters wie im Originaldatensatz festlegen (dh Stichproben mit Ersetzung der Cluster und ohne Ersetzung der Beobachtungen innerhalb jedes Clusters).

Dies ist die von Davidson vorgeschlagene Strategie (S. 100). Angenommen, wir ziehen B = 100Proben. Jeder von ihnen sollte aus 24 möglicherweise wiederkehrenden Clustern (z. B. cluster = 3, 3, 1, 4, 12, 11, 12, 5, 6, 8, 17, 19, 10, 9, 7, 7, 16, 18, 24, 23, 11, 15, 20, 1) bestehen, und jeder Cluster sollte die gleichen 6 Beobachtungen des ursprünglichen Datensatzes enthalten. Wie geht das R? (entweder mit oder ohne -boot-Paket.) Haben Sie alternative Vorschläge für das weitere Vorgehen?

Die zweite Frage betrifft das anfängliche Regressionsmodell. Angenommen, ich verwende ein Modell mit festen Effekten und Abschnitten auf Clusterebene. Ändert es das angewandte Resampling-Verfahren ?

[1] Davidson, AC, Hinkley, DV (1997). Bootstrap-Methoden und ihre Anwendungen . Cambridge University Press.

Stefano Lombardi
quelle

Antworten:

9

Das Resampling der gesamten Cluster ist in der Umfragestatistik bekannt, solange dort überhaupt Resampling-Methoden angewendet wurden (dh seit Mitte der 1960er Jahre). Daher handelt es sich um eine etablierte Methode. Siehe meine Sammlung von Links unter http://www.citeulike.org/user/ctacmo/tag/survey_resampling . Ob das bootgeht oder nicht, weiß ich nicht; Ich verwende das surveyPaket, wenn ich mit Umfrage-Bootstraps arbeiten muss, obwohl es beim letzten Überprüfen nicht alle Funktionen hatte, die ich benötigte (wie einige kleine Beispielkorrekturen, soweit ich mich erinnern kann).

Ich denke nicht, dass das Anwenden eines bestimmten Modells wie fester Effekte die Dinge stark verändert, aber IMO, der verbleibende Bootstrap macht viele starke Annahmen (die Residuen sind iid, das Modell ist korrekt spezifiziert). Jeder von ihnen ist leicht zu brechen, und die Clusterstruktur bricht sicherlich die iid-Annahme.

Es gibt einige ökonometrische Literatur zu Wild Cluster Bootstrap. Sie gaben vor, im luftleeren Raum gearbeitet zu haben, ohne all die fünfzig Jahre der Umfragestatistik zu diesem Thema, also bin ich mir nicht sicher, was ich davon halten soll.

StasK
quelle
Mein Hauptzweifel bei der Erzielung fester Effekte auf Clusterebene ist, dass es in einigen simulierten Beispielen vorkommen kann, dass wir einige der anfänglichen Cluster nicht ausgewählt haben, sodass die zugehörigen clusterspezifischen Abschnitte nicht identifiziert werden können. Wenn Sie sich den Code ansehen, den ich gepostet habe, sollte dies aus "mechanischer" Sicht kein Problem sein (bei jeder Iteration können wir ein anderes FE-Modell nur mit den Abschnitten der abgetasteten Cluster anpassen). Ich habe mich gefragt, ob es in all dem ein "statistisches" Problem gibt
Stefano Lombardi
3

Ich habe versucht, das Problem selbst zu lösen, und den folgenden Code erstellt.

Obwohl es funktioniert, könnte es wahrscheinlich in Bezug auf die Geschwindigkeit verbessert werden. Wenn möglich, hätte ich es auch vorgezogen, einen Weg für die Verwendung des -boot-Pakets zu finden, da es ermöglicht, automatisch eine Reihe von Bootstrap-Konfidenzintervallen durch boot.ci...

Der Einfachheit halber besteht der Ausgangsdatensatz aus 18 Katzen (die "Beobachtungen auf niedrigerer Ebene"), die in 6 Laboratorien (der Clustervariablen) verschachtelt sind. Der Datensatz ist ausgeglichen ( n_cluster = 3für jeden Cluster). Wir haben einen Regressor, der das xerklärt y.

Der gefälschte Datensatz und die Matrix, in der die Ergebnisse gespeichert werden, sind:

  # fake sample 
  dat <- expand.grid(cat=factor(1:3), lab=factor(1:6))
  dat <- cbind(dat, x=runif(18), y=runif(18, 2, 5))

  # empty matrix for storing coefficients estimates and standard errors of x
  B <- 50 # number of bootstrap samples
  b.sample <- matrix(nrow=B, ncol=3, dimnames=list(c(), c("sim", "b_x", "se_x")))
  b.sample[,1] <- rep(1:B)

Bei jeder der BIterationen werden in der folgenden Schleife 6 Cluster mit Ersatz abgetastet, die jeweils aus 3 Katzen bestehen, die ohne Ersatz entnommen wurden (dh die interne Zusammensetzung der Cluster bleibt unverändert). Die Schätzungen des Regressorkoeffizienten und seines Standardfehlers werden in der zuvor erstellten Matrix gespeichert:

  ####################################
  #   loop through "b.sample" rows   #
  ####################################

  for (i in seq(1:B)) {

  ###   sampling with replacement from the clustering variable   

    # sampling with replacement from "cluster" 
    cls <- sample(unique(dat$lab), replace=TRUE)
    cls.col <- data.frame(lab=cls)

    # reconstructing the overall simulated sample
    cls.resample <- merge(cls.col, dat, by="lab")


  ###   fitting linear model to simulated data    

    # model fit
    mod.fit <- function(data) glm(data$y ~ data$x)

    # estimated coefficients and standard errors
    b_x <- summary(mod.fit(data=cls.resample))$coefficients[2,1]
    	se_x <- summary(mod.fit(data=cls.resample))$coefficients[2,2]

    b.sample[i,2] <- b_x
    b.sample[i,3] <- se_x

  }

Hoffe das hilft, Lando

Stefano Lombardi
quelle
Die Verwendung einer for-Schleife muss durch using dominiert werden replicate. Als Bonus wird das b.sampleArray automatisch für Sie zurückgegeben. Bei all dem Zusammenführen hier ist es mit ziemlicher Sicherheit besser, wenn Sie verwenden data.tableund neu abtasten key. Ich kann eine Antwort beisteuern, wenn ich an einen Computer komme ... Frage: Warum verfolgen Sie die Standardfehler der Koeffizienten?
MichaelChirico
Danke @MichaelChirico, ich stimme zu. Wenn ich mich gut erinnere, habe ich Standardfehler gespeichert, um später Konfidenzintervalle zu zeichnen.
Stefano Lombardi
sollten Konfidenzintervalle nicht nur die Quantile der Verteilung der Bootstrap-Koeffizienten sein? dh für ein 95% -Konfidenzintervallquantile(b.sample[,2], c(.025, .975))
MichaelChirico
3

Hier ist eine viel einfachere (und zweifellos schnellere) Möglichkeit, das Bootstrapping mit data.table(auf @ lando.carlissians Daten) durchzuführen:

library(data.table)
setDT(dat, key = "lab")
b.sample <- 
  replicate(B, dat[.(sample(unique(lab), replace = T)),
                   glm(y ~ x)$coefficients])
MichaelChirico
quelle
2

Ich musste dies vor kurzem tun und verwendet dplyr. Die Lösung ist nicht so elegant wie bei data.table, aber:

library(dplyr)
replicate(B, {
  cluster_sample <- data.frame(cluster = sample(dat$cluster, replace = TRUE))
  dat_sample <- dat %>% inner_join(cluster_sample, by = 'cluster')
  coef(lm(y ~ x, data = dat_sample))
})

Das inner_joinwiederholt sich jede Zeile einen bestimmten Wert hat , xder clusterdurch die Anzahl der Zeiten , die xin erscheint cluster_sample.

dash2
quelle
0

Hallo, eine sehr einfache Lösung basierend auf Split und Lapply, kein spezielles Paket außer "Boot", Beispiel mit einer Schätzung des ICC basierend auf dem Nagakawa-Verfahren:

# FIRST FUNCTION : "parameter assesment"
nagakawa <- function(dataICC){
    #dataICC <- dbICC
    modele <- lmer(indicateur.L ~ 1 + (1|sujet.L) + (1|injection.L) + experience.L, data = dataICC)
    variance <- get_variance(modele)
    var.fixed <- variance$var.fixed
var.random <- variance$var.random
    var.sujet <- variance$var.intercept[1]
var.resid <- variance$var.residual
    icc.juge1 <- var.random / (var.random + var.fixed + var.resid)

    modele <- lmer(indicateur.L ~ 1 + (1 + injection.L|sujet.L) + experience.L, data = dataICC)
    variance <- VarCorr(modele)
    var.fixed <- get_variance_fixed(modele)
    var.random <- (attributes(variance$sujet.L)$stddev[1])^2 + (attributes(variance$sujet.L)$stddev[2])^2
    var.sujet <- (attributes(variance$sujet.L)$stddev[1])^2
    var.resid <- (attributes(variance)$sc)^2
icc.juge2 <- var.random / (var.random + var.fixed + var.resid)
return(c(as.numeric(icc.juge1),as.numeric(icc.juge2)))
  }
```
#SECOND FONCTION : bootstrap function, split on the hirarchical level as you want
```
  nagakawa.boot <- function(data,x){
list.ICC <- split(x = data, f = paste(data$juge.L,data$injection.L,sep = "_"))
    list.BOOT <- lapply(X = list.ICC, FUN = function(y){
      y[x,]
    })
    db.BOOT <- do.call(what = "rbind", args = list.BOOT)
    nagakawa(dataICC = db.BOOT)
  }

DRITTE: Bootstrap-Ausführung

ICC.BOOT <- boot(data = dbICC, statistic = nagakawa.boot, R = 1000)
Benjamin Granger
quelle