#Zeugs, das wir irgendwie benötigen
library(tidyverse)
library(ggplot2)
N <- 1e4 # festlegen, wie oft (später) zufällig "Proben" entnommen werden, eine
# 1 mit 4 Nullen: 10.000
a
starren
die Überquerungszeiten verändert: b
Wir stellen ein (vereinfachtes) Modell der Wirklichkeit auf.
Vorannahme: Die zeit
die Menschen benötigen um eine Ampel zu überqueren unterliegt einer Normalverteilung.
zeit ~ dnorm(mu, sigma)
Eine Normalverteilung wird durch zwei Werte beschrieben, den Mittelwert mu
und die Standardabweichung sigma
.
Da wir nicht sonderlich daran interessiert sind, wie viel Zeit Menschen zur Überquerung von Ampeln benötigen müssen wir noch unseren Prädiktor das Starren hinzufügen: mu
sollte (laut Hypothese) unterschiedlich sein, je nach dem, ob jemand angestarrt wird, oder nicht.
Wir gehen von einem linearen Einfluss des Starrens auf mu
aus.
Wir nehmen an, dass mu
sich aus der durchschnittlichen Zeit zur Überquerung (der Straße) und einem Effekt des Starrens ergibt.
a
Auch hier gehen wir davon aus, dass die Werte einer Normalverteilung entspringen: a ~ dnorm(m, sd)
Frage 1: Wie kommen wir an eine gute Schätzung von m
?
b*x
Zu a
müssen wir also noch den Effekt des Starrens addieren, und zwar die Veränderung der Zeit durch das Starren: b * x
x
x
ist von uns als eine dichotome Variable definiert: 1 = angestarrt werden und 0 = nicht angestarrt werden
b
Grundsätzlich gehen wir auch hier davon aus, dass die Veränderung durch das Starren (“der Effekt”) aus einer Normalverteilung kommt. Dadurch, dass wir aber ausschließlich positiven Einfluss auf die Verkürzung erwarten2 definieren wir b
als log-normalverteilt (d.h., der Logarithmus von b
ist normalverteilt): b ~ dlnorm(mean, sd)
.
mu
ergibt sich nun also aus einem lineare Model mit dem wir innerhalb unseres Modells berechnen können, wie viel weniger Zeit Menschen benötigen, die angestarrt werden: mu = a + b * x
Jetzt können wir in das Model möglichst realistische Zahlen einsetzen. Beispielsweise, dass Menschen zur Überquerung der Straße im Schnitt 12 Sekunden (mit einer SD von .4 Sekunden) benötigen.
zeit ~ dnorm(mu, sigma)
mu <- a + b * x
a ~ dnorm( 12 , .4 )
b ~ dlnorm( 0 , .02 )
sigma ~ dunif( 0 , 2 ) # Stanardabweichung
effect_size <- -1 # 1 Sekunde weniger Zeit
Bisher zeigt der Term b * x
nur die Veränderung von einer Einheit an. Wie groß diese ist, müssen wir uns überlegen, um darauf basierend die nötige Stichprobengröße zu bestimmen, s.u..
Um den Effekt in Sekunden zu berechnen, muss x
mit dem erwarteten Effekt multipliziert werden: Bei einem erwarteten Effekt von 5 Sekunden: b * x * 5
Wenn unser Modell perfekt die Welt beschreibt, müssen nur noch die wahren Parameter dem Model hinzugefügt werden, und wir bräuchten keine Versuchsperson mehr erheben.
Beides kennen wir nicht, aber wir können unser Model so optimieren, dass die synthetischen Daten die es produziert, möglichst ähnlich den empirisch Daten sind. Dazu vergleichen wir, unsere Parameter mit erwartbaren Werten. Los geht’s!
a
# mittlere Überquerungsgeschwindigkeit ist 'mean' und variiert um 'sd'
sample_a <- rnorm( N , mean=12 , sd=.4 )
ggplot() +
aes(x=sample_a) +
stat_density(
adjust = .5,
fill = random_color(),
alpha = .5) +
geom_vline(xintercept = mean(sample_a), color = random_color()) +
theme_minimal()
Frage 3: Sind die Werte für a
plausibel, und was bedeutet die Linie?
b
# mittlerer Effekt 'meanlog', variiert um 'sd_log'
sample_b <- rlnorm( n=N , meanlog=0 , sdlog=.02 )
ggplot() +
stat_density(
aes(x=sample_b),
adjust = .5,
fill = random_color(),
alpha = .5) +
geom_vline(xintercept = mean(sample_b), color = random_color())+
theme_minimal()
Frage 4: Sind die Werte für b
plausibel?
mu
# Unabhängige Variable
# x = starren beschleunigt in Sekunden
x_0 = 0 # kein starren: kein Effekt
x_1 = 1 # starren: eine Einheit schneller, als sonst
# x_bar = mean(c(x_0, x_1))
# x_bar
mu_1 <- sample_a + sample_b * (x_1 * effect_size) # den Effekt in Sekunden umrechnen
mu_0 <- sample_a + sample_b * (x_0 * effect_size)
avg_mu_sim <- tibble(sample_a, sample_b, mu_1, mu_0)
ggplot(data=avg_mu_sim) +
stat_density(aes(x=mu_0), fill = random_color(), alpha = .5) +
geom_vline(xintercept = mean(mu_0), color = random_color()) +
stat_density(aes(x=mu_1), fill = random_color(), alpha = .5) +
geom_vline(xintercept = mean(mu_1), color = random_color())+
theme_minimal()
sigma
# wird erst später benötigt
sample_sigma <- runif( n=N , min=0 , max=2) # wird erst später relevant
ggplot() +
stat_density(
aes(x=sample_sigma),
adjust = .5,
fill = random_color(),
alpha = .5) +
geom_vline(xintercept = mean(sample_sigma), color = random_color())+
theme_minimal()
folgt
Um die Stichprobengröße zu bestimmen haben wir jetzt alles, was wir benötigen.
Nun können wir uns Daten beliebig oft simulieren und statistisch auswerten. Da wir die Wahrheit über unser Model kennen (H1 ist wahr) wissen wir, dass jeder nicht signifikante Test ein Fehler 2. Art ist.
Zuerst legen wir ein paar Parameter für die Simulation fest.
Die Antwort zu diesen Fragen hängt von 4 Faktoren ab und kann in jede Richtung gelöst werden:
Hier, in der Simulation, lösen wir zum Fehler 2. Art hin auf. Das heißt, dass wir festlegen, wie viele Versuchspersonen wir erheben, welche Wahrscheinlichkeit wir für den Fehler 1. Art akzeptieren und wie groß der Effekt ist, den wir erwarten. Das Ergebnis der Simulation ist die Wahrscheinlichkeit für einen Fehler 2. Art, gegeben den 3 Faktoren.
Wenn uns das Ergebnis nicht gefällt, müssen wir unsere Voraussetzungen überprüfen.
# Anzahl der Simulationen
nsims <- 10000 # hat nur was mit der anzunehmenden Genauigkeit der Power zutun
# 1. Stichprobengröße
nsubjects <- 40
# 2. Signifikanzniveau
type_I_error <- .01 # alpha
# 4. Effektgröße
effect_size <- effect_size # oben schon festgelegt
nsims
: Für ein Experiment liegt diese quasi bei 1.
Durch die Simulation können wir nun rumprobieren und entscheiden, was das für unsere Stichprobengröße bedeutet.
# Ein paar Dinge, die wir später benötigen
df_sim_data <- tibble() # Einen Datensatz für alle simulierten Daten
p_values <- tibble() # Einen Datensatz für alle p-Werte
starring <- c(x_0, x_1) # Eine Manipulation, s.o.
for (sim in 1:nsims){
time_crossing <-
sapply(
starring ,
function(stare)
rnorm(
# Wie viele Versuchspersonen sollen gezogen werden?
n = nsubjects/2,
# Das lineare Model (s.o.), welches die Zeit abhängig vom Starren vorhersagt
mean = sample_a + sample_b * stare * effect_size ,
# Die Varianz, wie unterschiedlich lange Versuchspersonen brauchen
sd = sample_sigma ) )
sim_data <-
tibble(
sim_n = sim,
no_stare=time_crossing[,1],
stare=time_crossing[,2])
# t-test rechnen
sim_ttest <-
t.test(
sim_data$stare,
sim_data$no_stare,
conf.level = 1 - type_I_error, # zu 1 - Fehlerrate wird H_1 korrekt angenommen
var.equal = TRUE, # per Definition (s.o.)
paired = FALSE) # keine Messwiederholung)
# # oder als lineares model
# sim_data_lm <- gather(
# sim_data, key = "stare", value = "crossing_time", stare:no_stare)
#
# sim_lm <-
# summary(
# lm(crossing_time ~ 1 + stare, data = sim_data_lm))
# p-werte sammeln
sim_p_value <-
tibble(
sim_n =sim,
# p_value = sim_lm$coefficients["starestare", "Pr(>|t|)"],
p_value = sim_ttest$p.value, # nur den p-Wert behalten
t_value = sim_ttest$statistic,
critical_t_value = qt(1-type_I_error/2, sim_ttest$parameter))
df_sim_data <- rbind(df_sim_data, sim_data)
p_values <- rbind(p_values, sim_p_value)
}
In dem Model legen wir einen Unterschied zwischen angestarrt und nicht angestarrt auf -1 Sekunden fest, H1 ist in unserem Model wahr.
p_values$below_alpha <- ifelse(p_values$p_value <= type_I_error, 1, 0)
type_II_error <- sum(p_values$below_alpha)/nrow(p_values)
Für unsere Studie, für eine Effektstärke von -1 Sekunden, bei n = 40 Versuchspersonen und einem Signifikanzniveau von 1% erreichen wir eine Power von 43.93%.
Die Wahrscheinlichkeit einen Fehler 2. Art zu begehen, bei einem nicht-signifikanten Ergebnis, liegt mit den oben festgelegt Werten bei 56.07%!
ggplot(data = p_values, aes(x = p_value)) +
stat_density(
adjust = .5,
fill = random_color(),
alpha = .5) + # anderes alpha!
geom_vline(
xintercept = type_I_error,
color = random_color())+
theme_minimal()
Frage 5: Was bedeutet das, und ist das akzeptabel?
# # 1000 simulierte Studien
# df_sim_data <-
# df_sim_data %>%
# group_by(sim_n) %>%
# summarise(
# mean_stare = mean(stare),
# # sd_stare = sd(stare),
# mean_no_stare = mean(no_stare),
# # sd_no_stare = sd(no_stare),
# effect_size = mean_stare - mean_no_stare) %>%
# cbind(p_values)
#
# DT::datatable(df_sim_data)
Inspiriert von McElreath, R. (2018). Statistical rethinking: A Bayesian course with examples in R and Stan. Chapman and Hall/CRC, Kapitel 3 [url].
inkl. Standardabweichung, Voraussetzung um Normalverteilungen zu nutzen (siehe unten)↩
Achtung: Das ist natürlich abhängig davon, wie wir den Effekt x
definieren! Siehe Frage 2. Hier gehen wir davon aus, dass jemand weniger Zeit benötigt. Der Term b * x
sollte entsprechend negativ werden, wenn er zu a
hinzuaddiert wird wenn gestarrt wird und keinen Einfluss auf a
haben, wenn nicht gestarrt wird. Das erreichen wir durch die Kodierung 1:0
.↩