Kapitel 7 Deskriptive Statistik

Die beschreibende Statistik bietet neben Informationen über die Verteilungen und Zusammenhänge der interessierenden Merkmale ebenfalls die Möglichkeit, unplausible Werte zu identifizieren, die mit den im vorherigen Kapitel gelernten Methoden entfernt oder korrigiert werden müssen. Die Beschreibungen der kontinuierlichen und kategorialen Merkmale dürfen in keiner wissenschaftlichen Arbeit fehlen.

7.1 Lagemaße und Streuungsmaße

Für dieses Kapitel müssen die Packages des tidyverse und remp installiert und geladen werden.

library(tidyverse)
library(remp)

Wir werden in diesem Kapitel den big5_mod Datensatz ohne die Spalte namens ID verwenden und bezeichnen diesen als big5_mod1.

big5_mod1 <- big5_mod |> select(-ID)
big5_mod1
# A tibble: 200 × 5
  Alter Geschlecht Extraversion Neurotizismus Gruppe
  <dbl> <chr>             <dbl>         <dbl> <fct> 
1    36 m                   3             1.9 Mittel
2    30 f                   3.1           3.4 Jung  
3    23 m                   3.4           2.4 Jung  
4    54 m                   3.3           4.2 Weise 
# ℹ 196 more rows

Einen ersten Überblick über die Daten können wir mit der direkt in R integrierten Funktion summary() erhalten, der wir lediglich den Namen des Datensatzes übergeben müssen.

summary(big5_mod1)
     Alter        Geschlecht         Extraversion   Neurotizismus      Gruppe   
 Min.   :13.00   Length:200         Min.   :2.300   Min.   :1.400   Jung  :147  
 1st Qu.:18.75   Class :character   1st Qu.:2.800   1st Qu.:2.700   Mittel: 39  
 Median :23.00   Mode  :character   Median :3.000   Median :3.100   Weise : 14  
 Mean   :26.48                      Mean   :3.076   Mean   :3.133               
 3rd Qu.:31.25                      3rd Qu.:3.300   3rd Qu.:3.600               
 Max.   :60.00                      Max.   :4.300   Max.   :4.600               

Hier sehen wir einen Vorteil von Faktoren. Während wir die Häufigkeiten der einzelnen Altersgruppen ausgegeben bekommen, kann R für die Spalte mit Geschlecht lediglich die Anzahl an vorhandenen Character Werten zählen. Für weitere Informationen über Faktoren und deren Umgang schaue dir erneut Kapitel 4.3.2 und 6.10 an.

Allerdings fehlt bei dieser Ansicht zum Beispiel die Standardabweichung und man kann mit die Ausgabe nicht vernünftig zum Exportieren formatieren. Im begleitenden remp Package gibt es die Funktion descriptive(), die standardmäßig Anzahl, Minimum, 25% Quartil, Mittelwert, Median, 75% Quartil, die Standardabweichung und den Standardfehler für alle numerischen Spalten ausgibt. Möchte man Spalten nicht in der Ausgabe sehen, sollte man dieser zuvor mit select() entfernen (siehe Kapitel 6.2).

big5_mod1 |> 
  descriptive()
# A tibble: 3 × 10
  Variable          N   Min    Q1  Mean Median    Q3   Max    SD    SE
  <chr>         <int> <dbl> <dbl> <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl>
1 Alter           200  13    18.8 26.5    23    31.2  60   11.4   0.8 
2 Extraversion    200   2.3   2.8  3.08    3     3.3   4.3  0.35  0.02
3 Neurotizismus   200   1.4   2.7  3.13    3.1   3.6   4.6  0.68  0.05

Zusätzlich könnte man mit dem .print Argument die Anzahl ausgegebener Spalten erhöhen. Für Grupperiungen der deskriptiven Statistiken verwenden wir die Funktion group_by() aus dem dplyr Package des tidyverse. Dabei können wir der Funktion beliebig viele Spalten ohne Anführungszeichen übergeben. So können wir beispielsweise nach Geschlecht aufteilen.

big5_mod1 |> 
  group_by(Geschlecht) |> 
  descriptive() 
# A tibble: 6 × 11
# Groups:   Geschlecht [2]
  Geschlecht Variable          N   Min    Q1  Mean Median    Q3   Max    SD    SE
  <chr>      <chr>         <int> <dbl> <dbl> <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl>
