Jacob Liljehult
Klinisk sygeplejespecialist
cand.scient.san, Ph.d.
Neurologisk afdeling
Nordsjællands Hospital
Som eksempel bruges data for dødsfald under indlæggelsen mellem patienter indlagt med henholdsvis ishæmisk stroke og intracerebral blødning
strokedata <- read.csv("https://jacobliljehult.github.io/research/strokedata.csv",
sep=",", header = TRUE)
with(strokedata, table(diagdict, inhospdead))
inhospdead | ||
---|---|---|
diagdict | Alive | Dead |
ICH | 88 | 22 |
IS | 883 | 38 |
Chi2-test laves med funktionen chisq.test( table( x, y ))
. Kategoriske data vil oftest være kodes som factors,
men det er ikke nødvendigt for at lave testen.
Testen kan enten laves med marginale data eller med summerede data fra et datasæt:
table1 <- matrix( c(88,22,883,38),
nrow = 2, byrow = T)
chisq.test(table1)
Pearson's Chi-squared test with Yates' continuity correction
data: table1
X-squared = 42.327, df = 1, p-value = 7.722e-11
chisq.test( with(strokedata, table(diagdict, inhospdead)) )
Pearson's Chi-squared test with Yates' continuity correction
data: chisq.test( with(strokedata, table(diagdict, inhospdead)) )
X-squared = 42.327, df = 1, p-value = 7.722e-11
Chi2-testet har en modelantagelse om at alle celler i tabellen har en forventet værdi på mindst fem. Denne antagelse kan testes således:
chisq.test(chisq.test( with(strokedata, table(diagdict, inhospdead)) ))$expected
inhospdead | ||
---|---|---|
diagdict | Alive | Dead |
ICH | 103.5984 | 6.401552 |
IS | 867.4016 | 53.598448 |
Med samme data kan vi lave en Fisher exact test, som ikke kræver samme antagelse angående forventede værdier:
table2 <- matrix(c(88,22,883,38),
nrow = 2, byrow = T)
fisher.test(table2)
eller
fisher.test( with(strokedata, table(diagdict, inhospdead)) )
Fisher's Exact Test for Count Data
data: with(strokedata, table(diagdict, inhospdead))
p-value = 2.697e-08
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
0.09457859 0.32094882
sample estimates:
odds ratio
0.1726745
Logistisk regression kan laves med den generelle funktion glm()
(generalised lineary model), hvor family-argumentet angives som "binomial",
således:
glm(y ~ x, data=df, family="binomial")
Resultatet af modellen hentes med funktionen: summary(model2)
model1 <- glm(morsdic1y ~ smoking, data=strokedata, family="binomial")
summary(model1)
Min | 1Q | Median | 3Q | Max |
---|---|---|---|---|
-0.6641 | -0.6641 | -0.6246 | -0.4990 | 2.0713 |
Estimate | Std.Error | z value | Pr(>|z|) | ||
---|---|---|---|---|---|
(Intercept) | -2.0206 | 0.1799 | -11.233 | <2e-16 | *** |
smokingNever | 0.6212 | 0.2208 | 2.813 | 0.0049 | ** |
smokingPrevious | 0.4853 | 0.2325 | 2.087 | 0.0369 | * |
Null deviance: 901.83 on 998 degrees of freedom |
---|
Residual deviance: 893.21 on 996 degrees of freedom |
Resultaterne returneres på en logaritmisk skala og hvis man skal bruge odds ratio'er skal de transformeres med funktionen exp()
. Alternativt kan man
bruge funktionen publish()
fra pakken {Publish}, som yderligere også udregner konfidensintervaller for odds ratio'erne:
Publish::publish(model2)
Variable | Units | OddsRatio | CI.95 | p-value |
---|---|---|---|---|
smoking | Current | Ref | ||
Never | 1.86 | [1.21;2.87] | 0.004904 | |
Previous | 1.62 | [1.03;2.56] | 0.036881 |
I eksemplet er nuværende rygere (Current) brugt som reference, men fortolkningsmæssigt er det mere intuitivt at bruge de ueksponerede som reference, hvilket her er dem der
aldrig har røget (Never). For at ændre referencen med funktionen relevel( x, ref = r)
:
model2 <- morsdic1y ~ relevel(smoking, ref = "Never"),
data = strokedata, family = "binomial")
Publish::publish(model3)
Variable | Units | OddsRatio | CI.95 | p-value |
---|---|---|---|---|
relevel(smoking, ref = "Never") | Never | Ref | ||
Current | 0.54 | [0.35;0.83] | 0.004904 | |
Previous | 0.87 | [0.60;1.28] | 0.486122 |
Tilsvarende kan man bruge relevel()
-funktionen til at styre referencen for udfaldet, hvilket I dette eksempel ville være
relevel(morsdic1y, ref = "Alive")
.
I eksemplet med rygning og risikoen for at dø ser det ud til at der er lavere risiko for nuværende rygere end for patienter der aldrig har røget. Dette resultat virker
umiddelbart ikke rimeligt og kan muligvis forklares med en fælles association til en confounding faktor, som der bør justeres for.
Modellen kan justeres for kovariate ved at indsætte dem med et plus på x-siden af regressionsformlen, således glm(y ~ x + a, data = df, family="binomial")
.
En mulig confounder kunne være alder, hvorfor modellen kan justeres for dette:
model3 <- glm(morsdic1y ~ relevel(smoking, ref = "Never") + age,
data = strokedata, family = "binomial")
summary(model3)
Min | 1Q | Median | 3Q | Max |
---|---|---|---|---|
-1.4425 | -0.6108 | -0.3881 | -0.1964 | 3.0407 |
Estimate | Std.Error | z value | Pr(>|z|) | ||
---|---|---|---|---|---|
(Intercept) | -9.913524 | 0.884039 | -11.214 | <2e-16 | *** |
relevel(smoking, ref = "Never")Current | 0.241836 | 0.250483 | 0.965 | 0.334 | |
relevel(smoking, ref = "Never")Previous | 0.009786 | 0.213097 | 0.046 | 0.963 | |
age | 0.108171 | 0.010673 | 10.135 | <2e-16 | *** |
Null deviance: 901.83 on 998 degrees of freedom |
---|
Residual deviance: 751.16 on 996 degrees of freedom |
Publish::publish(model3)
Variable | Units | OddsRatio | CI.95 | p-value | |
---|---|---|---|---|---|
relevel(smoking, ref = "Never") | Never | Ref | |||
Current | 1.27 | [0.78;2.08] | 0.3343 | ||
Previous | 1.01 | [0.67;1.53] | 0.9634 | ||
age | 1.11 | [1.09;1.14] | <1e-04 |
Efter justering for alder ses det at der ikke længere er statistisk signifikant forskel mellem kategorierne i rygningsvariablen, og den tilsyneladende gavnlige effekt af rygning kan derfor forklares med at rygerne er yngre.