invisible header

link zum pdf

Diese Einheit vermittelt die Konstruktion und Auswertung von Kreuztabellen sowie die balkendiagrammgestützte Visualisierung bivariater Zusammenhänge. Diese statistischen Techniken kommen dann zum Einsatz, wenn bivariate Zusammenhänge kategorialer Variablen untersucht werden. Wir arbeiten wieder mit den Befragungsdaten (kursdata_anon) aus dem Kurs.

# Statistik 1: R Tutorat
# Übungsskript zur Tabellenanalyse
# Datum: 06.12.2024
# AutorIn: XXX

 

1 Vorbereitungen und Dateninspektion

# Working directory setzen (z.B. "c:\daten")
setwd("mein_laufwerk/mein_datenverzeichnis")
# Daten einlesen
library(haven)
kursdata_anon <- read_dta("kursdata_anon.dta")
#install.packages("tidyverse")
library(tidyverse)
# install.packages("sjPlot")
library(sjPlot)
#install.packages("ggplot2")
library(ggplot2)

Die Kreuztabellenanalyse ist dann sinnvoll, wenn zwei kategorial ausgeprägte Variablen illustriert oder analysiert werden sollen. In unserem Fall sind wir am Zusammenhang der Variablen geschlecht und rauchen_aktuell interessiert. Wir vermuten, dass unter Frauen der Anteil Rauchender grösser ist als unter Männern (H1, einseitige Hypothese).

Wir inspizieren zunächst beide Variablen und nehmen ggf. Bereinigungen vor.

# Eigenschaften der relevanten Variablen
attributes(kursdata_anon$geschlecht)
table(kursdata_anon$geschlecht)
class(kursdata_anon$geschlecht)

attributes(kursdata_anon$rauchen_aktuell)
table(kursdata_anon$rauchen_aktuell)
class(kursdata_anon$rauchen_aktuell)

# Bereinigung der "Rauchen" - Variable wegen falsch codiertem Missing
kursdata_anon$rauchen_aktuell[kursdata_anon$rauchen_aktuell==-99]<-NA
table(kursdata_anon$rauchen_aktuell)

Wir analysieren kategoriale Variablen und wenden dementsprechend Analyseverfahren für kategoriale Variablen an. In der Regel funktionieren diese am besten mit Faktorvariablen. Da die Variablen im Datensatz nicht als solche angelegt sind, faktorisieren wir sie.

kursdata_anon$geschlecht <- as_factor(kursdata_anon$geschlecht)
kursdata_anon$rauchen_aktuell <- as_factor(kursdata_anon$rauchen_aktuell)

Achtung: Gelegentlich werden bei Faktorisierungen latente, nicht verwendete Wertelabel als Kategorien angelegt. Dies ist auch hier, bei der Variable zum Rauchverhalten, der Fall:

table(kursdata_anon$geschlecht)
## 
##  weiblich maennlich 
##        46         8
table(kursdata_anon$rauchen_aktuell)
## 
## Keine Angabe         nein           ja 
##            0           37           16

Um die Phantomkategorie “keine Angabe” nicht weiter in die folgenden statistischen Darstellungen zu tragen, nutzen wir als einfachen Bereinigungsmechanismus den forecats::fct_drop()-Befehl

kursdata_anon$rauchen_aktuell<-fct_drop(kursdata_anon$rauchen_aktuell) 
table(kursdata_anon$rauchen_aktuell)
## 
## nein   ja 
##   37   16

 

2 Kreuztabelle mit sjPlot

Über den tab_xtab() Befehl aus dem sjPlot Package können wir die beiden Variablen kreuztabellarisch darstellen (ctable aus dem summarytools Package wäre ggf. noch eine gute Alternative). Variationen innerhalb der Teilbefehle show.col.prc = TRUE / show.row.prc = TRUE erzeugen die Integration von Spalten- und/oder Zeilenprozenten. Die Hypothese wie oben formuliert setzt die Variablen zwar nicht in einen klaren Kausalbezug, logisch ist aber nur ein Einfluss des Geschlechts denkbar. Wir lassen dieses Merkmal daher die Spalten definieren und weisen Spaltenprozente aus.

tab_xtab(var.row = kursdata_anon$rauchen_aktuell, 
         var.col = kursdata_anon$geschlecht,
         show.col.prc = TRUE,
         show.obs = TRUE)
letzte Woche
geraucht?
geschlecht Total
weiblich maennlich
nein 33
73.3 %
4
50 %
37
69.8 %
ja 12
26.7 %
4
50 %
16
30.2 %
Total 45
100 %
8
100 %
53
100 %
χ2=0.822 · df=1 · φ=0.182 · Fisher’s p=0.224

