Appendix

Author

Noah Levysohn, Leon Spillmann, Ilan Frei, Lawin Ideli, Alexander Pollakis

Published

January 19, 2026

ESS8 Datenmanipulation

alexandria()
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   4.0.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.2.0     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
Version:  1.39.4
Date:     2024-07-23
Author:   Philip Leifeld (University of Manchester)

Consider submitting praise using the praise or praise_interactive functions.
Please cite the JSS article in your publications -- see citation("texreg").


Attache Paket: 'texreg'


Das folgende Objekt ist maskiert 'package:tidyr':

    extract



Please cite as: 


 Hlavac, Marek (2022). stargazer: Well-Formatted Regression and Summary Statistics Tables.

 R package version 5.2.3. https://CRAN.R-project.org/package=stargazer 



Attache Paket: 'MASS'


Das folgende Objekt ist maskiert 'package:dplyr':

    select


Lade nötiges Paket: stats4

Lade nötiges Paket: splines


Please cite as: 


 Schlegel, Benjamin E. (2024). glm.predict: Predicted Values and Discrete Changes for Regression Models.

 R package version 4.3-0. https://cran.r-project.org/package=glm.predict 


Classes and Methods for R originally developed in the
Political Science Computational Laboratory
Department of Political Science
Stanford University (2002-2015),
by and under the direction of Simon Jackman.
hurdle and zeroinfl functions by Achim Zeileis.

Learn more about sjPlot with 'browseVignettes("sjPlot")'.


Attache Paket: 'sjPlot'


Das folgende Objekt ist maskiert 'package:ggplot2':

    set_theme


Lade nötiges Paket: Matrix


Attache Paket: 'Matrix'


Die folgenden Objekte sind maskiert von 'package:tidyr':

    expand, pack, unpack


Registered S3 method overwritten by 'clubSandwich':
  method    from    
  bread.mlm sandwich
df_ess8 <- read_csv("ESS8e02_3.csv")
Rows: 44387 Columns: 535
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr  (10): name, proddate, cntry, ctzshipc, cntbrthc, lnghom1, lnghom2, fbrn...
dbl (525): essround, edition, idno, dweight, pspwght, pweight, anweight, nws...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_essCOVID <- read_csv("ESS Theme - COVID-19.csv")
Rows: 59685 Columns: 47
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr  (3): name, proddate, cntry
dbl (44): essround, edition, idno, dweight, pspwght, pweight, anweight, prob...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_essCC <- read_csv("ESS Theme - Climate change.csv")
Rows: 150234 Columns: 45
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr  (3): name, proddate, cntry
dbl (42): essround, edition, idno, dweight, pspwght, pweight, anweight, prob...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_ess11 <- read_csv("ESS11e04_1.csv")
Warning: One or more parsing issues, call `problems()` on your data frame for details,
e.g.:
  dat <- vroom(...)
  problems(dat)
Rows: 50116 Columns: 691
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr    (9): name, proddate, cntry, cntbrthd, lnghom1, lnghom2, fbrncntc, mbr...
dbl  (666): essround, edition, idno, dweight, pspwght, pweight, anweight, nw...
lgl    (1): rshipa15
dttm  (15): inwds, ainws, ainwe, binwe, cinwe, dinwe, einwe, finwe, hinwe, i...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Vermerk: Die Funktion alexandria() ist eine eigens kreierte Funktion zum Laden mehrerer Packete.

df_ess8_de <- df_ess8 %>% filter(cntry == "DE")

df_ess8_de_var <- df_ess8_de %>% dplyr::select(imueclt, sbstrec, smdfslv, gvrfgap, inctxff, sbsrnen, bennent, atchctr, prtvede1, gndr, hinctnta, agea, edubde1, eduade2, eduade3, anweight)

df_ess8_ch <- df_ess8 %>% filter(cntry == "CH")

df_ess8_ch_var <- df_ess8_ch %>% dplyr::select(imueclt, sbstrec, smdfslv, gvrfgap, inctxff, sbsrnen, bennent, atchctr, prtvtfch, gndr, hinctnta, agea, edlvdch, anweight)
df_de_a <- df_ess8_de_var %>% rename(cultlife_undermined = imueclt, socbenefits_strainecon = sbstrec, diffinliving = smdfslv, appl_refugee = gvrfgap, increasetax_fossil = inctxff, subsid_renewenerg = sbsrnen, benefits_notentitled = bennent, attach_cntry = atchctr, vote = prtvede1)

df_ch_a <- df_ess8_ch_var %>% rename(cultlife_undermined = imueclt, socbenefits_strainecon = sbstrec, diffinliving = smdfslv, appl_refugee = gvrfgap, increasetax_fossil = inctxff, subsid_renewenerg = sbsrnen, benefits_notentitled = bennent, attach_cntry = atchctr, 
                                     vote = prtvtfch)

df_ch_a <- df_ch_a %>% mutate(cultlife_undermined = case_match(cultlife_undermined, 
                                                               77 ~ NA,
                                                               88 ~ NA,
                                                               99 ~ NA,
                                                               .default = cultlife_undermined))
df_ch_a <- df_ch_a %>% mutate(socbenefits_strainecon = case_match(socbenefits_strainecon,
                                                               7 ~ NA,
                                                               8 ~ NA,
                                                               9 ~ NA,
                                                               .default = socbenefits_strainecon))
df_ch_a <- df_ch_a %>% mutate(diffinliving = case_match(diffinliving,
                                                        7 ~ NA,
                                                        8 ~ NA,
                                                        9 ~ NA,
                                                        .default = diffinliving))
df_ch_a <- df_ch_a %>% mutate(appl_refugee = case_match(appl_refugee,
                                                        7 ~ NA,
                                                        8 ~ NA,
                                                        9 ~ NA,
                                                        .default = appl_refugee))
df_ch_a <- df_ch_a %>% mutate(increasetax_fossil = case_match(increasetax_fossil,
                                                              7 ~ NA,
                                                              8 ~ NA,
                                                              9 ~ NA,
                                                              .default = increasetax_fossil))