1 f          Alter           118  14   18    25.9    22    29.8  60   11.4   1.05
2 f          Extraversion    118   2.4  2.8   3.05    3     3.2   4.3  0.36  0.03
3 f          Neurotizismus   118   1.4  2.82  3.25    3.3   3.7   4.6  0.63  0.06
4 m          Alter            82  13   20    27.3    23    32    59   11.4   1.25
# ℹ 2 more rows

Bei Interesse nach Unterschieden innerhalb der Geschlechter je nach Altersgruppe, fügen wir die Spalte Gruppe in die Funktion group_by() hinzu.

big5_mod1 |> 
  group_by(Geschlecht, Gruppe) |> 
  descriptive() 
# A tibble: 18 × 12
# Groups:   Geschlecht, Gruppe [6]
  Geschlecht Gruppe Variable          N   Min    Q1  Mean Median    Q3   Max    SD    SE
  <chr>      <fct>  <chr>         <int> <dbl> <dbl> <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl>
1 f          Jung   Alter            89  14    17   20.4    20    23    30    4.21  0.45
2 f          Jung   Extraversion     89   2.4   2.8  3.07    3     3.3   4.3  0.37  0.04
3 f          Jung   Neurotizismus    89   1.4   2.9  3.29    3.3   3.6   4.6  0.58  0.06
4 f          Mittel Alter            20  31    34.8 39.0    39    42.2  49    5.16  1.15
# ℹ 14 more rows

Der Nachteil an dieser Funktion ist die fehlende Flexibilität, falls man andere Schätzer inkludieren möchte. Dafür bietet sich die Funktion summarise() aus dem dplyr Package (Teil des tidyverse). Als Argumente übergeben wir auf der linken Seite der Gleichung den gewünschten Namen der neu erstellen Spalte und auf der rechten Seite die Funktion zur Berechnung der Statistik mit dem gewünschten Spaltennamen.

Exemplarisch soll zunächst der Mittelwert mit der Funktion mean() und die Standardabweichung mit sd() berechnet werden. Bei fehlenden Werten müsste man zusätzlich das Argument na.rm zum Entfernen fehlender Werte bei der Berechnung hinzufügen (z.B. mean(Extraversion, na.rm = TRUE)). Wichtig ist allerdings, dass die innerhalb von summarise() verwendeten Funktionen nur einen Wert pro Spalte ausrechnen.

big5_mod1 |> 
  summarise(
    M = mean(Extraversion),
    SD = sd(Extraversion)
  )
# A tibble: 1 × 2
      M    SD
  <dbl> <dbl>
1  3.08 0.347

Auch hier gruppieren wir mit der zuvor kennengelernten Funktion group_by().

big5_mod1 |> 
  group_by(Geschlecht) |> 
  summarise(
    M = mean(Extraversion),
    SD = sd(Extraversion)
  )
# A tibble: 2 × 3
  Geschlecht     M    SD
  <chr>      <dbl> <dbl>
1 f           3.05 0.358
2 m           3.11 0.328

Grundsätzlich kann jede Funktion summarise() übergeben werden, die einen einzelnen Wert berechnet. Somit unterscheidet sich die Anwendung maßgeblich vom bereits kennengelernten mutate(). Dort musste die Ausgabe immer eine Reihe von Werten umfassen, die der Anzahl der Zeilen im Datensatz entspricht.

Grundsätzlich können wir beliebig viele Berechnungen in einem Funktionsaufruf durchführen. Möchte man die gleichen Statistiken für mehrere Spalten berechnen, greifen wir erneut auf die Hilfsfunktion across() zurück (siehe Kapitel 6.4.2). Hier müssen wir die verschiedenen Funktionen mit entsprechendem Namen innerhalb einer Liste übergeben. Listen als solche werden erst später eingeführt und müssen uns an dieser Stelle nicht weiter interessieren (siehe Kapitel 11.4).

big5_mod1 |> 
  summarise(across(
    .cols = Extraversion:Neurotizismus, 
    .fns = list(M = mean, Median = median, SD = sd))
  )
# A tibble: 1 × 6
  Extraversion_M Extraversion_Median Extraversion_SD Neurotizismus_M Neurotizismus_Median
           <dbl>               <dbl>           <dbl>           <dbl>                <dbl>
1           3.08                   3           0.347            3.13                  3.1
# ℹ 1 more variable: Neurotizismus_SD <dbl>