Über weitere Modifikationen des tab_xtab() Befehls - etwa durch title = ““ oder var.labels = c(““) - lässt sich der Tabellenoutput noch weiter formatieren, bevor wir den (im Viewer der R-Studio Konsole angezeigten) Output per Copy-Paste in ein Text- oder Grafikverarbeitungsprogramm exportieren und dort finalisieren.

tab_xtab(var.row = kursdata_anon$rauchen_aktuell, var.col = kursdata_anon$geschlecht,
         title = "Kreuztabelle: Rauchstatus nach Geschlecht",
         show.col.prc = TRUE,
         show.obs = TRUE)
Kreuztabelle: Rauchstatus nach Geschlecht
letzte Woche
geraucht?
geschlecht Total
weiblich maennlich
nein 33
73.3 %
4
50 %
37
69.8 %
ja 12
26.7 %
4
50 %
16
30.2 %
Total 45
100 %
8
100 %
53
100 %
χ2=0.822 · df=1 · φ=0.182 · Fisher’s p=0.224

Unter Männern ist der Anteil aktuell Rauchender 23.4 Prozentpunkte grösser als unter Frauen. Dieser Vergleich der Anteilswerte der AV zwischen den Kategorien der UV, die Prozentsatzdifferenz, gilt als wichtiger statistischer Kennwert der Tabellenanalyse, weil er sich als direkte Folge eines Unterschiedes in der UV, und somit als Ausdruck der Effektgrösse, deuten lässt.

Alternativ lässt sich, durch das Argument show.row.prc = TRUE, die Kreuztabelle auch mit Zeilen- statt Spaltenprozenten darstellen - obgleich dies in einer Tabellenkonstellation, in der die Spalten durch die unabhängige Variable definiert werden, statistische Darstellungsstandards verletzt.

tab_xtab(var.row = kursdata_anon$rauchen_aktuell, var.col = kursdata_anon$geschlecht,
         title = "Kreuztabelle: Rauchstatus nach Geschlecht",
         show.row.prc = TRUE,
         show.obs = TRUE)
Kreuztabelle: Rauchstatus nach Geschlecht
letzte Woche
geraucht?
geschlecht Total
weiblich maennlich
nein 33
89.2 %
4
10.8 %
37
100 %
ja 12
75 %
4
25 %
16
100 %
Total 45
84.9 %
8
15.1 %
53
100 %
χ2=0.822 · df=1 · φ=0.182 · Fisher’s p=0.224

In der Stichprobe identifizieren sich 15% als Männer. Mit einem Anteil von 25% sind diese unter den aktuell Rauchenden also überproportional vertreten - und mit einem Anteil von 10.8% unter den aktuell Nichtrauchenden unterproportional vertreten. Auch die vergleichende Perspektive auf zeilenbezogene Anteilswerte verweist also auf einen Zusammenhang zwischen den beiden Variablen. Gleichwohl lässt sich die “falsche” Prozentsatzdifferenz von 14.2 hier nicht als Mass der Einflussgrösse der UV, sondern nur als indirekter Ausdruck dieses Einflusses deuten.

 

3 Bivariate Visualisierung mit ggplot

Das ggplot2-Package stellt auch für bivariate (bzw. bedingte oder differenzierte) Visualisierungen einige schöne Optionen zur Verfügung, z.b. den “Stacked Barplot”.

plot_fill <- ggplot(kursdata_anon, aes(x = geschlecht, fill = rauchen_aktuell)) + 
  geom_bar(position = "fill") + 
  labs(title = "Rauchstatus nach Geschlecht",
       x = "Geschlecht", y = "Prozent", fill="Aktuell Rauchend",
       caption="Quelle: Kursbefragung Statistik I (n = 53)") + 
  scale_y_continuous(labels = scales::percent_format()) +
  theme_bw()
plot_fill

Anders als die verwendete Tabellenfunktionalität berücksichtigt ggplot als NA codierte fehlende Werte und stellt sie als Kategorie dar. Dies erschwert die visuelle Erfassung des Zusammenhangs. Da es auch deswegen eine statistische Konvention ist, Personen mit fehlenden Werten - von seltenen Ausnahmen abgesehen - nicht in bi- oder multivariaten Analysen zu repräsentieren, nutzen wir für jede visualisierte Variablenkonstellation einen spezifischen Teildatensatz, aus dem wir die Beobachtungen mit fehlenden Werten jeweils ausschliessen.