df_ch_a <- df_ch_a %>% mutate(subsid_renewenerg = case_match(subsid_renewenerg,
                                                             7 ~ NA,
                                                             8 ~ NA,
                                                             9 ~ NA,
                                                             .default = subsid_renewenerg))
df_ch_a <- df_ch_a %>% mutate(benefits_notentitled = case_match(benefits_notentitled,
                                                                7 ~ NA,
                                                                8 ~ NA,
                                                                9 ~ NA,
                                                                .default = benefits_notentitled))
df_ch_a <- df_ch_a %>% mutate(attach_cntry = case_match(attach_cntry,
                                                        77 ~ NA,
                                                        88 ~ NA,
                                                        99 ~ NA,
                                                        .default = attach_cntry))



df_de_a <- df_de_a %>% mutate(cultlife_undermined = case_match(cultlife_undermined, 
                                                               77 ~ NA,
                                                               88 ~ NA,
                                                               99 ~ NA,
                                                               .default = cultlife_undermined))
df_de_a <- df_de_a %>% mutate(socbenefits_strainecon = case_match(socbenefits_strainecon,
                                                               7 ~ NA,
                                                               8 ~ NA,
                                                               9 ~ NA,
                                                               .default = socbenefits_strainecon))
df_de_a <- df_de_a %>% mutate(diffinliving = case_match(diffinliving,
                                                        7 ~ NA,
                                                        8 ~ NA,
                                                        9 ~ NA,
                                                        .default = diffinliving))
df_de_a <- df_de_a %>% mutate(appl_refugee = case_match(appl_refugee,
                                                        7 ~ NA,
                                                        8 ~ NA,
                                                        9 ~ NA,
                                                        .default = appl_refugee))
df_de_a <- df_de_a %>% mutate(increasetax_fossil = case_match(increasetax_fossil,
                                                              7 ~ NA,
                                                              8 ~ NA,
                                                              9 ~ NA,
                                                              .default = increasetax_fossil))
df_de_a <- df_de_a %>% mutate(subsid_renewenerg = case_match(subsid_renewenerg,
                                                             7 ~ NA,
                                                             8 ~ NA,
                                                             9 ~ NA,
                                                             .default = subsid_renewenerg))
df_de_a <- df_de_a %>% mutate(benefits_notentitled = case_match(benefits_notentitled,
                                                                7 ~ NA,
                                                                8 ~ NA,
                                                                9 ~ NA,
                                                                .default = benefits_notentitled))
df_de_a <- df_de_a %>% mutate(attach_cntry = case_match(attach_cntry,
                                                        77 ~ NA,
                                                        88 ~ NA,
                                                        99 ~ NA,
                                                        .default = attach_cntry))


df_ch_a <- df_ch_a %>% mutate(vote = case_match(vote, 1 ~ 1,
                                                .default = 0))
df_de_a <- df_de_a %>% mutate(vote = case_match(vote, 6 ~ 1,
                                                .default = 0))

Vermerk: Antwort-Items aus dem Datensatz, welche nicht Teil der Skala sind (beispielsweise Don’t know) werden hier zu NAs umcodiert. Abhängige Varaible wird zu einer binären Variable umcodiert.

df_ch_a <- df_ch_a %>% mutate(cultlife_undermined = 10 - cultlife_undermined)
df_de_a <- df_de_a %>% mutate(cultlife_undermined = 10 - cultlife_undermined)

df_ch_a <- df_ch_a %>% mutate(socbenefits_strainecon = 6 - socbenefits_strainecon)
df_de_a <- df_de_a %>% mutate(socbenefits_strainecon = 6 - socbenefits_strainecon)

df_ch_a <- df_ch_a %>% mutate(benefits_notentitled = 6 - benefits_notentitled)
df_de_a <- df_de_a %>% mutate(benefits_notentitled = 6 - benefits_notentitled)

Vermerk: Anpassung der Skalenreihenfolge, so dass tiefe (hohe) Werte über alle Variablen “linken” (“rechten”) Positionen entsprechen.

library(lavaan)
This is lavaan 0.6-20
lavaan is FREE software! Please report any bugs.
cfa_1 <- "F1 =~ cultlife_undermined + appl_refugee + increasetax_fossil + attach_cntry"
cfa_fit_ch <- lavaan::cfa(cfa_1, data = df_ch_a)
summary(cfa_fit_ch)
lavaan 0.6-20 ended normally after 31 iterations

  Estimator                                         ML
  Optimization method                           NLMINB
  Number of model parameters                         8

                                                  Used       Total
  Number of observations                          1462        1525

Model Test User Model:
                                                      
  Test statistic                                 9.139
  Degrees of freedom                                 2
  P-value (Chi-square)                           0.010

Parameter Estimates:

  Standard errors                             Standard
  Information                                 Expected
  Information saturated (h1) model          Structured

Latent Variables:
                   Estimate  Std.Err  z-value  P(>|z|)
  F1 =~                                               
    cultlif_ndrmnd    1.000                           
    appl_refugee      0.498    0.060    8.349    0.000
    increastx_fssl    0.252    0.030    8.444    0.000
    attach_cntry      0.138    0.042    3.292    0.001

Variances:
                   Estimate  Std.Err  z-value  P(>|z|)
   .cultlif_ndrmnd    2.832    0.284    9.989    0.000
   .appl_refugee      0.621    0.069    8.956    0.000
   .increastx_fssl    1.238    0.049   25.275    0.000
   .attach_cntry      3.537    0.132   26.857    0.000
    F1                2.252    0.306    7.354    0.000
cfa <- "F1 =~ cultlife_undermined + appl_refugee + increasetax_fossil + attach_cntry"
cfa_fit_de <- lavaan::cfa(cfa_1, data = df_de_a)
summary(cfa_fit_de)
lavaan 0.6-20 ended normally after 32 iterations

  Estimator                                         ML
  Optimization method                           NLMINB
  Number of model parameters                         8

                                                  Used       Total
  Number of observations                          2788        2852