Wie dir vielleicht bereits aufgefallen ist, sieht die Ausgabe von summarise() für mehrere Spalten anders aus als die von descriptive(). Während erstere die Variablen nebeneinander in neue Spalten auflistet, fügt descriptive() die Ergebnisse zeilenweise hinzu. Wenn wir die gleiche Ausgabe wie in descriptive() erreichen möchten, müssen wir den Datensatz zunächst in ein langes Format bringen (siehe Kapitel 6.6). Nun gruppieren wir nach der neu erstellten Spalte namens Variable. Anschließend können wir wie gewohnt mit summarise() die gewünschten Berechnungen durchführen. Nichts anderes macht die Funktion descriptive() hinter den Kulissen.

big5_mod1 |> 
  pivot_longer(
    cols = c(Alter, Extraversion, Neurotizismus),
    names_to = "Variable",
    values_to = "Wert"
  ) |> 
  group_by(Variable) |> 
  summarise(
    Q1 = quantile(Wert, 0.25),
    Mean = mean(Wert),
    Q3 = quantile(Wert, 0.75)
  )
# A tibble: 3 × 4
  Variable         Q1  Mean    Q3
  <chr>         <dbl> <dbl> <dbl>
1 Alter          18.8 26.5   31.2
2 Extraversion    2.8  3.08   3.3
3 Neurotizismus   2.7  3.13   3.6

Alternativen für einen schnellen Überblick bieten beispielsweise auch das skimr Package mit der Funktion skim() oder describe() aus dem psych Package. Beide können auch nicht-numerische Spalten auswerten und erstere gibt zu jeder Spalte sogar ein kleines Histogramm aus.

Übung 7.1. (Noch nicht enthalten) Starte die Übung mit uebung_starten(7.1).

7.2 Häufigkeiten und Kontingenztafeln

Zum Ausführen der Funktionen dieses Kapitels muss das tidyverse und das Package janitor installiert und geladen sein.

library(tidyverse)
library(janitor)

In diesem Kapitel verwenden wir den big5_mod Datensatz aus dem remp Package. Der schnellste Weg zur Berechnung von Häufigkeiten ist die direkt in R integrierte Funktion namens tables(). Dabei übergeben wir die Spalten mithilfe des Dollar-Operators (siehe Kapitel 4.5). Hier wählen wir die Spalte Geschlecht aus.

table(big5_mod$Geschlecht)

  f   m 
118  82 

Durch das Hinzufügen einer weiteren Variable, erhalten wir eine klassische Kontingenztafel, die wir mit Methoden im Rahmen von Kapitel 9.6 inferenzstatistisch betrachten werden. An dieser Stelle möchten wir die absoluten Häufigkeiten der Geschlechter zusätzlich nach den drei Altersgruppen aufteilen. In diesem Fall beinhalten beide Spalten Textbezeichnung. Hätten wir zwei numerische Spalten (z.B. Tod 0/1 und Geschlecht 0/1) solltest zusätzlich das Argument dnn zum Festlegen der Dimensionsnamen verwenden.

table(big5_mod$Geschlecht, big5_mod$Gruppe, dnn = c("Geschlecht", "Altersgruppe"))
          Altersgruppe
Geschlecht Jung Mittel Weise
         f   89     20     9
         m   58     19     5

Ein weiteres nützliches Argument ist useNA, welches wir zum Anzeigen fehlender Werte auf "ifany" setzen können. Darüber hinaus können wir durch das Argument exclude eine Faktorstufe für die Erstellung einer Kontingenztafel zur späteren Auswertung herausnehmen. Wäre bei der Variable Geschlecht beispielsweise eine dritte Stufe namens Divers mit wenigen Beobachtungen vorhanden, könnten wir diese so für die Hypothesentests ausblenden. Die Voraussetzung dafür ist, dass die Variable als Faktor kodiert ist (siehe Kapitel 4.3.2 und 6.10).

Eine dritte Dimension führt zur Ausgabe als sogenannte Liste (siehe Kapitel 11.4). Die erste Kontingenztafel unter dem Wort FALSE beinhaltet alle Personen mit einer Extraversion kleiner oder gleich 3.5 und die Kontingenztafel darunter entsprechend alle Personen mit einer Extraversion größer 3.5, jeweils aufgeteilt nach Geschlecht und Altersgruppe. Das Inkludieren einer logischen Abfrage ist eine der großen Vorteil der table() Funktion.

table(
  big5_mod$Geschlecht, 
  big5_mod$Gruppe, 
  big5_mod$Extraversion > 3.5
)
, ,  = FALSE

   
    Jung Mittel Weise
  f   81     18     9
  m   54     18     4

, ,  = TRUE

   
    Jung Mittel Weise
  f    8      2     0
  m    4      1     1

