Bayes'sches Äquivalent von zwei Stichproben t-Test?

39

Ich bin nicht auf der Suche nach einer Plug-and-Play-Methode wie BEST in R, sondern nach einer mathematischen Erklärung einiger Bayes'scher Methoden, mit denen ich die Differenz zwischen dem Mittelwert zweier Stichproben testen kann.

John
quelle
15
Das Original-BEST-Papier könnte das sein, wonach Sie suchen: indiana.edu/~kruschke/BEST/BEST.pdf
Cam.Davidson.Pilon
4
Sprechen wir, um ganz klar zu sein, von einem Test mit zwei Stichproben, der einem frequentistischen Test der mittleren Unterschiede in zwei Gruppen, wie dem T-Test, entspricht? Oder interessieren Sie sich für Tests der starken Nullhypothese für Verteilungsunterschiede wie den Kolmogorov-Smirnoff-Test?
AdamO

Antworten:

46

Dies ist eine gute Frage, die sehr oft auftaucht: Link 1 , Link 2 . Die Veröffentlichung Bayesian Estimation Superseeds the T-Test , auf die Cam.Davidson.Pilon hingewiesen hat, ist eine hervorragende Ressource zu diesem Thema. Es ist auch sehr neu, veröffentlicht im Jahr 2012, was meiner Meinung nach teilweise auf das aktuelle Interesse an der Region zurückzuführen ist.

Ich werde versuchen, eine mathematische Erklärung einer Bayes'schen Alternative zum Zwei-Stichproben-T-Test zusammenzufassen. Diese Zusammenfassung ähnelt der BEST-Veröffentlichung, in der der Unterschied in zwei Stichproben durch Vergleich der Unterschiede in der hinteren Verteilung bewertet wird (siehe unten in R).

set.seed(7)

#create samples
sample.1 <- rnorm(8, 100, 3)
sample.2 <- rnorm(10, 103, 7)

#we need a pooled data set for estimating parameters in the prior.
pooled <- c(sample.1, sample.2)
par(mfrow=c(1, 2))

hist(sample.1)
hist(sample.2)

Bildbeschreibung hier eingeben

Um die Stichprobenmittel zu vergleichen, müssen wir schätzen, was sie sind. Die Bayes'sche Methode verwendet dazu den Bayes'schen Satz: P (A | B) = P (B | A) * P (A) / P (B) (die Syntax von P (A | B) wird als die Wahrscheinlichkeit von gelesen A gegeben B)

P(mean.1|sample.1) P(sample.1|mean.1)P(mean.1)P(sample.1|mean.1)P(mean.1)

Lassen Sie es uns in Code setzen. Code macht alles besser.

likelihood <- function(parameters){
  mu1=parameters[1]; sig1=parameters[2]; mu2=parameters[3]; sig2=parameters[4]
  prod(dnorm(sample.1, mu1, sig1)) * prod(dnorm(sample.2, mu2, sig2))
}

prior <- function(parameters){
  mu1=parameters[1]; sig1=parameters[2]; mu2=parameters[3]; sig2=parameters[4]
  dnorm(mu1, mean(pooled), 1000*sd(pooled)) * dnorm(mu2, mean(pooled), 1000*sd(pooled)) * dexp(sig1, rate=0.1) * dexp(sig2, 0.1)
}

Ich habe im Vorfeld einige Annahmen getroffen, die gerechtfertigt sein müssen. Um die Prioren davon abzuhalten, den geschätzten Mittelwert zu beeinträchtigen, wollte ich sie über plausible Werte hinweg breit und einheitlich machen, damit die Daten die Merkmale des Posterioren hervorbringen. Ich verwendete die empfohlene Einstellung von BEST und verteilte die mus normalerweise mit mean = mean (gepoolt) und einer breiten Standardabweichung = 1000 * sd (gepoolt). Die Standardabweichungen habe ich auf eine breite Exponentialverteilung gesetzt, weil ich eine breite unbegrenzte Verteilung wollte.

Jetzt können wir den posterior machen

posterior <- function(parameters) {likelihood(parameters) * prior(parameters)}

Wir werden die posteriore Verteilung unter Verwendung einer Markovkette Monte Carlo (MCMC) mit Metropolis Hastings-Modifikation untersuchen. Mit Code ist es am einfachsten zu verstehen.