Model Test User Model:
                                                      
  Test statistic                                16.331
  Degrees of freedom                                 2
  P-value (Chi-square)                           0.000

Parameter Estimates:

  Standard errors                             Standard
  Information                                 Expected
  Information saturated (h1) model          Structured

Latent Variables:
                   Estimate  Std.Err  z-value  P(>|z|)
  F1 =~                                               
    cultlif_ndrmnd    1.000                           
    appl_refugee      0.434    0.034   12.932    0.000
    increastx_fssl    0.270    0.021   13.178    0.000
    attach_cntry      0.126    0.032    3.991    0.000

Variances:
                   Estimate  Std.Err  z-value  P(>|z|)
   .cultlif_ndrmnd    3.511    0.229   15.334    0.000
   .appl_refugee      0.730    0.044   16.610    0.000
   .increastx_fssl    1.126    0.034   33.176    0.000
   .attach_cntry      4.649    0.125   37.128    0.000
    F1                2.776    0.251   11.052    0.000
cfa_2 <- "F2 =~ socbenefits_strainecon + diffinliving + benefits_notentitled"
cfa_fit_ch_econ <- lavaan::cfa(cfa_2, data = df_ch_a)
summary(cfa_fit_ch_econ)
lavaan 0.6-20 ended normally after 32 iterations

  Estimator                                         ML
  Optimization method                           NLMINB
  Number of model parameters                         6

                                                  Used       Total
  Number of observations                          1352        1525

Model Test User Model:
                                                      
  Test statistic                                 0.000
  Degrees of freedom                                 0

Parameter Estimates:

  Standard errors                             Standard
  Information                                 Expected
  Information saturated (h1) model          Structured

Latent Variables:
                   Estimate  Std.Err  z-value  P(>|z|)
  F2 =~                                               
    scbnfts_strncn    1.000                           
    diffinliving      0.119    0.075    1.580    0.114
    benfts_ntnttld    0.795    0.529    1.503    0.133

Variances:
                   Estimate  Std.Err  z-value  P(>|z|)
   .scbnfts_strncn    0.530    0.252    2.104    0.035
   .diffinliving      0.773    0.030   25.814    0.000
   .benfts_ntnttld    0.650    0.161    4.045    0.000
    F2                0.378    0.253    1.494    0.135
cfa_2 <- "F2 =~ socbenefits_strainecon + diffinliving + benefits_notentitled"
cfa_fit_de_econ <- lavaan::cfa(cfa_2, data = df_de_a)
summary(cfa_fit_de_econ)
lavaan 0.6-20 ended normally after 26 iterations

  Estimator                                         ML
  Optimization method                           NLMINB
  Number of model parameters                         6

                                                  Used       Total
  Number of observations                          2694        2852

Model Test User Model:
                                                      
  Test statistic                                 0.000
  Degrees of freedom                                 0

Parameter Estimates:

  Standard errors                             Standard
  Information                                 Expected
  Information saturated (h1) model          Structured

Latent Variables:
                   Estimate  Std.Err  z-value  P(>|z|)
  F2 =~                                               
    scbnfts_strncn    1.000                           
    diffinliving      0.132    0.070    1.900    0.057
    benfts_ntnttld    0.352    0.181    1.946    0.052

Variances:
                   Estimate  Std.Err  z-value  P(>|z|)
   .scbnfts_strncn    0.282    0.342    0.825    0.409
   .diffinliving      0.807    0.023   35.414    0.000
   .benfts_ntnttld    0.805    0.048   16.893    0.000
    F2                0.668    0.343    1.949    0.051
df_ch_a <- df_ch_a %>% mutate(index_galtan = (((df_ch_a$cultlife_undermined - mean(df_ch_a$cultlife_undermined, na.rm = T)) / sd(df_ch_a$cultlife_undermined, na.rm = T)) + ((df_ch_a$appl_refugee - mean(df_ch_a$appl_refugee, na.rm = T)) / sd(df_ch_a$appl_refugee, na.rm = T)) + ((df_ch_a$increasetax_fossil - mean(df_ch_a$increasetax_fossil, na.rm = T)) / sd(df_ch_a$increasetax_fossil, na.rm = T)) + ((df_ch_a$attach_cntry - mean(df_ch_a$attach_cntry, na.rm = T)) / sd(df_ch_a$attach_cntry, na.rm = T))) / 4)

df_de_a <- df_de_a %>% mutate(index_galtan = (((df_de_a$cultlife_undermined - mean(df_de_a$cultlife_undermined, na.rm = T)) / sd(df_de_a$cultlife_undermined, na.rm = T)) + ((df_de_a$appl_refugee - mean(df_de_a$appl_refugee, na.rm = T)) / sd(df_de_a$appl_refugee, na.rm = T)) + ((df_de_a$increasetax_fossil - mean(df_de_a$increasetax_fossil, na.rm = T)) / sd(df_de_a$increasetax_fossil, na.rm = T)) + ((df_de_a$attach_cntry - mean(df_de_a$attach_cntry, na.rm = T)) / sd(df_de_a$attach_cntry, na.rm = T))) / 4)

df_ch_a <- df_ch_a %>% mutate(index_galtan = index_galtan + 2.5)
df_de_a <- df_de_a %>% mutate(index_galtan = index_galtan + 2.5)



df_ch_a <- df_ch_a %>% mutate(index_econ = (((df_ch_a$socbenefits_strainecon - mean(df_ch_a$socbenefits_strainecon, na.rm = T)) / sd(df_ch_a$socbenefits_strainecon, na.rm = T)) + ((df_ch_a$diffinliving - mean(df_ch_a$diffinliving, na.rm = T)) /  sd(df_ch_a$diffinliving, na.rm = T)) + ((df_ch_a$benefits_notentitled - mean(df_ch_a$benefits_notentitled, na.rm = T)) / sd(df_ch_a$benefits_notentitled, na.rm = T))) / 3)