Nachteile der table() Funktion sind hingegen die unbefriedigenden Möglichkeiten zum Exportieren als Word oder PDF Dokument sowie die umständliche Anzeige relativer Häufigkeiten und bedingter Wahrscheinlichkeiten. An dieser Stelle kommt die Funktion tabyl() aus dem janitor Package ins Spiel. Dabei ist das erste Argument der Name des Datensatzes gefolgt von ein bis drei Spaltennamen. Fehlende Werte werden automatisch angezeigt. Falls dies nicht erwünscht ist, könnten wir diese mit dem Argument show_na = FALSE ausblenden.

tabyl(big5_mod, Geschlecht)
 Geschlecht   n percent
          f 118    0.59
          m  82    0.41

Neben der absoluten werden zusätzlich die relativen Häufigkeiten angezeigt. Die Ausgaben der Funktion tabyl() sind außerdem mit der Hilfe von R Markdown direkt nach Word exportierbar (siehe Kapitel 10.3.1). Möchten wir wie zuvor zwei Variablen miteinander in Bezug auf Häufigkeiten analysieren, sollten wir auf einige Formatierungshilfen aus dem janitor Package zurückgreifen. Auch wenn diese zunächst umständlich erscheinen, profitiert man durch die übersichtliche Ausgabe enorm.

Die Funktionen zum Formatieren beginnen alle mit dem Präfix adorn. In unserem ersten Beispiel sind wir an Unterschieden in Bezug auf die Häufigkeit der Altersgruppen je nach Geschlecht interessiert. Ausgeben möchten wir also die Zeilenrandsummen in einer extra Spalte ("col"), die bedingten Wahrscheinlichkeiten für jede Altersgruppe gegeben des jeweiligen Geschlechts ("row") in Prozent, nur eine Nachkommastelle der Prozentwerte, die absoluten Häufigkeiten in Klammern und abschließend die Namen der verwendeten Spalten.

tabyl(big5_mod, Geschlecht, Gruppe) |> 
  adorn_totals("col") |> 
  adorn_percentages("row") |> 
  adorn_pct_formatting(digits = 1) |> 
  adorn_ns() |> 
  adorn_title()
                Gruppe                                 
 Geschlecht       Jung     Mittel    Weise        Total
          f 75.4% (89) 16.9% (20) 7.6% (9) 100.0% (118)
          m 70.7% (58) 23.2% (19) 6.1% (5) 100.0%  (82)

Möchten wir hingegen herausfinden, ob mehr Frauen oder Männer in den jeweiligen Altersgruppen befragt wurden, lassen wir uns stattdessen die Spaltenrandsummen in einer extra Zeile ("row") und die bedingten Wahrscheinlichkeiten mit Konditionierung auf die Altersgruppe ("col") ausgeben.

tabyl(big5_mod, Geschlecht, Gruppe) |> 
  adorn_totals("row") |> 
  adorn_percentages("col") |> 
  adorn_pct_formatting(digits = 1) |> 
  adorn_ns() |> 
  adorn_title()
                  Gruppe                        
 Geschlecht         Jung      Mittel       Weise
          f  60.5%  (89)  51.3% (20)  64.3%  (9)
          m  39.5%  (58)  48.7% (19)  35.7%  (5)
      Total 100.0% (147) 100.0% (39) 100.0% (14)

Während die Funktion table() vor allem für einen ersten Überblick und zum Erstellen von Kontingenztafeln für Hypothesentests geeignet ist, bietet die Funktion tabyl() viele Formatierungsmöglichkeiten mit direkter Kompatibilität mit R Markdown zum Exportieren in ein Word Dokument.

Übung 7.2. (Noch nicht enthalten) Starte die Übung mit uebung_starten(7.2).

7.3 Zusammenhangsmaße

Für einen schnell graphischen Überblick über größere Korrelationstabellen wird die Installation und das Laden des corrplot Packages empfohlen.

library(corrplot)

In diesem Kapitel wird ebenfalls der big5_mod Datensatz aus dem remp Package verwendet. Zwei der wichtigsten Zusammenhangsmaße für metrische Variablen sind die Kovarianz und die darauf basierende Korrelation. Eine Korrelation berechnen wir mit der cor() Funktion, äquivalent dazu die Kovarianz mit cov(). Wir werden uns im weiteren Verlauf die Korrelationen konzentrieren. Wichtig ist hierbei das method Argument, welches standardmäßig die Produkt-Moment-Korrelation berechnet. Als Argument müssen wir die einzelnen Spalten als Wertereihe mithilfe des Dollar-Operators aus dem Datensatz extrahieren (siehe Kapitel 4.5).