kursdata_rauchplot <- filter(kursdata_anon, !is.na(geschlecht) & !is.na(rauchen_aktuell))
plot_fill <- ggplot(kursdata_rauchplot, aes(x = geschlecht, fill = rauchen_aktuell)) + 
  geom_bar(position = "fill") + 
  labs(title = "Rauchstatus nach Geschlecht",
       x = "Geschlecht", y = "Prozent", fill="Aktuell Rauchend",
       caption="Quelle: Kursbefragung Statistik I (n = 53)") + 
  scale_y_continuous(labels = scales::percent) +
  theme_bw()
plot_fill

In diesem mit der Suboption geom_bar realisierten gestapelten Balkendiagramm bilden die 45 Frauen die durch die rechte Säule und die 8 Männer die linke Säule. Die rote Fläche kennzeichnet jeweils den Anteil an Nichtrauchenden innerhalb der Kategorien der UV. Die farblich einheitlichen Flächen reflektieren also jeweils die Spaltenprozente der Kreuztabelle. Dementsprechend markiert der Unterschied in der Höhe der Farbgrenze die Prozentsatzdifferenz. Es wird nun auch visuell gestützt deutlich: Unter Männern ist der Anteil an Rauchenden grösser als unter Frauen.

Der oben verwendete Befehl zur Erzeugung des gestapelten Balkendiagramms unterscheidet sich nur in Nuancen vom Befehl für das einfache Balkendiagramm: Indem das fill=-Argument zur Farbgestaltung der Balken nicht mit einer Farbe, sondern mit einer Variable besetzt wird, erscheint innerhalb der Balken ein Farbmuster entsprechend der bedingten Verteilung dieser Variable.

Da die Balkendiagramm-Variante position=“fill” automatisch Anteilswerte auf die y-Achse legt, können über scale_y_continuous(labels = scales::percent) einfach Prozentwerte auf der y-Achse abgebildet werden und somit die Kategoriehäufigkeiten der x-Variablen (ähnlich wie in der Tabelle durch die Spaltenprozentuierung) auf 100% setzen.

Eine alternative Variante des gestapelten Balkendiagramms ergibt sich, wenn wir die position = “fill” - Anweisung weglassen:

plot_fill_v2 <- ggplot(kursdata_rauchplot, aes(x = geschlecht, fill = rauchen_aktuell)) + 
  geom_bar() + 
    aes(y = after_stat(count / sum(count)))+ 
  labs(title = "Rauchstatus nach Geschlecht",
       x = "Geschlecht", y="Prozent", fill="Aktuell Rauchend",
       caption="Quelle: Kursbefragung Statistik I (n = 53)") + 
  scale_y_continuous(labels = scales::percent)+
  theme_bw()
plot_fill_v2

Hier wurde ebenfalls ein gestapeltes Balkendiagramm erzeugt, allerdings sind die Kategorien der UV nun nicht mehr auf 100% gleichgestellt, sondern über ihre absoluten Häufigkeiten repräsentiert. Dadurch wird einerseits die univariate Verteilungen der unabhängigen Variable deutlich, andererseits ist nun der Unterschied der bedingten Verteilungen der abhängigen Variable nicht mehr so klar akzentuiert. Da uns aber im Zuge der bivariaten Zusammenhangsanalyse nicht Unterschiede in der Geschlechterverteilung interessieren, sondern Unterschiede im Rauchverhalten zwischen den Geschlechtern, ist diese Darstellung hier nicht so gut geeignet.

Achtung: Nur bei Spezifikation von position=“fill” werden auf der y-Achse automatisch Anteilswerte dargestellt. Wenn wir auch ohne diese Spezifikation korrekte Prozentwerte darstellen möchten, müssen wir zusätzlich über aes(y = after_stat(count / sum(count))) absolute Werte zunächst in Anteilswerte transformieren, damit über scale_y_continuous(labels = scales::percent) die korrekte Hochrechnung auf Prozente erfolgt.

Anteilswerte können nicht nur gestapelt, sondern auch einfach nebeneinander gestellt werden, und zwar durch die Anweisung position = “dodge”:

plot_fill_v2 <- ggplot(kursdata_rauchplot, aes(x = geschlecht, fill = rauchen_aktuell)) + 
  geom_bar(position="dodge") + 
      aes(y = after_stat(count / sum(count)))+ 
  labs(title = "Rauchstatus nach Geschlecht",
       x = "Geschlecht", y="Prozent", fill="Aktuell Rauchend",
       caption="Quelle: Kursbefragung Statistik I (n = 53)") + 
    scale_y_continuous(labels = scales::percent) +
  theme_bw()