df_de_a <- df_de_a %>% mutate(index_econ = (((df_de_a$socbenefits_strainecon - mean(df_de_a$socbenefits_strainecon, na.rm = T)) / sd(df_de_a$socbenefits_strainecon, na.rm = T)) + ((df_de_a$diffinliving - mean(df_de_a$diffinliving, na.rm = T)) /  sd(df_de_a$diffinliving, na.rm = T)) + ((df_de_a$benefits_notentitled - mean(df_de_a$benefits_notentitled, na.rm = T)) / sd(df_de_a$benefits_notentitled, na.rm = T))) / 3)


df_ch_a <- df_ch_a %>% mutate(index_econ = index_econ + 2.5)
df_de_a <- df_de_a %>% mutate(index_econ = index_econ + 2.5)

Vermerk: Standardisierung und Berechnung des Mittelwerts zur Erstellung des Index. Eichung des Minimal auf Null.

Modellierung

Modell zu gesellschaftspolitischer Position (ESS8)

logit_svp <- glm(vote ~ index_galtan + agea + edlvdch + hinctnta + gndr, data = df_ch_a, family = binomial("logit"), weights = anweight)
Warning in eval(family$initialize): Nicht-ganzzahlige #Erfolge in einem
binomial-GLM
screenreg(logit_svp)

===========================
                Model 1    
---------------------------
(Intercept)       -7.48 ***
                  (0.94)   
index_galtan       2.02 ***
                  (0.28)   
agea               0.00    
                  (0.00)   
edlvdch           -0.00    
                  (0.00)   
hinctnta          -0.01    
                  (0.01)   
gndr              -0.23    
                  (0.28)   
---------------------------
AIC              218.39    
BIC              250.12    
Log Likelihood  -103.20    
Deviance         357.77    
Num. obs.       1462       
===========================
*** p < 0.001; ** p < 0.01; * p < 0.05
logit_afd <- glm(vote ~ index_galtan + agea + hinctnta + gndr, data = df_de_a, family = binomial("logit"), weights = anweight)
Warning in eval(family$initialize): Nicht-ganzzahlige #Erfolge in einem
binomial-GLM
set.seed(123)
preds_afd <- predicts(logit_afd, "0-4.5; median; median; mode", type = "simulation")

Visualisierung

set.seed(123)
preds_svp <- predicts(logit_svp, "0-4.5; median; mode; median; mode",  type = "simulation")

preds_svp %>% ggplot(aes(x = index_galtan, y = mean, ymin = lower, ymax = upper)) +
  geom_ribbon(alpha = 0.3) +
  geom_line() + 
  ylab("Wahlwahrscheinlichkeit SVP") +
  xlab("Index zu gesellschaftspolitischer Position") + 
  scale_y_continuous(labels = scales::percent) +
  theme_minimal()

set.seed(123)
preds_afd <- predicts(logit_afd, "0-4.5; median; median; mode", type = "simulation")

preds_afd %>% ggplot(aes(x = index_galtan, y = mean, ymin = lower, ymax = upper)) +
  geom_ribbon(alpha = 0.3) +
  geom_line() + 
  ylab("Wahlwahrscheinlichkeit AfD") +
  xlab("Index zu gesellschaftspolitischer Position") + 
  scale_y_continuous(labels = scales::percent) +
  theme_minimal()

Modellgüte und t-Test

t.test(df_ch_a$index_galtan[df_ch_a$vote == 1], df_de_a$index_galtan[df_de_a$vote == 1])

    Welch Two Sample t-test

data:  df_ch_a$index_galtan[df_ch_a$vote == 1] and df_de_a$index_galtan[df_de_a$vote == 1]
t = 0.45383, df = 78.298, p-value = 0.6512
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.1357355  0.2158987
sample estimates:
mean of x mean of y 
 3.076196  3.036114 
set.seed(123)
pred_out_ch <- predict(logit_svp, type = "response")
pred_out_de <- predict(logit_afd, type = "response")

pred_out_ch.01 <- as.numeric(cut(pred_out_ch, breaks = c(-Inf, 0.5, Inf), labels = c(0,1)))
pred_out_de.01 <- as.numeric(cut(pred_out_de, breaks = c(-Inf, 0.5, Inf), labels = c(0,1)))

conf_mat_ch <- table(logit_svp$model$vote, pred_out_ch.01)
conf_mat_de <- table(logit_afd$model$vote, pred_out_de.01)


library(pROC)
Type 'citation("pROC")' for a citation.

Attache Paket: 'pROC'
Die folgenden Objekte sind maskiert von 'package:stats':

    cov, smooth, var
pROC::auc(logit_svp$model$vote, pred_out_ch)
Setting levels: control = 0, case = 1
Setting direction: controls < cases
Area under the curve: 0.803
pROC::auc(logit_afd$model$vote, pred_out_de)
Setting levels: control = 0, case = 1
Setting direction: controls < cases
Area under the curve: 0.7626
performance::r2_mcfadden(logit_svp)
Warning in eval(family$initialize): Nicht-ganzzahlige #Erfolge in einem
binomial-GLM
# R2 for Generalized Linear Regression
       R2: 0.204
  adj. R2: 0.197
performance::r2_mcfadden(logit_afd)
Warning in eval(family$initialize): Nicht-ganzzahlige #Erfolge in einem
binomial-GLM
# R2 for Generalized Linear Regression
       R2: 0.088
  adj. R2: 0.087

Modell zu verteilungspolitischer Position (ESS8)

logit_svp_econ <- glm(vote ~ index_econ + agea + edlvdch + hinctnta + gndr, data = df_ch_a, family = binomial("logit"), weights = anweight)
Warning in eval(family$initialize): Nicht-ganzzahlige #Erfolge in einem
binomial-GLM
logit_afd_econ <- glm(vote ~ index_econ + agea + hinctnta + gndr, data = df_de_a, family = binomial("logit"), weights = anweight)
Warning in eval(family$initialize): Nicht-ganzzahlige #Erfolge in einem
binomial-GLM