cor(big5_mod$Extraversion, big5_mod$Neurotizismus, method = "pearson")
[1] 0.06972529

Beim Vorliegen ordinaler Daten bevorzugen wir hingegen Rangkorrelation nach Spearman ("spearman") oder Kendall ("kendall"), wofür das Argument methodentsprechend anpassen.

cor(big5_mod$Extraversion, big5_mod$Neurotizismus, method = "spearman")
[1] 0.04874732

Um auf einen Schlag die Zusammenhänge von mehr als zwei Merkmalen zu explorieren, können wir der Funktion cor() den Datensatz mit den interessierenden Variablen auch direkt übergeben. Wichtig ist dabei, dass alle Spalten numerisch sind. Für unser Beispiel wählen wir uns zunächst die Spalten Alter, Extraversion und Neurotizismus aus und bezeichnen das Zwischenergebnis als big5_sub.

big5_sub <- big5_mod |> 
  select(Alter, Extraversion, Neurotizismus)

Anschließend berechnen wir die Korrelation mit der Funktion cor().

corr_table1 <- cor(big5_sub)
corr_table1
                   Alter Extraversion Neurotizismus
Alter          1.0000000  -0.12250136   -0.23019948
Extraversion  -0.1225014   1.00000000    0.06972529
Neurotizismus -0.2301995   0.06972529    1.00000000

Allerdings ist die Ausgabe vor allem bei größeren Korrelationstabellen nicht sonderlich übersichtlich. Deswegen verwenden wir zusätzlich die corrplot Funktion aus dem gleichnamigen Package, wobei wir an dieser Stelle nur die Korrelationen (method = "number") im unteren Dreieck (type = "lower") anschauen möchten. In Abbildung 7.1 sehen wir auf der linken Seite die Korrelation mit farblicher Markierung. Positive Korrelation werden in blau und negative Korrelation in rot illustriert. Je kleiner die Korrelation, desto blasser ist Farbe der abgebildeten Korrelation.

corrplot(corr_table1, method = "number", type = "lower")

Eine alternative Betrachtungsweise für Zusammenhänge sind Streudiagramme. Wir werden diese zwar im Detail erst in Kapitel 8.3 kennenlernen, allerdings bietet die direkt in R integrierte Funktion pairs() einen schönen ersten Überblick über mögliche Assoziationen der jeweiligen Merkmale (siehe Abbildung 7.1 rechts).

pairs(big5_sub, lower.panel = panel.smooth)
Visualisierung der Korrelationen und zugehörigen Streudiagrammen.Visualisierung der Korrelationen und zugehörigen Streudiagrammen.

Abbildung 7.1: Visualisierung der Korrelationen und zugehörigen Streudiagrammen.

Bei sehr großen Korrelationstabellen werden aber auch diese Visualisierungen schnell unübersichtlich. Daher bietet es sich an, stattdessen nur Kreise darzustellen, die je nach Richtung der Korrelation eine andere Farbe mit unterschiedlicher Deckkraft und je nach Betrag einen anderen Durchmesser haben. Exemplarisch untersuchen wir dafür die Assoziation zwischen den Fragen zur Extraversion und zum Neurotizismus aus dem im remp enthaltenen Datensatz namens big5_comp. Dafür wählen wir die interessierenden Spalten aus und erstellen die Korrelationstabelle (siehe Kapitel 6.2).

big5_sub2 <- big5_comp |> select(E1:N10)
corr_table2 <- cor(big5_sub2)

Abschließend verwenden wir die bereits kennengelernte Funktion corrplot() ohne zusätzliche Argumente. In Abbildung 7.2 wird sehen wir anschaulich, dass nur die jeweils die Fragen der entsprechenden Dimension miteinander korrelieren. Negative Korrelation innerhalb der Fragen zur Extraversion oder dem Neurotizismus weisen auf eine inverse Kodierung hin.

corrplot(corr_table2) 
Darstellung der Korrelationen als Kreise in Abhängigkeit der Stärke und Richtung.

Abbildung 7.2: Darstellung der Korrelationen als Kreise in Abhängigkeit der Stärke und Richtung.

Zusammenhangsmaße im Kontext von Kontingenztafeln werden im Rahmen von Kapitel 9.6 besprochen.

Übung 7.3. (Noch nicht enthalten) Starte die Übung mit uebung_starten(7.3).