#starting values
mu1 = 100; sig1 = 10; mu2 = 100; sig2 = 10
parameters <- c(mu1, sig1, mu2, sig2)

#this is the MCMC /w Metropolis method
n.iter <- 10000
results <- matrix(0, nrow=n.iter, ncol=4)
results[1, ] <- parameters
for (iteration in 2:n.iter){
  candidate <- parameters + rnorm(4, sd=0.5)
  ratio <- posterior(candidate)/posterior(parameters)
  if (runif(1) < ratio) parameters <- candidate #Metropolis modification
  results[iteration, ] <- parameters
}

Die Ergebnismatrix ist eine Liste von Stichproben aus der posterioren Verteilung für jeden Parameter, anhand derer wir unsere ursprüngliche Frage beantworten können: Unterscheidet sich Stichprobe 1 von Stichprobe 2? Um jedoch zunächst die Auswirkungen der Startwerte zu vermeiden, werden die ersten 500 Werte der Kette "eingebrannt".

#burn-in
results <- results[500:n.iter,]

Unterscheidet sich sample.1 von sample.2?

mu1 <- results[,1]
mu2 <- results[,3]

hist(mu1 - mu2)

Bildbeschreibung hier eingeben

mean(mu1 - mu2 < 0)
[1] 0.9953689

Aus dieser Analyse würde ich den Schluss ziehen, dass die Wahrscheinlichkeit, dass der Mittelwert für Probe 1 unter dem Mittelwert für Probe 2 liegt, bei 99,5% liegt.

Ein Vorteil des Bayes'schen Ansatzes ist, wie in der BEST-Veröffentlichung hervorgehoben, dass er starke Theorien aufstellen kann. ZB wie groß ist die Wahrscheinlichkeit, dass sample.2 5 Einheiten größer als sample.1 ist?

mean(mu2 - mu1 > 5)
[1] 0.9321124

Wir kommen zu dem Schluss, dass die Wahrscheinlichkeit, dass der Mittelwert von Stichprobe 2 um 5 Einheiten höher ist als der von Stichprobe 1, bei 93% liegt. Ein aufmerksamer Leser würde dies interessant finden, da wir wissen, dass die wahren Populationen Mittelwerte von 100 bzw. 103 haben. Dies ist höchstwahrscheinlich auf die geringe Stichprobengröße und die Auswahl einer Normalverteilung für die Wahrscheinlichkeit zurückzuführen.

Ich werde diese Antwort mit einer Warnung abschließen: Dieser Code dient zu Unterrichtszwecken. Verwenden Sie für eine echte Analyse RJAGS und passen Sie je nach Stichprobengröße eine t-Verteilung für die Wahrscheinlichkeit an. Bei Interesse schicke ich einen T-Test mit RJAGS.

EDIT: Wie hier angefordert handelt es sich um ein JAGS-Modell.

model.str <- 'model {
    for (i in 1:Ntotal) {
        y[i] ~ dt(mu[x[i]], tau[x[i]], nu)
    }
    for (j in 1:2) {
        mu[j] ~ dnorm(mu_pooled, tau_pooled)
        tau[j] <- 1 / pow(sigma[j], 2)
        sigma[j] ~ dunif(sigma_low, sigma_high)
    }
    nu <- nu_minus_one + 1
    nu_minus_one ~ dexp(1 / 29)
}'

# Indicator variable
x <- c(rep(1, length(sample.1)), rep(2, length(sample.2)))

cpd.model <- jags.model(textConnection(model.str),
                        data=list(y=pooled,
                                  x=x,
                                  mu_pooled=mean(pooled),
                                  tau_pooled=1/(1000 * sd(pooled))^2,
                                  sigma_low=sd(pooled) / 1000,
                                  sigma_high=sd(pooled) * 1000,
                                  Ntotal=length(pooled)))
update(cpd.model, 1000)
chain <- coda.samples(model = cpd.model, n.iter = 100000,
                      variable.names = c('mu', 'sigma'))
rchain <- as.matrix(chain)
hist(rchain[, 'mu[1]'] - rchain[, 'mu[2]'])
mean(rchain[, 'mu[1]'] - rchain[, 'mu[2]'] < 0)
mean(rchain[, 'mu[2]'] - rchain[, 'mu[1]'] > 5)
user1068430
quelle
Ich frage mich nur, ob es eine vernünftige Lösung gibt, den Bayes-Zwei-Stichproben-Vergleich mit dieser Art von Datensätzen zu verwenden. stackoverflow.com/q/57503523/7288088
Anheizen
7