Visualisierung

set.seed(123)
preds_svp_econ <- predicts(logit_svp_econ, "0-5, 0.5; median; mode; median; mode",  type = "simulation")

preds_svp_econ %>% ggplot(aes(x = index_econ, y = mean, ymin = lower, ymax = upper)) +
  geom_ribbon(alpha = 0.3, fill = "#00cc00") +
  geom_line(color = "forestgreen", linewidth = 1.2) + 
  ylab("Wahlwahrscheinlichkeit SVP") +
  xlab("Index zu verteilungspolitischer Position") + 
  scale_y_continuous(labels = scales::percent) +
  theme_minimal() + 
  labs(title = "Wahlwahrscheinlichkeit der SVP nach verteilungspolitischer Position") 

set.seed(123)
preds_afd_econ <- predicts(logit_afd_econ, "0-5, 0.5; median; median; mode",  type = "simulation")

preds_afd_econ %>% ggplot(aes(x = index_econ, y = mean, ymin = lower, ymax = upper)) +
  geom_ribbon(alpha = 0.3, fill = "steelblue") +
  geom_line(color = "blue", linewidth = 1.2) + 
  ylab("Wahlwahrscheinlichkeit AfD") +
  xlab("Index zu verteilungspolitischer Position") + 
  scale_y_continuous(labels = scales::percent) +
  theme_minimal() +
  labs(title = "Wahlwahrscheinlichkeit der AfD nach verteilungspolitischer Position") 

Modellgüte und t-Test

t.test(df_ch_a$index_econ[df_ch_a$vote == 1], df_de_a$index_econ[df_de_a$vote == 1])

    Welch Two Sample t-test

data:  df_ch_a$index_econ[df_ch_a$vote == 1] and df_de_a$index_econ[df_de_a$vote == 1]
t = 1.1842, df = 83.204, p-value = 0.2397
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.08167486  0.32204951
sample estimates:
mean of x mean of y 
 2.841299  2.721112 
performance::r2_mcfadden(logit_svp_econ)
Warning in eval(family$initialize): Nicht-ganzzahlige #Erfolge in einem
binomial-GLM
# R2 for Generalized Linear Regression
       R2: 0.191
  adj. R2: 0.183
performance::r2_mcfadden(logit_afd_econ)
Warning in eval(family$initialize): Nicht-ganzzahlige #Erfolge in einem
binomial-GLM
# R2 for Generalized Linear Regression
       R2: 0.058
  adj. R2: 0.056
set.seed(123)
pred_out_ch_econ <- predict(logit_svp_econ, type = "response")
pred_out_de_econ <- predict(logit_afd_econ, type = "response")

pROC::auc(logit_svp_econ$model$vote, pred_out_ch_econ)
Setting levels: control = 0, case = 1
Setting direction: controls < cases
Area under the curve: 0.6795
pROC::auc(logit_afd_econ$model$vote, pred_out_de_econ)
Setting levels: control = 0, case = 1
Setting direction: controls < cases
Area under the curve: 0.6475
pred_out_ch_econ.01 <- cut(pred_out_ch_econ, breaks = c(-Inf, 0.5, Inf), labels = c(0,1))
pred_out_de_econ.01 <- cut(pred_out_de_econ, breaks = c(-Inf, 0.5, Inf), labels = c(0,1))

conf_mat_econ_ch <- table(logit_svp_econ$model$vote, pred_out_ch_econ.01)
conf_mat_econ_de <- table(logit_afd_econ$model$vote, pred_out_de_econ.01)
stargazer(list(logit_svp, logit_afd, logit_svp_econ, logit_afd_econ), 
          type = "text")

=========================================================
                            Dependent variable:          
                  ---------------------------------------
                                   vote                  
                     (1)       (2)       (3)       (4)   
---------------------------------------------------------
index_galtan      2.019***  1.468***                     
                   (0.276)   (0.167)                     
                                                         
index_econ                            0.947***  0.596*** 
                                       (0.221)   (0.152) 
                                                         
agea                0.002     0.003     0.003     0.006  
                   (0.004)   (0.004)   (0.004)   (0.005) 
                                                         
edlvdch            -0.001              -0.001            
                   (0.002)             (0.005)           
                                                         
hinctnta           -0.007   -0.015**   -0.005   -0.014** 
                   (0.005)   (0.006)   (0.005)   (0.006) 
                                                         
gndr               -0.226   -0.552***  -0.325   -0.624***
                   (0.282)   (0.188)   (0.277)   (0.191) 
                                                         
Constant          -7.480*** -7.204*** -4.312*** -4.825***
                   (0.942)   (0.587)   (0.773)   (0.550) 
                                                         
---------------------------------------------------------
Observations        1,462     2,788     1,352     2,694  
Log Likelihood    -103.195  -554.614  -105.010  -573.103 
Akaike Inf. Crit.  218.390  1,119.227  222.020  1,156.206
=========================================================
Note:                         *p<0.1; **p<0.05; ***p<0.01

Modell mit beiden Indices

logit_svp_joined <- glm(vote ~ index_galtan + index_econ + agea + edlvdch + hinctnta + gndr, data = df_ch_a, family = binomial("logit"), weights = anweight)
Warning in eval(family$initialize): Nicht-ganzzahlige #Erfolge in einem
binomial-GLM
logit_afd_joined <- glm(vote ~ index_galtan + index_econ + agea + hinctnta + gndr, data = df_de_a, family = binomial("logit"), weights = anweight)
Warning in eval(family$initialize): Nicht-ganzzahlige #Erfolge in einem
binomial-GLM
stargazer(logit_svp_joined, type = "text")

=============================================
                      Dependent variable:    
                  ---------------------------
                             vote            
---------------------------------------------
index_galtan               1.928***          
                            (0.298)          
                                             
index_econ                  0.483*           
                            (0.247)          
                                             
