#Packages
library(rio) #laden van data
library(sjPlot) #overzichten van data objecten
library(tidyverse) #datamanipulatie en grafieken
library(broom) #resultaten van regressiemodellen
#Data
<- import("ESS9e03, Netherlands.sav")
ESS9NL
#view_df example op subset van de dataset
|>
ESS9NL select(polintr, ppltrst) |>
::view_df() sjPlot
9 Logistische Regressie & Odds Ratios
Logistische regressiemodellen worden gebruikt voor binaire afhankelijke variabelen. We maken hier gebruik van de Nederlandse survey voor ronde 9 van de European Social Survey (ESS). Deze dataset is op de ESS website beschikbaar in SPSS format (.sav). We kunnen de view_df
functie in sjplot
gebruiken om de variabelen en hun labels in de dataset te inspecteren. Zie Paragraaf 1.1
ID | Name | Label | Values | Value Labels |
1 | polintr | How interested in politics | 1 2 3 4 7 8 9 |
Very interested Quite interested Hardly interested Not at all interested Refusal Don't know No answer |
2 | ppltrst | Most people can be trusted or you can't be too careful |
0 1 2 3 4 5 6 7 8 9 10 77 88 99 |
You can't be too careful 1 2 3 4 5 6 7 8 9 Most people can be trusted Refusal Don't know No answer |
Deview_df()
output toont dat er numerieke waarden zijn die geassocieerd zijn met ontbrekende waarden (bv. respondenten die “Don’t Know” antwoorden krijgen een score van 8 op polintr
). Deze waarden werden al naar ‘NA’ omgezet zoals je kunt zien in onderstaande tabel en dus is er geen verdere data managament nodig. Zie Section 4.2 van het Statistiek 1 boek om deze leerstof op te frissen.
table(ESS9NL$polintr)
1 2 3 4
213 832 478 149
Kijk altijd goed naar instructies van opdrachten alsook verdere informatie over de dataset (bv. het codeboek, of informatie over de dataset te verkrijgen met functies zoals view_df()
of attributes()
) om te weten welke datamanagement stappen je moet zetten vooraleer je je analyse kan uitvoeren.
9.1 Logistische regressieanalyse
9.1.1 Data Management
In dit voorbeeld zullen we eerst onderzoeken of gender (gndr
) opkomst bij verkiezingen bepaalt (vote
).
We kijken eerst of data management nodig is:
#Variabele attributen
|>
ESS9NL select(gndr, vote) |>
view_df()
ID | Name | Label | Values | Value Labels |
1 | gndr | Gender | 1 2 9 |
Male Female No answer |
2 | vote | Voted last national election | 1 2 3 7 8 9 |
Yes No Not eligible to vote Refusal Don't know No answer |
#Tabellen
table(ESS9NL$gndr)
1 2
833 840
table(ESS9NL$vote)
1 2 3
1291 247 130
De onafhankelijke variabele heeft 2 categorieën en moet in een factor variabele worden omgezet. De afhankelijke variabele heeft 3 categorieën (Yes, No, Not Eligible). We maken hier een binaire factor variabele van door eerst de “Not Eligible” categorie op NA te zetten:
#Factor maken
<- ESS9NL |>
ESS9NL mutate(gndr_F = factorize(gndr),
vote_F = factorize(vote))
#not eligible op NA
<- ESS9NL |>
ESS9NL mutate(vote_F = na_if(vote_F,"Not eligible to vote"))
- 1
- De categorie met de laagste numerieke waarde wordt hierbij de referentiecategorie. We gebruiken factorize gezien datawaarden labels hebben.
- 2
- We maken hier geen nieuwe variabele aan voor de gehercodeerde variabelen maar overschrijven de originele variabelen. Dit is doorgaans niet aangeraden voor studenten, gelukkig weten wij meestal wel waar we mee bezig zijn.
We checken de niveaus van de variabelen, in het bijzonder van de vote variabele:
levels(ESS9NL$vote_F)
[1] "Yes" "No" "Not eligible to vote"
[4] "Refusal" "Don't know" "No answer"
table(ESS9NL$vote_F)
Yes No Not eligible to vote
1291 247 0
Refusal Don't know No answer
0 0 0
De vote
variabele is nu een factor variabele met “Yes” als de referentiecategorie. Dit is niet wat we willen gezien we stemmen willen voorspellen. Als we de variabele zo laten voorspelt het model of een persoon niet heeft gestemd. We veranderen dit met de relevel functie (zie Paragraaf 2.1.1).1
#Relevel de variabele
<- ESS9NL |>
ESS9NL mutate(vote_F = relevel(vote_F, "No"))
#en controleer het resultaat
levels(ESS9NL$vote_F)
[1] "No" "Yes" "Not eligible to vote"
[4] "Refusal" "Don't know" "No answer"
mutate(vote_F = relevel(vote_F, "No"))
-
We gebruiken de relevel functie op de
vote
variabele. We creëren hier geen nieuwe variabele, maar overschrijven de oude. Je zou er ook voor kunnen kiezen een nieuwe variabele te maken. De categorie tussen dubbele aanhalingstekens zal de eerste categorie worden en dus de referentiecategorie in de regressie. We gebruiken het label “No” omdat de variabele reeds tot factor is getransformeerd (en dus niet de originele numerieke waarde ‘2’).
Laten we nu kijken naar de gndr_F
variabele:
table(ESS9NL$gndr_F)
Male Female No answer
833 840 0
levels(ESS9NL$gndr_F)
[1] "Male" "Female" "No answer"
Als we de niveaus bekijken zien we dat ‘Male’ als referentie zal worden genomen. Dit is prima, maar bij wijze van voorbeeld veranderen we dit hieronder naar ‘Female’. We zien ook een derde categorie ‘No answer’. Dit label werd gegeven aan de waarde in de variabele maar is leeg. R zal deze dus verwijderen in de analyses.
<- ESS9NL |>
ESS9NL mutate(gndr_F = relevel(gndr_F, "Female"))
#controleer je codering
levels(ESS9NL$gndr_F)
[1] "Female" "Male" "No answer"
De afhankelijke variabele voor een logistische regressie is een (factor) binaire variabele. Zorg ervoor dat de referentiecategorie de uitkomst is die je niet wil voorspellen en de hoogste categorie net die is die je wil voorspellen. Anders zal je interpretatie foutief zijn.
9.1.2 Logistische regressie uitvoeren
Het uitvoeren van logistische regressie in R is gelijkaardig aan lineare regressie. In plaats van de ingebouwde functie lm()
, gebruiken we de eveneens ingebouwde glm()
functie. De afkorting staat voor ‘generalized linear model’.
#Schat het model
<- glm(vote_F ~ gndr_F,
Vote_model data = ESS9NL, family = "binomial")
Vote_model <-
-
We slaan de resultaten op in een data object met naam naar keuze.
glm(vote_F ~ gndr_F,
-
We voeren de glm functie uit met gefactoriseerde vote als afhankelijke variabele, voorspeld (~) door onze enige onafhankelijke variabele: gndr (gefactoriseerd). We kunnen meerdere onafhankelijke variabelen toevoegen, gescheiden van elkaar met een ‘+’ teken.
data = ESS9NL,
-
We geven aan welke dataset gebruikt wordt.
family = "binomial")
-
We verduidelijken de familie van modellen voor ons generalized linear model. Voor logistische regressie is dit “binomial”. Dit gedeelte van de code blijft onveranderd. Zie de Veelvoorkomende Fouten appendix ( Paragraaf A.3) voor een error die je kunt tegenkomen als je dit gedeelte vergeet.
De resultaten bekijken we weer met de summary()
functie:
summary(Vote_model)
Call:
glm(formula = vote_F ~ gndr_F, family = "binomial", data = ESS9NL)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 1.56485 0.09535 16.412 <2e-16 ***
gndr_FMale 0.18359 0.13925 1.318 0.187
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 1355.5 on 1537 degrees of freedom
Residual deviance: 1353.7 on 1536 degrees of freedom
(135 observations deleted due to missingness)
AIC: 1357.7
Number of Fisher Scoring iterations: 4
De output is gelijkaardig aan die van de lineaire regressie met lm()
.
- Call: Het model dat geschat werd
- Deviance Residuals: beschrijvende statistieken over de residuals van het model.
- Coefficients: De logistische regressiecoëfficiënten (Estimate), hun standaardfouten (Std. Error), en de teststatistiek (z-waarde; de Z-statistiek is gelijk aan \(\frac{\textrm{Coefficient}}{\textrm{Std. Error}}\)), en de p-waarde voor de z-statistiek (Pr(>|z|). Symbolen m.b.t. statistische significantie vind je rechts van de p-waarde waar van toepassing. De interpretatie van de symbolen wordt uitgelegd in de legende onder de coëfficiënten (“Signif. Codes:”).
- (Dispersion parameter…): Te negeren.
- Area that begins with Null deviance: Informatie over de fit van het model, besproken in een volgend hoofdstuk.
- Number of Fisher Scoring Iterations: Aantal iteraties van het algoritme.
We kunnen meerdere predictoren toevoegen aan het model op een gelijkaardige manier als bij lineaire regressie: door ze te scheiden met een +
teken. Hier voegen we leeftijd (agea
), vertrouwen in politici (trstplt
), en links-rechts positie (lrscale
) toe. Datamanagement voor deze variabelen is niet nodig: ze zijn continue en missing waarden zijn reeds als NA aangeduid.
#Schat het model
<- glm(vote_F ~ gndr_F + agea + trstplt + lrscale,
Vote_model_mp data = ESS9NL, family = "binomial")
#Bekijk de output
summary(Vote_model_mp)
Call:
glm(formula = vote_F ~ gndr_F + agea + trstplt + lrscale, family = "binomial",
data = ESS9NL)
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -0.284194 0.380455 -0.747 0.455
gndr_FMale 0.043281 0.154201 0.281 0.779
agea 0.018349 0.004503 4.075 4.61e-05 ***
trstplt 0.195020 0.038706 5.039 4.69e-07 ***
lrscale 0.029257 0.039306 0.744 0.457
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 1173.9 on 1424 degrees of freedom
Residual deviance: 1135.3 on 1420 degrees of freedom
(248 observations deleted due to missingness)
AIC: 1145.3
Number of Fisher Scoring iterations: 4
Logistische regressiecoëfficiënten geven een schatting van de verandering in de log van de odds dat Y=1 als X met 1 eenheid stijgt. Ze zijn dus niet makkelijk direct te interpreteren. We kunnen ze wel gebruiken om iets over de richting van de relatie te zeggen. Een positieve coëfficiënt toont dat de kans dat Y=1 stijgt als de onafhankelijke variabele stijgt. Een negatieve coëfficiënt toont dat de kans dat Y=1 daalt als de onafhankelijke variabele stijgt. Voor verdere interpretatie maak je best gebruik van de odds ratios (in minder mate), de gemiddelde marginale effecten (average marginal effects) (zie Hoofdstuk 10) of de voorspelde kansen (zie Hoofdstuk 11) .
Voor dit voorbeeld:
- Mannen hebben een grotere kans om te stemmen dan vrouwen, maar het verschil is niet statistisch significant (p = 0.28).
- Oudere respondenten hebben een grotere kans om te gaan stemmen en dit verband is statistisch significant (p < 0.001).
- Respondenten met meer vertrouwen in politici hebben een grotere kans om te gaan stemmen. deze relatie is statistisch significant (p < 0.001).
- Stemmen is meer waarschijnlijk naarmate respondenten zich rechtser positioneren op de ideologieschaal, maar dit effect is niet statistisch significant (p = 0.74).
9.2 Odds Ratios
Logistische regressiecoëfficiënten kunnen omgezet worden in odds ratios die (iets) intuïtiever zijn om te interpereteren.
We kunnen de odds ratios en 95% betrouwbaarheidsintervallen verkrijgen met de tidy
functie uit het broom
package:
# logistische regressiecoëfficiënten en hun betrouwbaarheidsintervallen
tidy(Vote_model_mp, conf.int = TRUE)
# A tibble: 5 × 7
term estimate std.error statistic p.value conf.low conf.high
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 (Intercept) -0.284 0.380 -0.747 0.455 -1.03 0.463
2 gndr_FMale 0.0433 0.154 0.281 0.779 -0.259 0.346
3 agea 0.0183 0.00450 4.07 0.0000461 0.00958 0.0272
4 trstplt 0.195 0.0387 5.04 0.000000469 0.119 0.271
5 lrscale 0.0293 0.0393 0.744 0.457 -0.0480 0.106
# odds ratios (i.e. 'exponentiële coëfficiënten') en hun betrouwbaarheidsintervallen
tidy(Vote_model_mp, conf.int = TRUE, exp = TRUE)
# A tibble: 5 × 7
term estimate std.error statistic p.value conf.low conf.high
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 (Intercept) 0.753 0.380 -0.747 0.455 0.357 1.59
2 gndr_FMale 1.04 0.154 0.281 0.779 0.772 1.41
3 agea 1.02 0.00450 4.07 0.0000461 1.01 1.03
4 trstplt 1.22 0.0387 5.04 0.000000469 1.13 1.31
5 lrscale 1.03 0.0393 0.744 0.457 0.953 1.11
Zo lees je de syntax:
tidy(Vote_model_mp
-
We gebruiken de tidy functie op het model tussen haakjes.
conf.int = TRUE
-
We vragen R om de betrouwbaarheidsintervallen weer te geven. We kunnen ‘FALSE’ schrijven of deze code weglaten als we de betrouwbaarheidsintervallen niet willen.
exp = TRUE)
-
We vragen hier om de exponentiële (exponentiated) logistische regressiecoëfficiënten, oftewel de odds ratios. We kunnen ‘FALSE’ schrijven of deze code weglaten als we de logistische regressiecoëfficiënten willen.
Voor de interpretatie van odds ratios zijn er 3 zaken waar je op moet letten.
Ten eerste, odds ratios vertellen ons iets over de relatieve odds dat Y = 1 (bv. iemand gaat stemmen). Dit is verschillend van de coëfficiënten. de coefficiënten zijn de gelogde versies van de relatieve odds..
Ten tweede, odds ratios zijn multiplicatief en worden geïnterpreteerd in termen van 1 in plaats van 0. Een odds ratio groter dan 1 betekent een hogere kans dat Y=1. Een odds ratio lager dan 1 betekent een lagere kans dat Y=1. Een odds ratio van 1 betekent dat er geen effect is. Een betrouwbaarheidsinterval voor een odds ratio waar 1 niet in voorkomt duidt een statistisch significant effect aan. Een odds ratio kan niet negatief zijn.
Ten derde interpreteren we ook de odds ratios met een multiplicatieve logica. In het voorbeeld vinden we dat de odds om te stemmen 1.04 keer groter zijn voor mannelijke respondenten dan vrouwelijke respondenten, ceteris paribus. Het effect is wel niet significant. De odds om te stemmen vermenigvuldigen met 1.02 telkens leeftijd met 1 eenheid omhoog gaat (de andere onafhankelijke variabelen constant gehouden).
Met
factor()
zouden we direct in de syntax de volgorde van de niveaus aan kunnen duiden:mutate(vote_binary = factor(vote, levels = c(2, 1), labels = c("Did not vote", "Voted"))
. Het gebruik van factor vermijdt een veelvoorkomnde fout besproken in volgend hoofdstuk.↩︎