plot_fill_v2

Gelegentlich ergibt sich die Notwendigkeit, Abbildungen mit Graustufen bzw. in Schwarz/Weiss zu produzieren. In diesen Fällen können mit der Variante geom_bar_pattern Variablenausprägungen über Form- statt Farbmuster differenziert werden.

library(ggpattern)
plot_fill <- ggplot(kursdata_rauchplot, aes(x = geschlecht, stack = rauchen_aktuell)) + 
  geom_bar_pattern(aes(pattern=rauchen_aktuell), color="black", fill="grey95", position = "fill")+ 
  aes(y = after_stat(count / sum(count)))+ 
  labs(title = "Rauchstatus nach Geschlecht",
       x = "Geschlecht", y = "Prozent", pattern="Aktuell Rauchend",
       caption="Quelle: Kursbefragung Statistik I (n = 53)") + 
  scale_y_continuous(labels = scales::percent) +
  theme_bw()
plot_fill

 

4 Bildungshintergrund und Vertrauen - Anwendung

In dieser Anwendung wollen wir analysieren, ob der Bildungshintergrund und das Grundvertrauen einer Person zusammenhängen. Wir verwenden die Variablen akback und trustkat aus der Kursumfrage.

Bei trustkat handelt es sich um eine rekodierte Variante der originalen, 5-stufigen trust - Variable:

attributes(kursdata_anon$trust)
## $label
## [1] "Kann man Menschen im Allg. vertrauen? (5-volle Zustimmung, 1-volle Ablehnung)"
## 
## $format.stata
## [1] "%8.0g"
table(kursdata_anon$trust)
## 
##  1  2  3  4  5 
##  1  8 18 25  2

Die ursprünglichen (relativ dünn belegten) Randausprägungen 1 und 5 wurden in trustkat mit den anliegenden Ausprägungen 2 und 4 gruppiert, wodurch dann eine trichotome Variable mit den Ausprägungen 1 (“Gering”) 2 (“Mittel”) und 3 (“Viel”) entsteht.

attributes(kursdata_anon$trustkat)
## $label
## [1] "Allg. Vertrauen (kat.)"
## 
## $format.stata
## [1] "%9.0g"
## 
## $class
## [1] "haven_labelled" "vctrs_vctr"     "double"        
## 
## $labels
## Gering Mittel   Viel 
##      1      2      3
table(kursdata_anon$trustkat)
## 
##  1  2  3 
##  9 18 27
class(kursdata_anon$trustkat)
## [1] "haven_labelled" "vctrs_vctr"     "double"
table(as_factor(kursdata_anon$trustkat), 
      as_factor(kursdata_anon$trust))
##         
##           1  2  3  4  5
##   Gering  1  8  0  0  0
##   Mittel  0  0 18  0  0
##   Viel    0  0  0 25  2

akback bezieht sich auf das Bildungsniveau der Eltern. Die Variable unterscheidet zwischen Arbeiterkindern und Akademikerkindern (mindestens ein Elternteil akademisch ausgebildet):

attributes(kursdata_anon$akback)
## $label
## [1] "Akademikerkind?"
## 
## $format.stata
## [1] "%9.0g"
## 
## $class
## [1] "haven_labelled" "vctrs_vctr"     "double"        
## 
## $labels
## nein   ja 
##    0    1
table(kursdata_anon$akback)
## 
##  0  1 
## 21 33
attributes(kursdata_anon$eltern)
## $label
## [1] "(fach)hochschulabschluss eltern"
## 
## $format.stata
## [1] "%8.0g"
## 
## $class
## [1] "haven_labelled" "vctrs_vctr"     "double"        
## 
## $labels
##  beide  einer keiner 
##      1      2      3
table(as_factor(kursdata_anon$akback), 
      as_factor(kursdata_anon$eltern))
##       
##        beide einer keiner
##   nein     0     0     21
##   ja      21    12      0
#Faktorisierung 
kursdata_anon$akback<-as_factor(kursdata_anon$akback)
table (kursdata_anon$akback)
## 
## nein   ja 
##   21   33

4.1 Kreuztabelle

kursdata_anon$trustkat<-as_factor(kursdata_anon$trustkat)

tab_xtab(var.row = kursdata_anon$trustkat, var.col = kursdata_anon$akback,
         title = "Kreuztabelle: Vertrauen nach Bildungshintergrund",
         var.labels = c("Vertrauen in Mitmenschen", "Akademikerkind?"),
         show.col.prc = TRUE,
         show.obs = TRUE)