agea                        0.0004           
                            (0.005)          
                                             
edlvdch                     -0.0005          
                            (0.002)          
                                             
hinctnta                    -0.009           
                            (0.006)          
                                             
gndr                        -0.234           
                            (0.296)          
                                             
Constant                   -8.400***         
                            (1.134)          
                                             
---------------------------------------------
Observations                 1,323           
Log Likelihood              -86.377          
Akaike Inf. Crit.           186.754          
=============================================
Note:             *p<0.1; **p<0.05; ***p<0.01
stargazer(logit_afd_joined, type = "text")

=============================================
                      Dependent variable:    
                  ---------------------------
                             vote            
---------------------------------------------
index_galtan               1.409***          
                            (0.174)          
                                             
index_econ                  0.310**          
                            (0.151)          
                                             
agea                         0.001           
                            (0.005)          
                                             
hinctnta                   -0.014**          
                            (0.006)          
                                             
gndr                       -0.602***         
                            (0.193)          
                                             
Constant                   -7.732***         
                            (0.701)          
                                             
---------------------------------------------
Observations                 2,664           
Log Likelihood             -536.563          
Akaike Inf. Crit.          1,085.125         
=============================================
Note:             *p<0.1; **p<0.05; ***p<0.01

ESS11 Datenmanipulation

df_ess11_var <- df_ess11 %>% dplyr::select(agea, gndr, edlvdch, educde2, hinctnta, imueclt, atchctr, prtvthch, prtvgde2, imwbcnt, eqpolbg, wexashr, imptrada, ipstrgva, hmsacld, cntry, anweight)
df_ess11_1 <- df_ess11_var %>% rename(cultlife_undermined = imueclt, attch_cntry = atchctr, imm_cntry_bg = imwbcnt, genderinleadership = eqpolbg, exag_sex_harassment = wexashr, follow_traditions = imptrada, gov_ensuresafety = ipstrgva, hc_adoption = hmsacld)
df_ess11_2 <- df_ess11_1 %>%
  mutate(cultlife_undermined = case_match(cultlife_undermined,
                    77 ~ NA,
                    88 ~ NA,
                    99 ~ NA,
                    .default = cultlife_undermined))
df_ess11_2 <- df_ess11_2 %>%
  mutate(attch_cntry = case_match(attch_cntry,
                    77 ~ NA,
                    88 ~ NA,
                    99 ~ NA,
                    .default = attch_cntry))
df_ess11_2 <- df_ess11_2 %>%
  mutate(imm_cntry_bg = case_match(imm_cntry_bg,
                    77 ~ NA,
                    88 ~ NA,
                    99 ~ NA,
                    .default = imm_cntry_bg))
df_ess11_2 <- df_ess11_2 %>%
  mutate(genderinleadership = case_match(genderinleadership,
                    77 ~ NA,
                    88 ~ NA,
                    99 ~ NA,
                    .default = genderinleadership))
df_ess11_2 <- df_ess11_2 %>%
  mutate(exag_sex_harassment = case_match(exag_sex_harassment,
                    7 ~ NA,
                    8 ~ NA,
                    9 ~ NA,
                    .default = exag_sex_harassment))
df_ess11_2 <- df_ess11_2 %>%
  mutate(follow_traditions = case_match(follow_traditions,
                    66 ~ NA,
                    77 ~ NA,
                    88 ~ NA,
                    99 ~ NA,
                    .default = follow_traditions))
df_ess11_2 <- df_ess11_2 %>%
  mutate(hc_adoption = case_match(hc_adoption,
                    7 ~ NA,
                    8 ~ NA,
                    9 ~ NA,
                    .default = hc_adoption))
df_ess11_2 <- df_ess11_2 %>%
  mutate(gov_ensuresafety = case_match(gov_ensuresafety,
                    66 ~ NA,
                    77 ~ NA,
                    88 ~ NA,
                    99 ~ NA,
                    .default = gov_ensuresafety))

Vermerk: S. oben

df_ess11_2 <- df_ess11_2 %>% mutate(cultlife_undermined = 10 - cultlife_undermined)
df_ess11_2 <- df_ess11_2 %>% mutate(imm_cntry_bg = 10 - imm_cntry_bg)
df_ess11_2 <- df_ess11_2 %>% mutate(genderinleadership = 10 - genderinleadership)
df_ess11_2 <- df_ess11_2 %>% mutate(follow_traditions = 7 - follow_traditions)
df_ess11_2 <- df_ess11_2 %>% mutate(gov_ensuresafety = 7 - gov_ensuresafety)

Vermerk: S. oben

df_ess11_a <- df_ess11_2 %>% mutate(index_galtan = (((df_ess11_2$cultlife_undermined - mean(df_ess11_2$cultlife_undermined, na.rm = T)) / sd(df_ess11_2$cultlife_undermined, na.rm = T)) + ((df_ess11_2$imm_cntry_bg - mean(df_ess11_2$imm_cntry_bg, na.rm = T)) / sd(df_ess11_2$imm_cntry_bg, na.rm = T)) + ((df_ess11_2$genderinleadership - mean(df_ess11_2$genderinleadership, na.rm = T)) / sd(df_ess11_2$genderinleadership, na.rm = T)) + ((df_ess11_2$attch_cntry - mean(df_ess11_2$attch_cntry, na.rm = T)) / sd(df_ess11_2$attch_cntry, na.rm = T)) + ((df_ess11_2$exag_sex_harassment - mean(df_ess11_2$exag_sex_harassment, na.rm = T)) / sd(df_ess11_2$exag_sex_harassment, na.rm = T)) + ((df_ess11_2$follow_traditions - mean(df_ess11_2$follow_traditions, na.rm = T)) / sd(df_ess11_2$follow_traditions, na.rm = T)) + ((df_ess11_2$gov_ensuresafety - mean(df_ess11_2$gov_ensuresafety, na.rm = T)) / sd(df_ess11_2$gov_ensuresafety, na.rm = T)) + ((df_ess11_2$hc_adoption - mean(df_ess11_2$hc_adoption, na.rm = T)) / sd(df_ess11_2$hc_adoption, na.rm = T))) / 8)

