Gestion de l'autocorrélation élevée dans MCMC

10

Je construis un modèle bayésien hiérarchique assez complexe pour une méta-analyse utilisant R et JAGS. Pour simplifier un peu, les deux niveaux clés du modèle ont où est la ème observation de la (dans ce cas, les rendements des cultures GM vs non GM) dans l'étude , est l'effet pour l'étude , les s sont des effets pour diverses variables au niveau de l'étude (le statut de développement économique du pays où le étude a été réalisée, espèces cultivées, méthode d'étude, etc.) indexées par une famille de fonctions , et le

yjej=αj+ϵje
αj=hγh(j)+ϵj
yjejjejαjjγhϵs sont des termes d'erreur. Notez que les ne sont pas des coefficients sur des variables muettes. Au lieu de cela, il existe variables distinctes pour différentes valeurs au niveau de l'étude. Par exemple, il y a pour les pays en développement et pour les pays développés. γγγevelopjengγevelope

Je suis principalement intéressé par l'estimation des valeurs des . Cela signifie que supprimer des variables de niveau étude du modèle n'est pas une bonne option. γ

Il existe une forte corrélation entre plusieurs des variables au niveau de l'étude, et je pense que cela produit de grandes autocorrélations dans mes chaînes MCMC. Ce tracé de diagnostic illustre les trajectoires de la chaîne (à gauche) et l'autocorrélation qui en résulte (à droite):
autocorrélation élevée dans la sortie MCMC

À la suite de l'autocorrélation, j'obtiens des tailles d'échantillons efficaces de 60 à 120 à partir de 4 chaînes de 10 000 échantillons chacune.

J'ai deux questions, l'une clairement objective et l'autre plus subjective.

  1. Outre l'amincissement, l'ajout de chaînes et le fonctionnement de l'échantillonneur plus longtemps, quelles techniques puis-je utiliser pour gérer ce problème d'autocorrélation? Par «gérer», je veux dire «produire des estimations raisonnablement bonnes dans un délai raisonnable». En termes de puissance de calcul, j'exécute ces modèles sur un MacBook Pro.

  2. Quelle est la gravité de ce degré d'autocorrélation? Les discussions ici et sur le blog de John Kruschke suggèrent que, si nous exécutons le modèle assez longtemps, "l'autocorrélation grumeleuse a probablement toutes été moyennée" (Kruschke) et donc ce n'est pas vraiment un gros problème.

Voici le code JAGS pour le modèle qui a produit l'intrigue ci-dessus, juste au cas où quelqu'un serait suffisamment intéressé pour parcourir les détails:

model {
for (i in 1:n) {
    # Study finding = study effect + noise
    # tau = precision (1/variance)
    # nu = normality parameter (higher = more Gaussian)
    y[i] ~ dt(alpha[study[i]], tau[study[i]], nu)
}

nu <- nu_minus_one + 1
nu_minus_one ~ dexp(1/lambda)
lambda <- 30

# Hyperparameters above study effect
for (j in 1:n_study) {
    # Study effect = country-type effect + noise
    alpha_hat[j] <- gamma_countr[countr[j]] + 
                    gamma_studytype[studytype[j]] +
                    gamma_jour[jourtype[j]] +
                    gamma_industry[industrytype[j]]
    alpha[j] ~ dnorm(alpha_hat[j], tau_alpha)
    # Study-level variance
    tau[j] <- 1/sigmasq[j]
    sigmasq[j] ~ dunif(sigmasq_hat[j], sigmasq_hat[j] + pow(sigma_bound, 2))
    sigmasq_hat[j] <- eta_countr[countr[j]] + 
                        eta_studytype[studytype[j]] + 
                        eta_jour[jourtype[j]] +
                        eta_industry[industrytype[j]]
    sigma_hat[j] <- sqrt(sigmasq_hat[j])
}
tau_alpha <- 1/pow(sigma_alpha, 2)
sigma_alpha ~ dunif(0, sigma_alpha_bound)

# Priors for country-type effects
# Developing = 1, developed = 2
for (k in 1:2) {
    gamma_countr[k] ~ dnorm(gamma_prior_exp, tau_countr[k])
    tau_countr[k] <- 1/pow(sigma_countr[k], 2)
    sigma_countr[k] ~ dunif(0, gamma_sigma_bound)
    eta_countr[k] ~ dunif(0, eta_bound)
}

# Priors for study-type effects
# Farmer survey = 1, field trial = 2
for (k in 1:2) {
    gamma_studytype[k] ~ dnorm(gamma_prior_exp, tau_studytype[k])
    tau_studytype[k] <- 1/pow(sigma_studytype[k], 2)
    sigma_studytype[k] ~ dunif(0, gamma_sigma_bound)
    eta_studytype[k] ~ dunif(0, eta_bound)
}

# Priors for journal effects
# Note journal published = 1, journal published = 2
for (k in 1:2) {
    gamma_jour[k] ~ dnorm(gamma_prior_exp, tau_jourtype[k])
    tau_jourtype[k] <- 1/pow(sigma_jourtype[k], 2)
    sigma_jourtype[k] ~ dunif(0, gamma_sigma_bound)
    eta_jour[k] ~ dunif(0, eta_bound)
}

# Priors for industry funding effects
for (k in 1:2) {
    gamma_industry[k] ~ dnorm(gamma_prior_exp, tau_industrytype[k])
    tau_industrytype[k] <- 1/pow(sigma_industrytype[k], 2)
    sigma_industrytype[k] ~ dunif(0, gamma_sigma_bound)
    eta_industry[k] ~ dunif(0, eta_bound)
}
}
Dan Hicks
la source
1
Pour ce que ça vaut, des modèles multiniveaux complexes sont à peu près la raison pour laquelle Stan existe, pour exactement les raisons que vous identifiez.
Sycorax dit Réintégrer Monica
J'ai d'abord essayé de construire ça à Stan, il y a plusieurs mois. Les études impliquent un nombre différent de résultats, ce qui (au moins à l'époque; je n'ai pas vérifié si les choses ont changé) nécessitait d'ajouter une autre couche de complexité au code et signifiait que Stan ne pouvait pas tirer parti des calculs matriciels qui le rendent si rapide.
Dan Hicks
1
Je ne pensais pas tant à la vitesse qu'à l'efficacité avec laquelle HMC explore le postérieur. Ma compréhension est que parce que HMC peut couvrir beaucoup plus de terrain, chaque itération a une autocorrélation plus faible.
Sycorax dit Réintégrer Monica
Oh, oui, c'est un point intéressant. Je vais mettre cela sur ma liste de choses à essayer.
Dan Hicks

Réponses:

6

Suite à la suggestion de user777, il semble que la réponse à ma première question soit "utilisez Stan". Après avoir réécrit le modèle dans Stan, voici les trajectoires (4 chaînes x 5000 itérations après rodage):
entrez la description de l'image ici Et les tracés d'autocorrélation:
entrez la description de l'image ici

Bien mieux! Pour être complet, voici le code Stan:

data {                          // Data: Exogenously given information
// Data on totals
int n;                      // Number of distinct finding i
int n_study;                // Number of distinct studies j

// Finding-level data
vector[n] y;                // Endpoint for finding i
int study_n[n_study];       // # findings for study j

// Study-level data
int countr[n_study];        // Country type for study j
int studytype[n_study];     // Study type for study j
int jourtype[n_study];      // Was study j published in a journal?
int industrytype[n_study];  // Was study j funded by industry?

// Top-level constants set in R call
real sigma_alpha_bound;     // Upper bound for noise in alphas
real gamma_prior_exp;       // Prior expected value of gamma
real gamma_sigma_bound;     // Upper bound for noise in gammas
real eta_bound;             // Upper bound for etas
}

transformed data {
// Constants set here
int countr_levels;          // # levels for countr
int study_levels;           // # levels for studytype
int jour_levels;            // # levels for jourtype
int industry_levels;        // # levels for industrytype
countr_levels <- 2;
study_levels <- 2;
jour_levels <- 2;
industry_levels <- 2;
}

parameters {                    // Parameters:  Unobserved variables to be estimated
vector[n_study] alpha;      // Study-level mean
real<lower = 0, upper = sigma_alpha_bound> sigma_alpha;     // Noise in alphas

vector<lower = 0, upper = 100>[n_study] sigma;          // Study-level standard deviation

// Gammas:  contextual effects on study-level means
// Country-type effect and noise in its estimate
vector[countr_levels] gamma_countr;     
vector<lower = 0, upper = gamma_sigma_bound>[countr_levels] sigma_countr;
// Study-type effect and noise in its estimate
vector[study_levels] gamma_study;
vector<lower = 0, upper = gamma_sigma_bound>[study_levels] sigma_study;
vector[jour_levels] gamma_jour;
vector<lower = 0, upper = gamma_sigma_bound>[jour_levels] sigma_jour;
vector[industry_levels] gamma_industry;
vector<lower = 0, upper = gamma_sigma_bound>[industry_levels] sigma_industry;


// Etas:  contextual effects on study-level standard deviation
vector<lower = 0, upper = eta_bound>[countr_levels] eta_countr;
vector<lower = 0, upper = eta_bound>[study_levels] eta_study;
vector<lower = 0, upper = eta_bound>[jour_levels] eta_jour;
vector<lower = 0, upper = eta_bound>[industry_levels] eta_industry;
}

transformed parameters {
vector[n_study] alpha_hat;                  // Fitted alpha, based only on gammas
vector<lower = 0>[n_study] sigma_hat;       // Fitted sd, based only on sigmasq_hat

for (j in 1:n_study) {
    alpha_hat[j] <- gamma_countr[countr[j]] + gamma_study[studytype[j]] + 
                    gamma_jour[jourtype[j]] + gamma_industry[industrytype[j]];
    sigma_hat[j] <- sqrt(eta_countr[countr[j]]^2 + eta_study[studytype[j]]^2 +
                        eta_jour[jourtype[j]] + eta_industry[industrytype[j]]);
}
}

model {
// Technique for working w/ ragged data from Stan manual, page 135
int pos;
pos <- 1;
for (j in 1:n_study) {
    segment(y, pos, study_n[j]) ~ normal(alpha[j], sigma[j]);
    pos <- pos + study_n[j];
}

// Study-level mean = fitted alpha + Gaussian noise
alpha ~ normal(alpha_hat, sigma_alpha);

// Study-level variance = gamma distribution w/ mean sigma_hat
sigma ~ gamma(.1 * sigma_hat, .1);

// Priors for gammas
gamma_countr ~ normal(gamma_prior_exp, sigma_countr);
gamma_study ~ normal(gamma_prior_exp, sigma_study);
gamma_jour ~ normal(gamma_prior_exp, sigma_study);
gamma_industry ~ normal(gamma_prior_exp, sigma_study);
}
Dan Hicks
la source