Übung: Parteien im Links-Rechts-Spektrum

Autor:in

Sebastian Knoll

Veröffentlichungsdatum

19. Februar 2024

Bitte tragen Sie hier Ihre Lösungen ein - bei Aufgaben, bei denen kein R Code gefordert ist, nach Absolvierung einfach “OK”. ##Vorbereitungen

Laden Sie hier den Datensatz herunter

Download ESS Datensatz

Installation und Laden der notwendigen Pakete

Installieren/Laden Sie die hier benötigten Pakete (Tipp: Nach der Installation eines Pakets mit install.packages() kommentieren Sie diese Zeile am besten aus, da sonst bei jedem Rendering Durchlauf das jeweilige Paket neu installiert wird) #1) “OK” #2) “OK” #3) “OK” #4)

Code
library(tidyverse)
library(sjmisc)
library(sjPlot)
library(gtsummary)
library(patchwork)
library(quarto) 

#5) Datenaufbereitung

Laden der Daten in RStudio (Anpassen des Pfades erforderlich)

Laden Sie die Daten mit haven::read_sav() und speichern Sie diese als Objekt ESS.

Code
ESS <- haven::read_spss("~/Desktop/SozioR/_data/ESS10/ESS10SC.sav")

#6) Daten nach Österreich filtern

Filtern Sie die Fälle so, dass nur die österreichischen Fälle verbleiben (s. Variable cntry) und speichern Sie das Ergebnis als Objekt ess ab.

Code
ess <- ESS |> filter(cntry == "AT")

#7) Häufigkeitsauszählung

Erzeugen Sie mit sjmisc::frq() Häufigkeitsauszählungen der drei Variablen agea, lrscale, prtvtcat.

Code
ess |> select(agea, lrscale, prtvtcat) |> sjmisc::frq()

#8) lrscale

Kopieren Sie die lrscale mit der subjektiven Positionierung im politischen Links-Rechts-Spektrum in eine neue Variable lrscale_r und labeln Sie diese neue Variable mittels labelled::set_variable_labels() mit Positionierung im Links-Rechts-Spektrum und die beiden extremen Ausprägungen (Pole) 0 und 10 mittels labelled::set_value_labels() mit Links und Rechts. Prüfen Sie das Ergebnis mit einer Häufigkeitsauszählung mit sjmisc::frq() mit der ursprünglichen und der neu erzeugten Variable.

Code
ess <- ess |> 
  mutate(lrscale_r = lrscale) |> 
  labelled::set_variable_labels(lrscale_r = "Positionierung im Links-Rechts-Spektrum") |> 
  labelled::set_value_labels(lrscale_r = c("Links" = 0, "Rechts" = 10))
ess |> select(lrscale_r) |> sjmisc::frq()

#9) agea

Rekodieren Sie die Altersvariable agea in eine neue Variable agea_r mit den Alterskategorien bis 29 J, 30 bis 49 J, 50 bis 69 J, ab 70 J. Labeln Sie die neue Variable in der Pipe auch gleich mittels labelled::set_variable_labels() (“Alter (kat.)”) und die Ausprägungen mittels set_value_labels() entsprechend der obigen Alterskategorien (“bis 29 J”, etc.). Um zu überprüfen, ob die Rekodierung korrekt funktioniert hat, erstellen Sie bitte eine Häufigkeitsauszählung beider Variablen (mit sjmisc::frq()) und kreuztabulieren Sie die neue mit der ursprünglichen Variable - am besten mit der ursprünglichen Variable in der Zeile und der neuen Variable in der Spalte (mit gtsummary::tbl_cross()). So erkennen wir schnell, ob z.B. Ausprägungen nicht berücksichtigt wurden etc.