df_ess11_a <- df_ess11_a %>% mutate(index_galtan = index_galtan + 2.2)

Vermerk: S. oben

cfa_3 <- "F3 =~ cultlife_undermined + imm_cntry_bg + genderinleadership + attch_cntry + exag_sex_harassment + follow_traditions + gov_ensuresafety + hc_adoption"
cfa_11 <- lavaan::cfa(cfa_3, data = df_ess11_a)
summary(cfa_11)
lavaan 0.6-20 ended normally after 41 iterations

  Estimator                                         ML
  Optimization method                           NLMINB
  Number of model parameters                        16

                                                  Used       Total
  Number of observations                         40289       50116

Model Test User Model:
                                                       
  Test statistic                              11348.042
  Degrees of freedom                                 20
  P-value (Chi-square)                            0.000

Parameter Estimates:

  Standard errors                             Standard
  Information                                 Expected
  Information saturated (h1) model          Structured

Latent Variables:
                   Estimate  Std.Err  z-value  P(>|z|)
  F3 =~                                               
    cultlif_ndrmnd    1.000                           
    imm_cntry_bg      0.841    0.007  120.469    0.000
    genderinldrshp    0.165    0.003   49.640    0.000
    attch_cntry       0.039    0.005    7.891    0.000
    exg_sx_hrssmnt    0.071    0.002   34.949    0.000
    follow_tradtns    0.117    0.003   37.915    0.000
    gov_ensuresfty    0.074    0.003   27.899    0.000
    hc_adoption       0.247    0.003   74.354    0.000

Variances:
                   Estimate  Std.Err  z-value  P(>|z|)
   .cultlif_ndrmnd    1.380    0.042   32.805    0.000
   .imm_cntry_bg      2.050    0.032   63.229    0.000
   .genderinldrshp    2.006    0.014  140.175    0.000
   .attch_cntry       4.853    0.034  141.892    0.000
   .exg_sx_hrssmnt    0.771    0.005  141.109    0.000
   .follow_tradtns    1.784    0.013  140.954    0.000
   .gov_ensuresfty    1.327    0.009  141.418    0.000
   .hc_adoption       1.779    0.013  137.307    0.000
    F3                5.623    0.063   88.754    0.000
df_ess11_ch <- df_ess11_a %>% filter(cntry == "CH")
df_ess11_de <- df_ess11_a %>% filter(cntry == "DE")

df_ess11_ch <- df_ess11_ch %>% mutate(vote = prtvthch)
df_ess11_de <- df_ess11_de %>% mutate(vote = prtvgde2)

df_ess11_ch <- df_ess11_ch %>% mutate(vote = case_match(vote, 1 ~ 1,
                                                .default = 0))
df_ess11_de <- df_ess11_de %>% mutate(vote = case_match(vote, 6 ~ 1,
                                                .default = 0))

Vermerk: S. oben

Modellierung ESS11

Modell zu gesellschaftspolitischer Position

logit_svp_11 <- glm(vote ~ index_galtan + agea + edlvdch + hinctnta + gndr, data = df_ess11_ch, family = binomial("logit"), weights = anweight)
Warning in eval(family$initialize): Nicht-ganzzahlige #Erfolge in einem
binomial-GLM
logit_afd_11 <- glm(vote ~ index_galtan + agea + educde2 + hinctnta + gndr, data = df_ess11_de, family = binomial("logit"), weights = anweight)
Warning in eval(family$initialize): Nicht-ganzzahlige #Erfolge in einem
binomial-GLM
screenreg(logit_afd_11)

===========================
                Model 1    
---------------------------
(Intercept)       -8.55 ***
                  (0.48)   
index_galtan       2.77 ***
                  (0.16)   
agea              -0.01 ***
                  (0.00)   
educde2           -0.00    
                  (0.00)   
hinctnta          -0.04 ***
                  (0.01)   
gndr               0.02    
                  (0.14)   
---------------------------
AIC             1715.82    
BIC             1749.83    
Log Likelihood  -851.91    
Deviance        1704.48    
Num. obs.       2140       
===========================
*** p < 0.001; ** p < 0.01; * p < 0.05

Visualisierung

set.seed(123)
preds_svp_11 <- predicts(logit_svp_11, "0-4, 0.5; median; mode; median; mode", type = "simulation")

preds_svp_11 %>% ggplot(aes(x = index_galtan, y = mean, ymin = lower, ymax = upper)) +
  geom_ribbon(alpha = 0.3, fill = "#00cc00" ) +
  geom_line(color = "forestgreen", linewidth = 1.2) + 
  ylab("Wahlwahrscheinlichkeit SVP") +
  xlab("Index zu gesellschaftspolitischer Position") + 
  scale_y_continuous(labels = scales::percent) +
  theme_minimal() +
  labs(title = "Wahlwahrscheinlichkeit der SVP nach gesellschaftspolitischer Position")

set.seed(123)
preds_afd_11 <- predicts(logit_afd_11, "0-4, 0.5; median; mode; median; mode", type = "simulation")

preds_afd_11 %>% ggplot(aes(x = index_galtan, y = mean, ymin = lower, ymax = upper)) +
  geom_ribbon(alpha = 0.3, fill = "steelblue") +
  geom_line(color = "blue", linewidth = 1.2) + 
  ylab("Wahlwahrscheinlichkeit AfD") +
  xlab("Index zu gesellschaftspolitischer Position") + 
  scale_y_continuous(labels = scales::percent) +
  theme_minimal() + 
  labs(title = "Wahlwahrscheinlichkeit der AfD nach gesellschaftspolitischer Position")

Modellgüte und t-Test

t.test(df_ess11_ch$index_galtan[df_ess11_ch$vote == 1], df_ess11_de$index_galtan[df_ess11_de$vote == 1])

    Welch Two Sample t-test

