Statistik
eksempler i R

Neurologi Neuroanatomi Statistik Home

Deskriptiv


Kvantitative data
Kategoriske data
Intervaller

Analytisk


Sandsynligheder

Kategoriske udfald

Kategoriske eksponeringer
Logistisk regression

Kvantitative udfald

Kvantitative udfald
Linær regression
Korrelationer
Overlevelse
Poisson regression

Tilfældighed


Randomisering

Forskning


PhD thesis



Jacob Liljehult
Klinisk sygeplejespecialist
cand.scient.san, Ph.d.

Neurologisk afdeling
Nordsjællands Hospital

Kategoriske data

Test når både eksponering og udfald er kategorisk

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
diagdictAliveDead
ICH8822
IS88338

Chi2-test

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:

Marginal model

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

Summerede data

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
diagdictAliveDead
ICH103.59846.401552
IS867.401653.598448

Fisher exact test

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

Test når eksponeringen er enten kategorisk eller kvantitativ og udfald er binomialt

Logistisk regression

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)

Call:
glm(formula = morsdic1y ~ smoking, family = "binomial", data = strokedata)

Deviance Residuals:
Min1QMedian3QMax
-0.6641-0.6641-0.6246-0.49902.0713

Coefficients:
Estimate Std.Error z value Pr(>|z|)
(Intercept)-2.02060.1799-11.233<2e-16 ***
smokingNever0.62120.22082.8130.0049 **
smokingPrevious0.48530.23252.0870.0369 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

Null deviance: 901.83 on 998 degrees of freedom
Residual deviance: 893.21 on 996 degrees of freedom
  (32 observations deleted due to missingness)
AIC: 899.21

Number of Fisher Scoring iterations: 4

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)

VariableUnitsOddsRatioCI.95p-value
smokingCurrentRef
Never1.86[1.21;2.87]0.004904
Previous1.62[1.03;2.56]0.036881

Ændring af reference-kategorier

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)

VariableUnitsOddsRatioCI.95p-value
relevel(smoking, ref = "Never")NeverRef
Current 0.54[0.35;0.83] 0.004904
Previous0.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").

Justerede modeller

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)

Call:
glm(formula = morsdic1y ~ relevel(smoking, ref = "Never") + age,
family = "binomial", data = strokedata)

Deviance Residuals:
Min1QMedian3QMax
-1.4425-0.6108-0.3881-0.19643.0407

Coefficients:
Estimate Std.Error z value Pr(>|z|)
(Intercept)-9.9135240.884039-11.214<2e-16 ***
relevel(smoking, ref = "Never")Current0.2418360.2504830.9650.334
relevel(smoking, ref = "Never")Previous0.0097860.2130970.0460.963
age0.1081710.01067310.135<2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

Null deviance: 901.83 on 998 degrees of freedom
Residual deviance: 751.16 on 996 degrees of freedom
  (32 observations deleted due to missingness)
AIC: 759.16

Number of Fisher Scoring iterations: 5

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.