Die ausgezeichnete Antwort von user1068430 in Python implementiert

import numpy as np
from pylab import plt

def dnorm(x, mu, sig):
    return 1/(sig * np.sqrt(2 * np.pi)) * np.exp(-(x - mu)**2 / (2 * sig**2))

def dexp(x, l):
    return l * np.exp(- l*x)

def like(parameters):
    [mu1, sig1, mu2, sig2] = parameters
    return dnorm(sample1, mu1, sig1).prod()*dnorm(sample2, mu2, sig2).prod()

def prior(parameters):
    [mu1, sig1, mu2, sig2] = parameters
    return dnorm(mu1, pooled.mean(), 1000*pooled.std()) * dnorm(mu2, pooled.mean(), 1000*pooled.std()) * dexp(sig1, 0.1) * dexp(sig2, 0.1)

def posterior(parameters):
    [mu1, sig1, mu2, sig2] = parameters
    return like([mu1, sig1, mu2, sig2])*prior([mu1, sig1, mu2, sig2])


#create samples
sample1 = np.random.normal(100, 3, 8)
sample2 = np.random.normal(100, 7, 10)

pooled= np.append(sample1, sample2)

plt.figure(0)
plt.hist(sample1)
plt.hold(True)
plt.hist(sample2)
plt.show(block=False)

mu1 = 100 
sig1 = 10
mu2 = 100
sig2 = 10
parameters = np.array([mu1, sig1, mu2, sig2])

niter = 10000

results = np.zeros([niter, 4])
results[1,:] = parameters

for iteration in np.arange(2,niter):
    candidate = parameters + np.random.normal(0,0.5,4)
    ratio = posterior(candidate)/posterior(parameters)
    if np.random.uniform() < ratio:
        parameters = candidate
    results[iteration,:] = parameters

#burn-in
results = results[499:niter-1,:]

mu1 = results[:,1]
mu2 = results[:,3]

d = (mu1 - mu2)
p_value = np.mean(d > 0)

plt.figure(1)
plt.hist(d,normed = 1)
plt.show()
Francisco Grings
quelle
6

Mit einer Bayes'schen Analyse haben Sie mehr Dinge zu spezifizieren (das ist eigentlich eine gute Sache, da es viel mehr Flexibilität und Fähigkeit gibt, das zu modellieren, was Sie für die Wahrheit halten). Nehmen Sie Normalen für die Wahrscheinlichkeiten an? Werden die beiden Gruppen die gleiche Varianz haben?

Ein einfacher Ansatz besteht darin, die 2 Mittelwerte (und 1 oder 2 Varianzen / Dispersionen) zu modellieren und anschließend die Differenz der 2 Mittelwerte und / oder das glaubwürdige Intervall auf die Differenz der 2 Mittelwerte zu untersuchen.

Greg Snow
quelle
Könnten Sie diesbezüglich nähere Angaben machen? Ich bin mir nicht sicher, wie man Model 2 meint und wie man sich Posteriors ansieht.
John
4

Eine mathematische Erklärung einiger Bayes'scher Methoden, mit denen ich die Differenz zwischen dem Mittelwert zweier Stichproben testen kann.

Es gibt verschiedene Ansätze, dies zu "testen". Ich werde ein paar erwähnen:

  • Wenn Sie eine explizite Entscheidung wünschen, können Sie sich die Entscheidungstheorie ansehen.

  • Eine ziemlich einfache Sache, die manchmal gemacht wird, ist, ein Intervall für den Unterschied in den Mitteln zu finden und zu überlegen, ob es 0 enthält oder nicht. Dazu müsste mit einem Modell für die Beobachtungen, Prioritäten bei den Parametern und der Berechnung der posterioren Verteilung der Mittelwertdifferenz, die von den Daten abhängig ist, begonnen werden.

    Sie müssen angeben, um welches Modell es sich handelt (z. B. normale, konstante Varianz), und dann (mindestens) einige Prioritäten für die Differenz der Mittelwerte und eine Prioritätsstufe für die Varianz. Möglicherweise haben Sie Prioritäten für die Parameter dieser Prioritäten. Oder Sie nehmen keine konstante Varianz an. Oder Sie nehmen etwas anderes als Normalität an.

Glen_b
quelle