data:  df_ess11_ch$index_galtan[df_ess11_ch$vote == 1] and df_ess11_de$index_galtan[df_ess11_de$vote == 1]
t = -1.5864, df = 139.23, p-value = 0.1149
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.21096271  0.02313203
sample estimates:
mean of x mean of y 
 2.434670  2.528585 
set.seed(123)
pred_out_ch_11 <- predict(logit_svp_11, type = "response")
pred_out_de_11 <- predict(logit_afd_11, type = "response")

library(pROC)
pROC::auc(logit_svp_11$model$vote, pred_out_ch_11)
Setting levels: control = 0, case = 1
Setting direction: controls < cases
Area under the curve: 0.7926
pROC::auc(logit_afd_11$model$vote, pred_out_de_11)
Setting levels: control = 0, case = 1
Setting direction: controls < cases
Area under the curve: 0.793
performance::r2_mcfadden(logit_svp_11)
Warning in eval(family$initialize): Nicht-ganzzahlige #Erfolge in einem
binomial-GLM
# R2 for Generalized Linear Regression
       R2: 0.262
  adj. R2: 0.258
performance::r2_mcfadden(logit_afd_11)
Warning in eval(family$initialize): Nicht-ganzzahlige #Erfolge in einem
binomial-GLM
# R2 for Generalized Linear Regression
       R2: 0.299
  adj. R2: 0.298
pred_out_11_ch.01 <- as.numeric(cut(pred_out_ch_11, breaks = c(-Inf, 0.5, Inf), labels = c(0,1)))
pred_out_11_de.01 <- as.numeric(cut(pred_out_de_11, breaks = c(-Inf, 0.5, Inf), labels = c(0,1)))

conf_mat_ch_11 <- table(logit_svp_11$model$vote, pred_out_11_ch.01)
conf_mat_de_11 <- table(logit_afd_11$model$vote, pred_out_11_de.01)
stargazer(list(logit_svp_11, logit_afd_11, logit_svp_econ, logit_afd_econ), type = "text", covariate.labels = c("Index gesellschaftspolitische Position", "Index verteilungspolitische Position"), column.labels = c("ESS11 für SVP", "ESS11 für AfD", "ESS8 für SVP", "ESS8 für AfD"), dep.var.labels = "Wahl SVP/AfD", header = F, float = F)

============================================================================================
                                                        Dependent variable:                 
                                       -----------------------------------------------------
                                                           Wahl SVP/AfD                     
                                       ESS11 für SVP ESS11 für AfD ESS8 für SVP ESS8 für AfD
                                            (1)           (2)          (3)          (4)     
--------------------------------------------------------------------------------------------
Index gesellschaftspolitische Position   2.509***      2.775***                             
                                          (0.373)       (0.164)                             
                                                                                            
Index verteilungspolitische Position                                 0.947***     0.596***  
                                                                     (0.221)      (0.152)   
                                                                                            
agea                                      0.004*       -0.015***      0.003        0.006    
                                          (0.002)       (0.004)      (0.004)      (0.005)   
                                                                                            
edlvdch                                   0.0001                      -0.001                
                                         (0.0002)                    (0.005)                
                                                                                            
educde2                                                -0.00003                             
                                                       (0.0001)                             
                                                                                            
hinctnta                                  -0.006       -0.040***      -0.005      -0.014**  
                                          (0.006)       (0.010)      (0.005)      (0.006)   
                                                                                            
gndr                                      -0.252         0.016        -0.325     -0.624***  
                                          (0.283)       (0.138)      (0.277)      (0.191)   
                                                                                            
Constant                                 -7.523***     -8.548***    -4.312***    -4.825***  
                                          (0.987)       (0.475)      (0.773)      (0.550)   
                                                                                            
--------------------------------------------------------------------------------------------
Observations                               1,187         2,140        1,352        2,694    
Log Likelihood                           -188.774      -851.910      -105.010     -573.103  
Akaike Inf. Crit.                         389.548      1,715.820     222.020     1,156.206  
============================================================================================
Note:                                                            *p<0.1; **p<0.05; ***p<0.01

Allgemeine Bemerkungen

Ein allgemeines Problem ist die enorme Unterrepräsentation der SVP-/AfD- Wähler:innen, welche gegebenenfalls die Analyse verzerrt: So haben von 2420 deutschen Proband:innen nur 88 im Datensatz (ESS11) angegeben die AfD gewählt zu haben, was nicht dem realen Wahlanteil entspricht. Dies könnte möglicherweise die tiefe proportionale Fehlerreduktion erklären: Das naive Modell hat bereits eine sehr hohe Trefferquote. Die geringe Fallzahl erschwert zudem die Schätzung der Koeffizienten und die vorhergesagten Wahrscheinlichkeiten werden unterschätzt.

Die Faktorladungen der Variablen innerhalb eines Index wurden überprüft. Das Ziel der Aggregation war nicht die Identifizierung eines einzelnen latenten Faktors, sondern die Erfassung der verschiedenen Facetten der jeweiligen Dimension. Die Faktoren sind alle in die jeweils selbe Richtung - auch wenn teilweise schwach - korreliert.

Die Störvariable “Bildung” wurde für Deutschland in der Analyse des ESS8 Datensatzes nicht kontrolliert, da diese Variable innerhalb des Datensatzes in mehrere Variablen aufgefächert ist und die Aggregation dieser in eine einzelne, den Rahmen dieses Projektes überschritten hätte.

KI-Statement

Die Autor:innen deklarieren, dass generative KI (z. B. ChatGPT) unterstützend genutzt wurde. Der Output der KI wurde beispielsweise verwendet, um sich einen Überblick über das Thema zu verschaffen oder, um bei der Formatierung respektive Visualisierung zu unterstützen. GitHub CoPilot wurde nicht genutzt. Alle Inhalte sind allein durch die Autor:innen erstellt; sie tragen die Verantwortung bezüglich Korrektheit des Inhalts.