Code
ess <- ess |> mutate(agea_r = case_match(agea, 
                                          0:29 ~ 1,
                                          30:49 ~ 2,
                                          50:69 ~ 3,
                                          70:120 ~ 4,
                                          999 ~ NA, 
                                          .default = NA)) |> 
  labelled::set_variable_labels(agea_r = "Alter (kat.)") |> 
  labelled::set_value_labels(agea_r = c("bis 29 J" = 1,
                                        "30 bis 49 J" = 2,
                                        "50 bis 69 J" = 3,
                                        "ab 70 J" = 4,
                                        .default = NA))

ess |> select(agea_r,agea) |> sjmisc::frq()
ess |> select(agea, agea_r) |> gtsummary::tbl_cross()

#10) prtvtcat

Rekodieren Sie die Variable mit der zuletzt (bei der letzten bundesweiten Wahl) gewählten Partei (prtvtcat) in eine neue Variable prtvtcat_r so, dass die Codes für fehlende Werte (66, 77, 88, 99) auf NA gesetzt werden, alle Parteien unter 1% Stimmenanteil der Kategorie Other hinzugefügt werden, und sonst alle Parteien den Code behalten (Anm.: Beurteilen Sie dies anhand der Häufigkeitsauszählung und rekodieren Sie entsprechend). Labeln Sie die neue Variable Gewählte Partei und benennen Sie die die Kategorie “Other” mithilfe von labelled::add_value_labels() (s. https://cran.r-project.org/web/packages/labelled/vignettes/intro_labelled.html) in “Andere” um. Prüfen Sie wiederum mittels Häufigkeitstabelle und Kreuztabelle, ob die Rekodierung geklappt hat.

Code
ess <- ess |>
  mutate(prtvtcat_r = prtvtcat |>
           case_match(c(4,6,8,9)~ 9,
                      c(66,77,88,99)~ NA,
                      .default = prtvtcat)) |>
  labelled::set_variable_labels(prtvtcat_r= "Gewählte Partei") |>
  labelled::add_value_labels(prtvtcat_r = c (Andere = 9))

ess |> select(prtvtcat, prtvtcat_r) |> sjmisc::frq ()
ess |> select(prtvtcat, prtvtcat_r) |> gtsummary :: tbl_cross()

#11) Löschen der nicht benötigten Labels und Umwandlung zu einer Faktorvariable

Ihnen ist beim vorigen Punkt vielleicht aufgefallen, dass a) bei der Häufigkeitsauszählung mit sjmisc::frq() die Labels trotz der Umkodierung der Codes für fehlende Werte noch immer sichtbar waren und dass b) die Kreuztabelle (mit gtsummary::tbl_cross()) keine Labels, sondern nur die Zahlenwerte anzeigt. Der Grund für a) ist, dass die Labels nicht verschwinden, wenn die Beobachtungen in eine andere Kategorie codiert werden, sondern auch wenn diese unbesetzt sind, weiter bestehen – wir sollten die Labels noch löschen, damit nicht der Eindruck erweckt wird, dass die Fallzahlen in diesen Kategorien tatsächlich 0 sind. Der Grund für b) ist, dass gtsummary::tbl_cross() (und viele andere Funktionen) die numerischen gelabelten Variablen als numerische Variablen behandeln (also als Variablen, mit denen gerechnet werden kann und bei denen Berechnungen des Mittelwerts, der Standardaweichung etc. Sinn machen), und nicht eine kategoriale Variable – wir sollten die gelabelten Variablen, die wir als kategoriale Variablen betrachten in Faktorvariablen (factor ist in R der Datentyp für kategoriale Variablen, s. https://r4ds.hadley.nz/factors.html) umwandeln.

Code
#a) Löschen der Labels für leere Kategorien
ess <- ess |> labelled::remove_value_labels(prtvtcat_r = c(4,6,8,66:99))
ess |> select(prtvtcat_r) |> sjmisc::frq ()

#b) Häufigkeitstabelle für die neue Variable ohne Labels
ess <- ess |> mutate(prtvtcat_r = prtvtcat_r |> labelled::to_factor())
ess |> select(prtvtcat_r) |> sjmisc::frq ()
ess |> select(prtvtcat, prtvtcat_r) |> gtsummary :: tbl_cross()

#beide variablen als Kreuztablle 
ess |> select(prtvtcat, prtvtcat_r) |> labelled::to_factor() |> gtsummary :: tbl_cross()

#12) Faktorvariable Alter

Wandeln Sie nun auch die zuvor gebildete Altersvariable agea_r mit labelled::to_factor() in eine Faktorvariable um.

Code
ess <- ess |> mutate(agea_r = agea_r |> labelled::to_factor())

#13) Übersichtstabellen und -grafiken

Übersicht über die neu rekodierten Variablen

Erzeugen Sie eine Übersichtstabelle der hier verwendeten Variablen agea_r, lrscale_r, prtvtcat_r mit gtsummary::tbl_summary(). Beachten Sie die erscheinende Anmerkung (ℹ Column(s) lrscale and prtvtcat_r are class “haven_labelled”.) und fügen Sie in die Pipe noch die Funktion labelled::to_factor() ein, die die gelabelten numerischen Variablen in Faktorvariablen umwandelt.

Code
ess |> select(agea_r,lrscale_r, prtvtcat_r) |> labelled::to_factor() |> gtsummary::tbl_summary()

#14) Säulendiagramm der drei Varibalen

Bitte erzeugen Sie mittels sjPlot::plot_frq() und sonst möglichst wenig Schreibarbeit die Balken- genauer: Säulendiagramme für die drei Variablen.

Code
ess |> select(agea_r,lrscale_r, prtvtcat_r) |> sjPlot::plot_frq()

Code
#Grafiken zusammenfügen

plot1 <- ess |> select(agea_r) |> sjPlot::plot_frq()
plot2 <- ess |> select(prtvtcat_r) |> sjPlot::plot_frq()
plot3 <- ess |> select(lrscale_r) |> sjPlot::plot_frq()

library(patchwork)
(plot1 + plot2)/plot3

#15) Grafische Analyse

Box-Plot 1

Erzeugen Sie mit {ggplot} folgende Grafik mit geom_boxplot(). Stellen Sie lrscale_r auf der x-Achse und prtvtcat_r auf der y-Achse dar und verwenden Sie zur Darstellung geom_boxplot()

Code
ess |> ggplot(aes(x = lrscale_r, y = prtvtcat_r)) + geom_boxplot()

#16) Box-Plot 2

Grafiken mit ggplot2 lassen sich schichtweise aufbauen: Ersetzen Sie den Layer geom_boxplot() mit geom_violin() und setzen Sie einen Layer mit geom_boxplot(width = 0.05) darüber (Anm. width legt fest, dass der Boxplot nur sehr schmal (1/20 der maximalen Breite) dargestellt werden soll), sodass Sie folgenden Plot erhalten:

Code
ess |> ggplot(aes(x = lrscale_r, y = prtvtcat_r)) +geom_violin() + geom_boxplot(width = 0.05)

#17) Interpretation von bestehenden Code mittels

Wir können diesen Plot noch weiter bearbeiten. Bitte gehen Sie die folgenden Zeilen durch, finden Sie heraus, was dort geschieht und kommentieren Sie ganz kurz.

Code
plot1 <- ess |> 
  drop_na(agea_r, lrscale_r, prtvtcat_r) |> # löscht alle fehlende Werte (Nas) für die genannten Variablen  
  ggplot(aes(x = lrscale_r, y = prtvtcat_r, fill = prtvtcat_r)) + #ggplot wie oben + füllfarbe ist abhängig von gewählter Partei
  geom_jitter(height = .25, alpha = .25) + # Einzelne Datenpunkte werden verzittert dargestellt, damit Überlappung von Datenpunkten vermieden werden, alpha=Deckkarft, heigt= Streubreite 25%,
  geom_violin(alpha = .5) + # violinplot mit geringerer Deckkarft 5%
  geom_boxplot(width = 0.05, color = "white", outlier.alpha = 0) + # boxplot, sehr schmal, weiß und Ausreißer werden nicht dargestellt
    #Parteien werden nach Parteifarbe eingefärbt: Mit scale_fill_manual werden manuell die Parteifarben vergeben. 
  scale_fill_manual(values = c(rgb(255,0,0, maxColorValue = 255), #red
                               rgb(99,195,208, maxColorValue = 255), #turquoise"
                               rgb(0,102,255, maxColorValue = 255), #blue
                               rgb(146,208,80, maxColorValue = 255), #"green"
                               rgb(232,65,136, maxColorValue = 255), #"deeppink",
                               "grey")) +  # Farben s. https://www.data.gv.at/katalog/dataset/3179c5b2-9bb5-4a7f-a573-5491ccb0110b/resource/50753a22-ca46-4345-8c5e-f458362702c6/download/farbzuteilungn1710.pdf   

  scale_x_continuous(breaks = 0:10, labels = c("Links", 1:9, "Rechts")) + #Werte des LR-Spektrum auf der x-Achse sollen ohne Kommastellen angezeigt werden, stattdessesn 0=Links, 1 bis 9 in ganze Zahlen, 10=Rechts.
  scale_y_discrete(limits = rev) + #kategoriale Variablen: Labels (Parteienanordnung) auf der  Achse sollen umgedreht werden
  labs(title = "Selbsteinordnung im Links-Rechts-Spektrum nach zuletzt gewählter Partei",
       caption = "Daten: European Social Survey Welle 10 (Erhebungszeitraum 30.08.2021 - 06.12.2021)", #Beschriftung und Datenquelle
       x = "",
       y = "") + 
  theme_minimal() + #ggplot theme "theme_minimal" ohne grauen hintergrund
  theme(plot.title.position = "plot", #customizing des ggplot theme "theme_minimal", Überschrift auf Plot-Ebene
        legend.position = "none", 
        panel.grid.minor = element_blank()) #grids nur bei breaks 0:10

plot1

#18) Grafische Darstellung nach Alter

Uns interessiert, ob die Selbsteinordnung innerhalb der Parteien mit dem Alter variiert, also ob sich die Links-Rechts-Einordnung unter den SPÖ Wähler:innen zwischen den Altersgruppen unterscheidet. Mit {ggplot2} können wir sehr einfach sog. “small multiples” erzeugen, also den selben Plot für unterschiedliche Gruppen (s. https://ggplot2-book.org/facet.html). Bitte kopieren Sie den Code für den vorherigen Plot und fügen Sie eine Zeile mit facet_wrap() hinzu, mit der Sie die Grafik nach Altersgruppe facettieren, sodass Sie folgenden Plot erhalten:

Code
plot2 <- ess |> 
  drop_na(agea_r, lrscale_r, prtvtcat_r) |> 
  ggplot(aes(x = lrscale_r, y = agea_r, fill = prtvtcat_r)) + 
  geom_jitter(height = .25, alpha = .25) + 
  geom_violin(alpha = .5) + 
  geom_boxplot(width = 0.05, color = "white", outlier.alpha = 0) +  
  scale_fill_manual(values = c(rgb(255,0,0, maxColorValue = 255), 
                               rgb(99,195,208, maxColorValue = 255), 
                               rgb(0,102,255, maxColorValue = 255), 
                               rgb(146,208,80, maxColorValue = 255), 
                               rgb(232,65,136, maxColorValue = 255), 
                               "grey")) +  

  scale_x_continuous(breaks = 0:10, labels = c("Links", 1:9, "Rechts")) + 
  scale_y_discrete(limits = rev) + 
  labs(title = "Selbsteinordnung im Links-Rechts-Spektrum nach zuletzt gewählter Partei",
       caption = "Daten: European Social Survey Welle 10 (Erhebungszeitraum 30.08.2021 - 06.12.2021)", 
       x = "",
       y = "") + 
  theme_minimal() + 
  theme(plot.title.position = "plot", 
        legend.position = "none", 
        panel.grid.minor = element_blank()) + 
        facet_wrap(~prtvtcat_r)

plot2

#19) Speichern der beiden Grafiken

Bitte speichern Sie die beiden letzten Grafiken mit ggsave() ab, als “selbsteinordnung_lr_01.png” bzw. “selbsteinordnung_lr_02.png”, beide im A4 Querformat (also Breite = 297, Höhe = 210mm), mit einer Auflösung von 300dpi (dots per inch) und weißem Hintergrund (Tipp: Option bg = …). Öffnen Sie die Dateien und prüfen Sie, ob die Speicherung korrekt funktioniert hat.

Code
ggsave(plot = plot1, filename = "selbsteinordnung_lr_01.png", width = 297, height = 210 , dpi = 300, units = "mm", bg= "white")

ggsave(plot = plot2, filename = "selbsteinordnung_lr_02.png", width = 297, height = 210 , dpi = 300, units = "mm", bg= "white")

#20) Modellierung

Lineares Modell

Abschließend berechnen wir noch ein lineares Modelle mit der Links-Rechts-Einstufung als abhängiger Variable und der Partei und dem Alter als erklärender Variable, also einen Mittelwertsvergleich zwischen den Selbsteinstufungen nach Partei unter Kontrolle des Alterseffekts. Verwenden Sie dazu die Funktion lm() und geben Sie das Modell als Formel ein (s.a. https://r4ds.had.co.nz/model-basics.html). Speichern Sie das Modell als Objekt mod1 ab und erzeugen Sie mit summary() eine Modellzusammenfassung:

Code
mod1 <- lm(lrscale_r ~ agea_r + prtvtcat_r, data = ess)
mod1
summary(mod1)

#21) Tabellarische und grafische Darstellung des Models

In R stehen viele unterschiedliche Funktionen zur Verfügung, mit denen Modelle tabellarisch und grafisch dargestellt werden können, z.B. sjPlot::tab_model() und sjPlot::plot_model(), sowie gtsummary::tbl_regression(). Erzeugen Sie auf diese Weise folgende zwei übersichtliche Koeffiziententabelle mit sjPlot::tab_model() und gtsummary::tbl_regression():

Code
mod1 |> sjPlot::tab_model()
  Positionierung im
Links-Rechts-Spektrum
Predictors Estimates CI p
(Intercept) 3.27 2.93 – 3.61 <0.001
Alter (kat.): 30 bis 49 J -0.03 -0.35 – 0.30 0.861
Alter (kat.): 50 bis 69 J 0.28 -0.03 – 0.60 0.079
Alter (kat.): ab 70 J 0.58 0.21 – 0.96 0.003
Gewählte Partei: ÖVP 1.91 1.64 – 2.18 <0.001
Gewählte Partei: FPÖ 2.68 2.28 – 3.09 <0.001
Gewählte Partei: Grüne -0.50 -0.82 – -0.19 0.002
Gewählte Partei: NEOS 1.04 0.62 – 1.46 <0.001
Gewählte Partei: Andere 1.15 0.67 – 1.62 <0.001
Observations 1369
R2 / R2 adjusted 0.276 / 0.271
Code
mod1 |> gtsummary::tbl_regression() |> gtsummary::add_glance_source_note(include = c(nobs, r.squared, adj.r.squared, sigma))
Characteristic Beta 95% CI1 p-value
Alter (kat.)


    bis 29 J
    30 bis 49 J -0.03 -0.35, 0.30 0.9
    50 bis 69 J 0.28 -0.03, 0.60 0.079
    ab 70 J 0.58 0.21, 0.96 0.003
Gewählte Partei


    SPÖ
    ÖVP 1.9 1.6, 2.2 <0.001
    FPÖ 2.7 2.3, 3.1 <0.001
    Grüne -0.50 -0.82, -0.19 0.002
    NEOS 1.0 0.62, 1.5 <0.001
    Andere 1.1 0.67, 1.6 <0.001
No. Obs. = 1,369; R² = 0.276; Adjusted R² = 0.271; Sigma = 1.85
1 CI = Confidence Interval