Übung zur Poisson-Regression
Simulation und Analyse von Poisson-Daten
Das Ziel dieser Übung ist das Verstehen von Poisson-Daten und einer Poisson-Regression. Wir werden hier Daten gemäss einem als bekannt vorausgesetzten Modell (zweifaktorielles Design) simulierten und dann analysieren.
Zusätzlich üben wir den Umgang mit Interaktionseffekten. In einem zweifaktoriellen Design haben Faktoren \(A\) und \(B\) einen Interaktionseffekt, wenn die erwartete Veränderung in der Zielgrösse bei einer Veränderung der Stufe auf dem Faktor \(A\) von der Stufe des Faktors \(B\) abhängt, und umgekehrt. Wenn jede Veränderung der Stufe des Faktors \(A\) über alle Stufen vom Faktor \(B\) konstant ist, dann haben die beiden Faktoren keinen Interaktionseffekt, sie agieren dann \(additiv\) und das Modell hat nur Haupteffekte.
Simuliere mit untigem Code Poisson-Daten (\(n=500\)) aus dem folgendem Modell:
\[ \boxed{\log \mu_i=\beta_0+\beta_1 sex_i+\beta_2 age_i+\beta_3 (sex:age)_i+\log(time_i), \qquad Y_i\sim \mathcal{P}(\mu_i)} \]
mit den Indikator-Variablen \[ sex_{i}\begin{cases} 1 &\mbox{if }sex_{i}=m\\ 0 & \mbox{if } sex_{i}=w \end{cases}, \quad age_{i}\begin{cases} 1 &\mbox{if }age_{i}=old\\ 0 & \mbox{if } age_{i}=young \end{cases}, \quad sex:age_i\begin{cases} 1 &\mbox{if }sex_{i}=m,age_i=old\\ 0 & else \end{cases} \]
sex
: biologisches Geschlecht, kategorielle Eingangsgrösseage
: Altersgrupppe, kategorielle Eingangsgrössetime
: Zeitdauer der BeobachtungCount
: Anzahl EreignisseSimulation bedeutet, dass wir allen Parametern einen wahren Wert zuordnen. Sie müssen folgenden Code natürlich nicht selber schreiben können, es geht hier darum, zu verstehen, wie Daten gemäss einem Modell “entstehen”. Gleichzeitig können Sie das Verständnis von vielen Aspekten wiederholen, die wir in diesem Modul eingeführt haben (Parameter, lineare Prädiktor, Link-Funktion, Verteilung usw.)
Versuchen Sie also, die Schritte der Simulation nachzuvollziehen.
Speichern Sie die Funktion
mysim()
ab (sie ist dann im workspace unterFunctions
ersichtlich) und definieren Sie dann das data framed.sim
mitd.sim<-mysim()
(ohne Argument). Betrachten Sie die Struktur der Daten.
<-function(seed=123) {
mysimset.seed(seed) # for reproducibility
<-500 # Number of observations
n# Parameters
<- 1.2 # Intercept
beta0 <- 0.5 # main sex effect (m vs. w)
beta1 <- -0.3 # main age effect (old vs. young)
beta2 <- 0 # interaction effect
beta3 <-c(beta0,beta1,beta2,beta3)
beta# Simulate grouping variables
<- factor(sample(c("w", "m"), size=n,replace=TRUE),levels=c("w","m")) # First grouping variable
sex <- factor(sample(c("young", "old"), size=n,replace = TRUE),levels=c("young","old")) # Second grouping variable
age # Create the design matrix for modelling
<- ifelse(sex == "m", 1, 0) # Convert to numeric for modeling
G1_num <- ifelse(age == "old", 1, 0)
G2_num <- G1_num * G2_num
G1G2_num # Simulate Exposure times
<- runif(n, min = 0.5, max = 5) # Exposure times from 0.5 to 5
time # Compute the linear predictor
<- beta0 + beta1 * G1_num + beta2 * G2_num + beta3 * G1G2_num + log(time)
linear_predictor # Compute the expectation
<-exp(linear_predictor)
mu# Simulate Poisson response variable
<- rpois(n, lambda = mu)
count # Combine into a data frame
data.frame(count = count,sex = sex,age = age,time = time)
}
<-mysim()
d.simstr(d.sim)
## 'data.frame': 500 obs. of 4 variables:
## $ count: int 8 15 3 14 15 13 21 13 2 8 ...
## $ sex : Factor w/ 2 levels "w","m": 1 1 1 2 1 2 2 2 1 1 ...
## $ age : Factor w/ 2 levels "young","old": 2 2 2 2 1 1 1 1 2 1 ...
## $ time : num 1.73 3.17 1.22 4.34 4.31 ...
::headTail(d.sim,10,10)
psych## count sex age time
## 1 8 w old 1.73
## 2 15 w old 3.17
## 3 3 w old 1.22
## 4 14 m old 4.34
## 5 15 w young 4.31
## 6 13 m young 2.65
## 7 21 m young 3.98
## 8 13 m young 1.83
## 9 2 w old 0.8
## 10 8 w young 2.48
## ... ... <NA> <NA> ...
## 491 0 w young 0.56
## 492 0 m old 0.55
## 493 13 w young 4.98
## 494 16 m old 3.95
## 495 8 m young 1.92
## 496 19 m young 4.15
## 497 22 m old 4.96
## 498 6 w old 1.4
## 499 8 w old 3.41
## 500 4 w old 2.47
Deskriptive Statistik
- Beschreiben Sie die Variablen mit
summary()
- Betrachten Sie eine Kreuztabelle von
sex
undage
. (mittable()
). Sind die Daten balanciert, d.h. haben alle Zellen gleich viele Beobachtungen? - Berechne die durchschnittliche Anzahlen und Raten bezüglich
sex
,age
undsex:age
-Kombination. Für die Raten berechnen wir harmonische Mittel:
sum(d.sim$count)/sum(d.sim$time)
stattmean(d.sim$count/d.sim$time)
(für overall) undtapply(d.sim,list(d.sim$sex,d.sim$age),FUN=function(x){sum(x$count)/sum(x$time)})
statttapply(d.sim$count/d.sim$time,list(d.sim$sex,d.sim$age),mean)
(fürsex:age
-Kombination)
Wie gross ist die beobachtete Rate Ratio bezüglich
sex
(\(m/w\)), unabhängig vonage
(“marginal”)?Wie gross ist die beobachtete Rate Ratio bezüglich
sex
(\(m/w\)), in beiden Gruppen vonage
? (“conditional”). Ist die Rate Ratio klar verschieden in beidenage
-Gruppen?
- Beschreiben
summary()
summary(d.sim)
## count sex age time
## Min. : 0.00 w:261 young:245 Min. :0.5052
## 1st Qu.: 5.00 m:239 old :255 1st Qu.:1.5992
## Median : 9.00 Median :2.7398
## Mean :10.18 Mean :2.7225
## 3rd Qu.:14.00 3rd Qu.:3.8133
## Max. :38.00 Max. :4.9979
- Kreuztabelle
table(d.sim$sex,d.sim$age)
##
## young old
## w 123 138
## m 122 117
Die Daten sind nicht ganz balanciert.
- Anzahlen und Raten
- Anzahlen
mean(d.sim$count)
## [1] 10.18
tapply(d.sim$count,d.sim$sex,mean)
## w m
## 8.003831 12.556485
tapply(d.sim$count,d.sim$age,mean)
## young old
## 11.857143 8.568627
tapply(d.sim$count,list(d.sim$sex,d.sim$age),mean)
## young old
## w 9.260163 6.884058
## m 14.475410 10.555556
- Raten (Harmonic means!)
<-sum(d.sim$count)/sum(d.sim$time)
ratesOverall<-tapply(d.sim,list(d.sim$age),FUN=function(x){sum(x$count)/sum(x$time)})
ratesAge<-tapply(d.sim,list(d.sim$sex),FUN=function(x){sum(x$count)/sum(x$time)})
ratesSex<-tapply(d.sim,list(d.sim$sex,d.sim$age),FUN=function(x){sum(x$count)/sum(x$time)})
ratesSexAge
ratesOverall## [1] 3.739186
ratesAge## young old
## 4.363895 3.141312
ratesSex## w m
## 2.887931 4.704471
ratesSexAge## young old
## w 3.325283 2.494565
## m 5.464744 3.923857
- Beobachtete Rate Ratios
- marginal
2]/ratesSex[1]
ratesSex[## m
## 1.629011
- Rate Ratios bezüglich
sex
für beide Gruppen vonage
, bedingt
ratesSexAge## young old
## w 3.325283 2.494565
## m 5.464744 3.923857
apply(ratesSexAge,2, function(x)x[2]/x[1])
## young old
## 1.643392 1.572962
Die Rate Ratio bezüglich sex
scheint nur leicht vom level auf age
abzuhängen. Wir vermuten hier schon, dass es keinen Interaktionseffekt gibt.
Modelle
Passen Sie ein
glm
an mit Interaktionseffekt (mit NamenmPoisI
) (das heisst, mit Termensex+age+sex:age
oder kurzsex*age
) und mit dem Offset-Term. Passen Sie gleichzeitig auch ein Modell an ohne Interaktion (mit NamenmPoisM
) und ein Modell ohnesex
undage
(mit NamenmPois0
) (nur mit Intercept und Offset.)Fakultativ: Vergleichen Sie die geschätzten Koeffizienten von
mPoisI
mit den wahren Parametern (die wir natürlich nur hier kennen, weil wir simuliert haben). Sind unsere Schätzungen verzerrt? Dazu ziehen wir \(k=1000\) mal eine neue Stichprobe und passen das Modell an (mit untigem Code). Studieren Sie die Matrixbetasim
(Beschreiben Sie die vier Kolonnen). Verzerrt ist eine Schätzung, wenn sie im Schnitt nicht gleich dem wahren Wert ist.
<-1000
k<-matrix(NA,nrow=k,ncol=4) #Matrix zum Auffüllen
betasimfor (i in 1:k) {
<-glm(count~sex*age+offset(log(time)),family=poisson(link="log"), data=mysim(seed=i))$coef
betasim[i,]
}##
head(betasim)
## [,1] [,2] [,3] [,4]
## [1,] 1.189445 0.5506043 -0.3096503 -0.084067866
## [2,] 1.238503 0.4839592 -0.3221731 -0.045097397
## [3,] 1.242606 0.4548178 -0.3334876 0.003967023
## [4,] 1.207219 0.4919022 -0.3138161 0.070311851
## [5,] 1.140620 0.5888954 -0.1601007 -0.209345945
## [6,] 1.215929 0.4800045 -0.2435946 -0.006623491
Wenden Sie
drop1
an, um densex:age
Interaktionseffekt zu testen. Kann man ihn weglassen?Betrachten Sie das Modell ohne Interaktion (Haupteffektmodell). Berechnen Sie das Verhältnis der Residualdevianz zu den Residualfreiheitsgraden. Ist dieses klar grösser als 1? (was übergrosser Streuung entsprechen würde).
Berechnen Sie eine Punkt- und Intervallschätzung (im Haupteffektmodell) für den
sex
undage
-Effekt auf Rate Ratio-Skala.Wie gross ist die geschätzte relative Ratenreduktion von alt versus jung (im Haupteffektmodell)?
Um welchen Faktor ist die geschätzte Rate gemäss Modell bei
sex=w
grösser als beisex=m
(im Haupteffektmodell)?Wie gross ist die geschätzte Rate gemäss Modell für eine weiblich junge Person (im Haupteffektmodell)?
Die geschätzten Raten und log Raten gemäss Modell bekommen wir mit
emmeans(m.poisM,~age+sex,type="response",infer=TRUE,offset=0)
undemmeans(m.poisM,~age+sex,infer=TRUE,offset=0)
.- Machen Sie eine Graphik mit
emmeans::emmip()
zum Visualisieren der vom Modell vorhergesagten Raten für die viersex:age
Gruppen, einmal auf dem linearen Prädiktor und einmal bezüglich der Raten (type="response"
). - Setzen Sie immer
offset=0
(das entspricht ja einer Zeiteinheit), damit man Raten statt Anzahlen hat.
- Wir passen ein Poisson Modell an mit
glm()
mit den zwei Haupteffektesex
undage
und demsex:age
-Interaktionseffekt (sex*age
ist äquivalent mitsex+age+sex:age
). Gleichzeitig passen wir noch ein Modell an ohne Interaktionseffekt und ein Modell ohne Eingangsgrössen.
<-glm(count~sex*age+offset(log(time)),family=poisson(link="log"), data=d.sim)
m.poisI<-update(m.poisI,.~.-sex:age)
m.poisM<-update(m.poisI,.~.-sex*age)
m.pois0coef(m.poisI)
## (Intercept) sexm ageold sexm:ageold
## 1.20155480 0.49676249 -0.28744050 -0.04380172
coef(m.poisM)
## (Intercept) sexm ageold
## 1.2131174 0.4776709 -0.3130446
coef(m.pois0)
## (Intercept)
## 1.318868
summary(m.poisI)
##
## Call:
## glm(formula = count ~ sex * age + offset(log(time)), family = poisson(link = "log"),
## data = d.sim)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 1.20155 0.02963 40.551 < 2e-16 ***
## sexm 0.49676 0.03800 13.072 < 2e-16 ***
## ageold -0.28744 0.04394 -6.542 6.07e-11 ***
## sexm:ageold -0.04380 0.05750 -0.762 0.446
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for poisson family taken to be 1)
##
## Null deviance: 960.71 on 499 degrees of freedom
## Residual deviance: 537.70 on 496 degrees of freedom
## AIC: 2505.1
##
## Number of Fisher Scoring iterations: 4
- Fakultativ: Die Schätzungen sind hier unverzerrt (d.h. nicht systematisch verschieden von den wahren Werten), weil wir aus der Wahrheit simuliert haben. Zufallsstreuung bleibt natürlich immer.
- Kennwerte der Verteilung von \(k=1000\) simulierten \(\hat{\beta}_0\),\(\hat{\beta}_1\),\(\hat{\beta}_2\),\(\hat{\beta}_3\):
::describe(betasim)
psych## vars n mean sd median trimmed mad min max range skew kurtosis se
## X1 1 1000 1.2 0.03 1.2 1.2 0.03 1.11 1.28 0.17 -0.05 -0.12 0
## X2 2 1000 0.5 0.04 0.5 0.5 0.04 0.37 0.62 0.24 -0.05 0.18 0
## X3 3 1000 -0.3 0.05 -0.3 -0.3 0.05 -0.46 -0.13 0.33 0.02 0.14 0
## X4 4 1000 0.0 0.06 0.0 0.0 0.06 -0.21 0.18 0.39 -0.03 0.02 0
Die mean
sind praktisch identisch mit den wahren \(\beta\)’s. Die Schätzungen sind also unverzerrt. sd
sind die Standardfehler. Vergleiche mit den Standardfehlern unter Std.Error
.
- Das reduzierte Modell ohne Interaktionseffekt kann nicht verworfen werden:
drop1(m.poisI,test="Chisq")
## Single term deletions
##
## Model:
## count ~ sex * age + offset(log(time))
## Df Deviance AIC LRT Pr(>Chi)
## <none> 537.70 2505.1
## sex:age 1 538.28 2503.6 0.58022 0.4462
anova(m.poisM,m.poisI)# $äquivalent
## Analysis of Deviance Table
##
## Model 1: count ~ sex + age + offset(log(time))
## Model 2: count ~ sex * age + offset(log(time))
## Resid. Df Resid. Dev Df Deviance Pr(>Chi)
## 1 497 538.28
## 2 496 537.70 1 0.58022 0.4462
- Wir betrachten das Haupteffekt-Modell
summary(m.poisM)
##
## Call:
## glm(formula = count ~ sex + age + offset(log(time)), family = poisson(link = "log"),
## data = d.sim)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 1.21312 0.02530 47.95 <2e-16 ***
## sexm 0.47767 0.02851 16.75 <2e-16 ***
## ageold -0.31304 0.02833 -11.05 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for poisson family taken to be 1)
##
## Null deviance: 960.71 on 499 degrees of freedom
## Residual deviance: 538.28 on 497 degrees of freedom
## AIC: 2503.6
##
## Number of Fisher Scoring iterations: 4
- Übergrosse Streuung haben wir nicht, da das Verhältnis von Residualdevianz zu den Residualfreiheitsgraden nahe bei 1 ist.
deviance(m.poisM)/df.residual(m.poisM)
## [1] 1.08305
- Punkt und Intervallschätzung der Rate-Ratios für
sex
undage
- Punktschätzung und Likelihood Konfidenzintervalle mit
confint()
:
exp(m.poisM$coef)##Punktschätzung
## (Intercept) sexm ageold
## 3.3639552 1.6123148 0.7312173
exp(confint(m.poisM))##Intervallschätzung
## 2.5 % 97.5 %
## (Intercept) 3.2001898 3.5338550
## sexm 1.5248312 1.7051354
## ageold 0.6916662 0.7729176
- Alternative:
parameters()
mitexponentiate=TRUE
gibt ebenfalls Likelihood-CI’s für Rate Ratios.
\(RR<1\) entsprechen negativen Effekten auf log Skala, \(RR>1\) entsprechen positiven Effekten auf log Skala.
::parameters(m.poisM,exponentiate=TRUE)
parameters## Parameter | IRR | SE | 95% CI | z | p
## ----------------------------------------------------------
## (Intercept) | 3.36 | 0.09 | [3.20, 3.53] | 47.95 | < .001
## sex [m] | 1.61 | 0.05 | [1.52, 1.71] | 16.76 | < .001
## age [old] | 0.73 | 0.02 | [0.69, 0.77] | -11.05 | < .001
::parameters(m.poisM)
parameters## Parameter | Log-Mean | SE | 95% CI | z | p
## ----------------------------------------------------------------
## (Intercept) | 1.21 | 0.03 | [ 1.16, 1.26] | 47.95 | < .001
## sex [m] | 0.48 | 0.03 | [ 0.42, 0.53] | 16.76 | < .001
## age [old] | -0.31 | 0.03 | [-0.37, -0.26] | -11.05 | < .001
Die geschätzte Rate Ratio für
age
ist 0.7312173, also ist die geschätzte relative Ratenreduktion (alt zu jung) -0.2687827 oder -26.8782737 Prozent.Die geschätzte Rate Ratio für
sex=m
versussex=w
ist 1.6123148, also ist der Faktor, um den die Rate fürsex=w
grösser ist als fürsex=m
gleich \(\frac{1}{1.6123148}\)=0.6202263Die geschätzte Event-Rate für eine weibliche junge Person ist 3.3639552 Events pro Zeiteinheit.
Geschätzte Raten und log Raten gemäss Modell: Damit wir Raten statt log Raten haben, müssen wir
type="response"
setzen. Damit wir Raten statt Anzahlen haben, müssten wiroffset=0
setzen (was dann einer Zeiteinheit entspricht, da \(\log(1)=0\)).
library(emmeans)
emmeans(m.poisM,~age+sex,infer=TRUE,offset=0)
## age sex emmean SE df asymp.LCL asymp.UCL z.ratio p.value
## young w 1.21 0.0253 Inf 1.164 1.263 47.948 <.0001
## old w 0.90 0.0269 Inf 0.847 0.953 33.476 <.0001
## young m 1.69 0.0217 Inf 1.648 1.733 77.816 <.0001
## old m 1.38 0.0246 Inf 1.329 1.426 55.918 <.0001
##
## Results are given on the log (not the response) scale.
## Confidence level used: 0.95
emmeans(m.poisM,~age+sex,type="response",infer=TRUE,offset=0)
## age sex rate SE df asymp.LCL asymp.UCL null z.ratio p.value
## young w 3.36 0.0851 Inf 3.20 3.53 1 47.948 <.0001
## old w 2.46 0.0661 Inf 2.33 2.59 1 33.476 <.0001
## young m 5.42 0.1178 Inf 5.20 5.66 1 77.816 <.0001
## old m 3.97 0.0977 Inf 3.78 4.16 1 55.918 <.0001
##
## Confidence level used: 0.95
## Intervals are back-transformed from the log scale
## Tests are performed on the log scale
Diese Grössen reproduzieren wir auch “von Hand” aus den geschätzten Parametern mit:
3.36 #young woman, oder: exp(1.21)
## [1] 3.36
3.36*0.73 #old woman, oder: exp(1.21-0.31)=exp(1.21)exp(-0.31)
## [1] 2.4528
3.36*1.61 #young man, oder: exp(1.21+0.48)=exp(1.21)exp(0.48)
## [1] 5.4096
3.36*0.73*1.61 #old man, oder: exp(1.21+0.48-0.31)=exp(1.21)exp(0.48)exp(-0.31)
## [1] 3.949008
Mit emmeans::emmip()
können wir Vorhersagen gemäss Modell plotten, auf dem linearen Prädiktor und auf “Response” (Rate).
emmip(m.poisM,age~sex,infer=TRUE,offset=0) # log Rates
emmip(m.poisM,age~sex,infer=TRUE,type="response",offset=0) # Rates