Kreuztabelle: Vertrauen nach Bildungshintergrund
Vertrauen in
Mitmenschen
Akademikerkind? Total
nein ja
Gering 1
4.8 %
8
24.2 %
9
16.7 %
Mittel 9
42.9 %
9
27.3 %
18
33.3 %
Viel 11
52.4 %
16
48.5 %
27
50 %
Total 21
100 %
33
100 %
54
100 %
χ2=3.896 · df=2 · Cramer’s V=0.269 · Fisher’s p=0.139

4.2 Visualisierung

kursdata_plot2 <- filter(kursdata_anon, !is.na(akback) & !is.na(trustkat))

plot_fill_trust <- ggplot(kursdata_plot2, aes(x = akback, fill = trustkat)) +
  geom_bar(position = "fill") + 
  labs(title = "Vertrauen in Menschen nach Bildungshintergrund",
       x = "", y = "",  fill="Vertrauen",
       caption="Quelle: Kursbefragung Statistik I (n = 76)") +
  
  scale_y_continuous(labels = scales::percent_format()) + 
  scale_x_discrete(labels=c("Arbeiterkind", "Akademikerkind")) + 
  theme_bw()
plot_fill_trust

Die Kategorienordnung ist noch nicht perfekt: Intuitiver wäre es, wenn sich die Kategorien in den Säulen entsprechend ihrer hierarchischen Bedeutung von unten nach oben anordnen würden. Dieses lässt sich nur sehr schwer innerhalb des ggplot-Befehls arrangieren. Zielführender Standard für die Modifikation der Kategorienreihenfolge ist auch hier, wie schon in der univariaten Statistik, die Neuordnung innerhalb der Variable über factor(levels()):

kursdata_plot2$trustkat<-factor(kursdata_plot2$trustkat, levels=c("Viel", "Mittel", "Gering"))

plot_fill_trust <- ggplot(kursdata_plot2, aes(x = akback, fill = trustkat)) +
  geom_bar(position = "fill") + 
  labs(title = "Vertrauen in Menschen nach Bildungshintergrund",
       x = "", y = "",  fill="Vertrauen",
       caption="Quelle: Kursbefragung Statistik I (n = 76)") +
  scale_y_continuous(labels = scales::percent_format()) + 
  scale_x_discrete(labels=c("Arbeiterkind", "Akademikerkind")) + 
  theme_bw()
plot_fill_trust

plot_fill_trust <- ggplot(kursdata_plot2, aes(x = akback, fill = trustkat)) +
  geom_bar(position = "fill") + 
  labs(
    title = "Vertrauen in Menschen nach Bildungshintergrund",
    x = "", 
    y = "",  
    fill = "Vertrauen",
    caption = "Quelle: Kursbefragung Statistik I (n = 76)"
  ) +
  scale_y_continuous(labels = scales::percent_format()) + 
  scale_x_discrete(labels = c("Arbeiterkind", "Akademikerkind")) + 
  scale_fill_manual(values = c("#77DD77", "#FFDDC1", "#FF6961")) +  
  theme_bw()

plot_fill_trust

plot_dodge_trust <- ggplot(kursdata_plot2, aes(x = akback, y = ..count.., fill = trustkat)) +
  geom_bar(position = "dodge", stat = "count") +  # Position dodge für nebeneinanderliegende Balken
  labs(
    title = "Vertrauen in Menschen nach Bildungshintergrund",
    x = "", 
    y = "Anzahl",  
    fill = "Vertrauen",
    caption = "Quelle: Kursbefragung Statistik I (n = 76)"
  ) +
  scale_x_discrete(labels = c("Arbeiterkind", "Akademikerkind")) + 
  scale_fill_manual(values = c("#77DD77", "#FFDDC1", "#FF6961")) +  # Farben der Tricolore
  theme_bw()

plot_dodge_trust

[Auswertungsvorschläge siehe Foliensatz oben]

 

Folgende Texte empfehlen wir euch zur Lektüre und Vertiefung:

BCP Kapitel 5: Beckerman, A.P., Childs, D.Z., Petchey, O.L. (2017): Getting Started with R. Oxford: Universität Press.

 

Hier gehts weiter zur Übung IV

 

logo.knit

Conforti, E., Siefart, F., De Min, N., Dürr, R., Moos, M., Senn, S., Strassmann-Rocha, D., Giesselmann, M. (2022): “R für das Soziologiestudium an der UZH”