oecd-yacsda

eda
datawrangling
vis
yacsda
R
Published

May 8, 2024

Fallstudie: Explorative Datenanalyse zum Datensatz “OECD Wellbeing”

(YACSDA: Yet another Case Study on Data Analysis)

1 Grundlagen

Tip

Wenn Sie nicht mehr weiter wissen, googeln Sie nach dem Problem. Oder fragen Sie einen ChatBot, z.B. ChatGPT. \(\square\)

Important

Im Folgenden werden mitunter mehrere Lösungswege präsentiert. Sie können sich den Weg aussuchen, der Ihnen am besten gefällt. Sie müssen nicht alle Wege verstehen oder gar beherrschen. Einer reicht. \(\square\)

1.1 Hintergrund

In diesem Post untersuchen wir einige Aspekte der explorativen Datenanalyse für den Datensatz oecd wellbeing aus dem Jahr 2016.

Hinweis: Als Vertiefung gekennzeichnete Abschnitt sind nicht prüfungsrelevant.

1.2 Benötigte Pakete

Ein Standard-Paket zur grundlegenden Datenanalyse bzw. des Datenjudos ist tidyverse. Darüber hinaus verwenden wir noch zwei Pakete zur Visualisierung und eines für den Komfort.

library(tidyverse)  # Datenjudo
library(easystats)  # Komfort 
library(DataExplorer)  # Data vis
library(ggpubr)  # Data vis

1.3 Datensatz laden

Der Datensatz kann hier bezogen werden.

Doi: https://doi.org/10.1787/data-00707-en.

Falls der Datensatz lokal (auf Ihrem Rechner) vorliegt, können Sie ihn in gewohnter Manier importieren. Geben Sie dazu den Pfad zum Datensatz ein; bei mir sieht das so aus:

oecd <- read.csv("/Users/sebastiansaueruser/datasets/oecd_wellbeing.csv")

Liegt die Datendatei im gleichen Verzeichnis wie Ihre R-/Quarto-/Rmd-Datei, dann brauchen Sie nur den Dateinamen, nicht den Pfad, anzugeben.

Alternativ können Sie die Daten direkt von einem Server beziehen:

oecd <- read.csv("https://raw.githubusercontent.com/sebastiansauer/2021-sose/master/data/OECD/oecd-wellbeing.csv")

1.4 Erster Blick

glimpse(oecd)
#> Rows: 429
#> Columns: 15
#> $ Country                  <chr> "Australia", "Australia", "Australia", "Austr…
#> $ Region                   <chr> "New South Wales", "Victoria", "Queensland", …
#> $ region_type              <chr> "country_part", "country_part", "country_part…
#> $ Code                     <chr> "AU1", "AU2", "AU3", "AU4", "AU5", "AU6", "AU…
#> $ Education                <dbl> 8.0, 8.1, 7.8, 7.3, 7.6, 6.5, 8.1, 9.5, 8.8, …
#> $ Jobs                     <dbl> 8.1, 7.9, 8.1, 7.8, 8.8, 7.6, 8.7, 9.3, 7.8, …
#> $ Income                   <dbl> 6.8, 5.9, 6.3, 6.1, 7.9, 5.4, 8.2, 10.0, 5.7,…
#> $ Safety                   <dbl> 8.8, 9.5, 9.5, 9.0, 8.6, 8.8, 0.0, 10.0, 9.7,…
#> $ Health                   <dbl> 9.0, 9.5, 8.3, 8.5, 9.3, 5.4, 2.4, 9.3, 6.7, …
#> $ Environment              <dbl> 9.8, 8.6, 9.9, 9.4, 9.6, 10.0, 9.2, 9.1, 3.5,…
#> $ Civic_engagement         <dbl> 10.0, 10.0, 10.0, 10.0, 10.0, 10.0, 8.4, 10.0…
#> $ Accessiblity_to_services <dbl> 7.2, 7.5, 7.7, 7.2, 7.8, 6.8, 7.8, 8.7, 8.0, …
#> $ Housing                  <dbl> 7.2, 7.8, 8.3, 8.3, 8.9, 8.3, 5.6, 8.3, 6.1, …
#> $ Community                <dbl> 8.9, 9.3, 8.6, 8.6, 8.5, 8.6, 10.0, 9.8, 8.3,…
#> $ Life_satisfaction        <dbl> 7.8, 8.5, 8.1, 8.5, 7.8, 9.6, 7.0, 9.6, 7.8, …

Wie glimpse() aufzeigt, liegen also einige qualitative (kategoriale, chr, vom Typ “Text”) und einige quantitative (metrische, dbl) Variablen vor. Die qualitativen Variablen sind für eine direkte Analyse weniger interessant; vielmehr ist es interessant, die Statistiken auf die Gruppen (Stufen, Level) der qualitativen Variablen aufzusplitten.

Betrachten wir aber zu Beginn die metrischen Variablen einzeln (univariat).

1.5 Deskriptive Statistiken zu den metrischen Variablen, einzeln (univariat)

Zentrale Statistiken zu den metrischen Variablen lassen sich auf mehreren Wegen mit R berechnen. Hier ist ein Weg:

describe_distribution(oecd)
Variable Mean SD IQR Min Max Skewness Kurtosis n n_Missing
Education 6.81 2.97 3.50 0 10 -1.08 -0.02 426 3
Jobs 6.45 2.41 2.90 0 10 -0.96 0.48 429 0
Income 4.11 2.70 3.40 0 10 0.44 -0.38 429 0
Safety 7.05 3.23 3.80 0 10 -1.18 0.10 429 0
Health 5.73 2.93 5.20 0 10 -0.33 -1.15 429 0
Environment 5.40 2.73 4.35 0 10 -0.11 -0.89 429 0
Civic_engagement 5.05 2.85 4.10 0 10 -0.03 -0.91 429 0
Accessiblity_to_services 6.53 2.65 2.60 0 10 -1.13 0.50 429 0
Housing 4.80 3.02 5.50 0 10 -0.06 -1.12 427 2
Community 6.88 2.75 3.25 0 10 -1.13 0.32 425 4
Life_satisfaction 5.80 2.90 4.90 0 10 -0.47 -0.87 425 4

Jetzt gehen wir weiter zur Visualisierung der Verteilung der metrischen Variablen. Auch hier gibt es wieder viele Lösungen.

Es reicht, wenn Sie mit einer Lösung vertraut sind.

1.5.1 Mit ggpubr

oecd |> 
gghistogram(x = "Life_satisfaction")

1.5.2 Mit DataExplorer

oecd |> 
  select(Life_satisfaction) |> 
  plot_histogram()

1.5.3 Mit ggplot

Das R-Paket ggplot wird durch das “Meta-Paket” tidyverse gestartet. Sie müssen es also nicht extra starten.

oecd %>% 
  ggplot(aes(x = Life_satisfaction)) +
  geom_histogram()

Eine ähnliche Aussage liefert das Dichte-Diagramm:

oecd %>% 
  ggplot(aes(x = Life_satisfaction)) +
  geom_density()

Die Dichte gibt an, welcher Anteil der Beobachtungen an der jeweiligen Stelle der X-Achse lägen, wenn man eine Einheit betrachtet (z.B. die Lebenszufriedenheit von 5-6).

1.6 Histogramm nach Gruppen: Lebenszufriedenheit in De und Fr

Angenommen, man möchte Deutschland mit Frankreich vergleichen im Hinblick auf die Lebenszufriedenheit.

Zunächst filtern wir den OECD-Datensatz, so dass nur die beiden genannten Länder enthalten bleiben:

oecd_de_fr <- 
oecd %>% 
  filter(Country == "Germany" | Country == "France") 

Dann visualisieren wir wieder.

1.6.1 Mit ggpubr

oecd_de_fr |> 
  gghistogram(x = "Life_satisfaction", facet.by = "Country")

1.6.2 Mit DataExplorer

Leider unterstützt DataExplorer nicht direkt den Vergleich von Grupen mit einem Histogramm. Man könnte aber einen Boxplot verwenden stattdessen.

oecd_de_fr |> 
  select(Life_satisfaction, Country) |> 
  plot_boxplot(by = "Country")

1.6.3 Mit ggplot

oecd_de_fr %>% 
  ggplot(aes(x = Life_satisfaction)) +
  geom_histogram(bins = 15) +
  facet_wrap(~ Country)

1.7 Histogramm für alle metrischen Variablen auf einmal

Um einen Überblick über die Verteilungen zu bekommen, bietet es sich an, sich alle Verteilungen anzuschauen. Malen wir einmal alle Histogramme auf einmal. Das geht wiederum mit DataExplorer sehr einfach:

oecd |> 
  plot_histogram()

1.8 VERTIEFUNG: Histogramm für alle Variablen auf kompliziert

Note

Dieser Abschnitt ist eine Vertiefung; Sie können in überspringen, ohne den Anschluss zu den folgenden Abschnitten zu verlieren. \(\square\)

Als erstes erzeugen wir einen langen Dataframe (der nur aus metrischen Variablen besteht):

oecd_de_fr %>% 
  select(where(is.numeric)) %>%  # wähle alle Spalten aus, wo sich Nummern finden
  pivot_longer(everything()) %>%  # baue alle Variablen in ein langes Format um
  slice(1:10) # zeige die Zeilen 1 bis 10
#> # A tibble: 10 × 2
#>    name                     value
#>    <chr>                    <dbl>
#>  1 Education                  7.8
#>  2 Jobs                       6  
#>  3 Income                     6.3
#>  4 Safety                     8.6
#>  5 Health                    10  
#>  6 Environment                3.5
#>  7 Civic_engagement           7.4
#>  8 Accessiblity_to_services   8.6
#>  9 Housing                    3.3
#> 10 Community                  7.9

Dann plotten wir Histogramme, wobei wir nach den Ländern (key) gruppieren. Aber zuerst speichern wir uns den “langen” Datensatz ab:

oecd_de_fr_long <- 
oecd_de_fr %>% 
  select(where(is.numeric)) %>%  # wähle alle Spalten aus, wo sich Nummern finden
  pivot_longer(everything()) 

Betrachten Sie diesen Daten einmal zur Übung.

Dann plotten wir in gewohnter Manier:

oecd_de_fr_long %>% 
  ggplot(aes(x = value)) +
  geom_histogram() +
  facet_wrap(~ name)

2 Forschungsfrage: Lebenszufriedenheit in De im internationalen Vergleich

2.1 Hintergrund

Hat Deutschland in Vergleich zu anderen Ländern eine hohe Lebenszufriedenheit?

Die Frage ist noch recht unpräzise formuliert, aber dafür gibt sie Raum für eine Menge von Untersuchungsansätzen.

2.1.1 Datensatz filtern - nur Länder, keine Landesteile

Der Datensatz in seiner aktuellen Form verstößt gegen die Regel der “Normalform”, dass in jeder Zeile (genau) eine Beobachtungseinheit steht und in jeder Zeile (genau) eine Variable. In einigen Zeilen stehen Länder, in den meisten anderen aber Landesteile (wie Bayern, Baden-Württemberg etc.). Filtern wir uns nur die Länder, und exkdluieren die Landesteile:

oecd_short <-
  filter(oecd, region_type == "country_whole") 

Die Anzahl der Zeilen dieses Datensatz oecd_short gibt uns Aufschluss über die Anzahl der untersuchten Länder.

2.1.2 Visualisierung der Lebenszufriedenheit der Länder

2.1.2.1 Mit DataExplorer

oecd_short |> 
  select(Country, Life_satisfaction) |> 
  plot_scatterplot(by = "Life_satisfaction")

2.1.2.2 Mit ggplot

oecd_short %>% 
  ggplot(aes(x = Country, y = Life_satisfaction)) +
  geom_point()

2.1.2.3 Sieht nicht so schön aus

Hm, unser Punktediagramm sieht nicht übersichtlich aus. Besser wäre es, die Punkte absteigend zu sortieren.

Betrachten wir dazu die Variable country näher: Es handelt sich um eine Character-Variable:

str(oecd)
#> 'data.frame':    429 obs. of  15 variables:
#>  $ Country                 : chr  "Australia" "Australia" "Australia" "Australia" ...
#>  $ Region                  : chr  "New South Wales" "Victoria" "Queensland" "South Australia" ...
#>  $ region_type             : chr  "country_part" "country_part" "country_part" "country_part" ...
#>  $ Code                    : chr  "AU1" "AU2" "AU3" "AU4" ...
#>  $ Education               : num  8 8.1 7.8 7.3 7.6 6.5 8.1 9.5 8.8 8.5 ...
#>  $ Jobs                    : num  8.1 7.9 8.1 7.8 8.8 7.6 8.7 9.3 7.8 8.2 ...
#>  $ Income                  : num  6.8 5.9 6.3 6.1 7.9 5.4 8.2 10 5.7 5.9 ...
#>  $ Safety                  : num  8.8 9.5 9.5 9 8.6 8.8 0 10 9.7 9.8 ...
#>  $ Health                  : num  9 9.5 8.3 8.5 9.3 5.4 2.4 9.3 6.7 6.6 ...
#>  $ Environment             : num  9.8 8.6 9.9 9.4 9.6 10 9.2 9.1 3.5 2.6 ...
#>  $ Civic_engagement        : num  10 10 10 10 10 10 8.4 10 8.6 8.1 ...
#>  $ Accessiblity_to_services: num  7.2 7.5 7.7 7.2 7.8 6.8 7.8 8.7 8 7.4 ...
#>  $ Housing                 : num  7.2 7.8 8.3 8.3 8.9 8.3 5.6 8.3 6.1 5.6 ...
#>  $ Community               : num  8.9 9.3 8.6 8.6 8.5 8.6 10 9.8 8.3 7.8 ...
#>  $ Life_satisfaction       : num  7.8 8.5 8.1 8.5 7.8 9.6 7 9.6 7.8 8.1 ...

Eine Variable des Typs character steht für Text, z.B. "Germany".

Offensichtlich sind diese alphabetisch geordnet – nach dieser Ordnung richtet sich die Ordnung im Diagramm.

2.1.3 Umwandling in eine Faktor-Variable

In solchen Fällen bietet es sich an, die Character-Variable in eine Factor-Variable umzuwandeln; dann geht das Weitere einfacher.

oecd_short <- 
oecd_short %>% 
  mutate(Country = factor(Country))

Übrigens: Möchte man wissen, wie viele unterschiedliche Werte eine Variable enthält, dann kann die Funktion distinct() verwenden:

oecd_short %>% 
  distinct(Country)
#>            Country
#> 1        Australia
#> 2          Austria
#> 3          Belgium
#> 4           Canada
#> 5            Chile
#> 6   Czech Republic
#> 7          Denmark
#> 8          Estonia
#> 9          Finland
#> 10          France
#> 11         Germany
#> 12          Greece
#> 13         Hungary
#> 14         Iceland
#> 15         Ireland
#> 16          Israel
#> 17           Italy
#> 18           Japan
#> 19           Korea
#> 20      Luxembourg
#> 21          Mexico
#> 22     Netherlands
#> 23     New Zealand
#> 24          Norway
#> 25          Poland
#> 26        Portugal
#> 27 Slovak Republic
#> 28        Slovenia
#> 29           Spain
#> 30          Sweden
#> 31     Switzerland
#> 32          Turkey
#> 33  United Kingdom
#> 34   United States

2.2 Ranking und Top-10-Prozent der Zufriedenheit

2.2.1 Top-10

Schauen wir uns die “Happy-Top-10” an, die 10 Länder mit der höchsten Lebenszufriedenheit:

oecd_short %>% 
  arrange(-Life_satisfaction) %>%  # absteigend sortieren
  select(Country, Life_satisfaction) %>% 
  slice(1:10)
#>        Country Life_satisfaction
#> 1      Denmark              10.0
#> 2  Switzerland              10.0
#> 3      Finland               9.7
#> 4  Netherlands               9.7
#> 5       Norway               9.7
#> 6       Canada               9.3
#> 7      Iceland               9.3
#> 8       Sweden               9.3
#> 9    Australia               8.8
#> 10     Austria               8.8

2.2.2 Die oberen 10% der Zufriedenheit

Mit welcher Lebenszufriedenheit gehört ein Land zu den Top-10-Prozent der zufriedenen Länder?

oecd_short %>% 
  summarise(quantile(Life_satisfaction, probs = .90))
#>   quantile(Life_satisfaction, probs = 0.9)
#> 1                                      9.7

Ah, Länder mit einer Lebenszufriedenheit von mind. 9.7 gehören zu den oberen Top-10-Prozent. Filtern wir mal entsprechend:

oecd_short %>% 
  filter(Life_satisfaction >= 9.7) %>% 
  select(Country, Life_satisfaction)
#>       Country Life_satisfaction
#> 1     Denmark              10.0
#> 2     Finland               9.7
#> 3 Netherlands               9.7
#> 4      Norway               9.7
#> 5 Switzerland              10.0

2.3 Vertiefung

Ändern wir die Sortierung! Mit reorder() kann man die Sortierung ändern (re-ordnen, daher der Name):

oecd_short_reordered <- 
oecd_short %>% 
  mutate(Country_sorted = reorder(Country, Life_satisfaction)) 

Ist das jetzt geordnet? str() (wie structure) verrät es uns:

str(oecd_short_reordered)
#> 'data.frame':    34 obs. of  16 variables:
#>  $ Country                 : Factor w/ 34 levels "Australia","Austria",..: 1 2 3 4 5 6 7 8 9 10 ...
#>  $ Region                  : chr  "Australia" "Austria" "Belgium" "Canada" ...
#>  $ region_type             : chr  "country_whole" "country_whole" "country_whole" "country_whole" ...
#>  $ Code                    : chr  "AUS" "AUT" "BEL" "CAN" ...
#>  $ Education               : num  7.6 8.4 7.5 9.2 7.2 10 6.7 9.6 8.7 7.6 ...
#>  $ Jobs                    : num  7.9 7.7 5 6.6 6.2 7.3 7.9 6.6 6.4 5.2 ...
#>  $ Income                  : num  9.5 7.9 6.2 7.4 0.4 2.8 5.1 1 5.6 7 ...
#>  $ Safety                  : num  8.4 10 5.7 6.5 0.6 6.1 10 0 10 8.4 ...
#>  $ Health                  : num  9 7.2 6.6 8.5 4.2 2.7 5.8 2.1 7.3 9.3 ...
#>  $ Environment             : num  9.7 2.8 1.9 7.4 8.5 1.4 5.8 6.4 7.9 4.5 ...
#>  $ Civic_engagement        : num  10 6.2 9.7 4.7 0.1 2.6 8.9 3.7 4.8 7.5 ...
#>  $ Accessiblity_to_services: num  6.9 7.2 7.6 8.1 0 6.7 8.3 7.6 9 6.9 ...
#>  $ Housing                 : num  9.5 5.1 8.8 10 1.5 2.9 6.6 1.5 6.6 5.1 ...
#>  $ Community               : num  8.8 7.6 7.7 8.5 2.5 5.1 9.6 4.6 8.7 7.6 ...
#>  $ Life_satisfaction       : num  8.8 8.8 7.9 9.3 4.9 5.3 10 0.4 9.7 6.2 ...
#>  $ Country_sorted          : Factor w/ 34 levels "Hungary","Portugal",..: 23 24 20 27 12 13 33 4 30 15 ...
#>   ..- attr(*, "scores")= num [1:34(1d)] 8.8 8.8 7.9 9.3 4.9 5.3 10 0.4 9.7 6.2 ...
#>   .. ..- attr(*, "dimnames")=List of 1
#>   .. .. ..$ : chr [1:34] "Australia" "Austria" "Belgium" "Canada" ...

Wie man sieht, ist Country_sorted jetzt anders sortiert.

Visualisieren wir das Ergebnis:

2.3.1 Mit DataExplorer

oecd_short_reordered |> 
  select(Country_sorted, Life_satisfaction) |> 
  plot_scatterplot(by = "Life_satisfaction")

Oh, DataExplorer macht die Reihenfolge wieder kaputt.

2.3.2 Mit ggpubr

oecd_short_reordered |> 
  ggscatter(x = "Country_sorted",
            y = "Life_satisfaction")

2.3.3 Mit ggplot

plot_sorted <- oecd_short_reordered %>% 
  ggplot(aes(x = Country_sorted, y = Life_satisfaction)) +
  geom_point()

plot_sorted

Schon besser. Man kann z.B. die Achsen nicht lesen 😢. Was könnte man da bloß tun?

2.3.4 Achsenu um 90 Grad drehen

Mit + coord_flip() lassen sich die Achsen um 90 Grad drehen:

plot_sorted + coord_flip()

Schön 😄.

Man hätte das Sortieren und Achsen drehen auch in einem Haps machen können:

oecd_short_reordered %>% 
  ggplot(aes(x = Country_sorted, y = Life_satisfaction)) +
  geom_point() + coord_flip()

Aber übersichtlicher ist es, die Dinge nacheinander zu tun.

2.3.5 Mittelwert ins Diagramm

Schön wäre es noch, im Bild den Mittelwert o.Ä. im Diagramm zu sehen:

oecd_short_reordered %>% 
  ggplot(aes(x = Country_sorted, y = Life_satisfaction)) +
  geom_point() +
  geom_hline(yintercept = 6.08, data = NA, color = "firebrick") + 
  coord_flip()

Tja, die Wünsche hören nie auf… Wäre es nicht noch nett, wenn “Deutschland” hervorgehoben wäre, optisch, so dass es im Diagramm hervorsticht. Nehmen wir an, wir sind an diesem Land besonders interessiert.

oecd_short_reordered <- 
  oecd_short_reordered %>% 
  mutate(is_Germany = Country == "Germany")

Damit haben wir eine Spalte erstellt, die angibt, ob ein Land Deutschland ist (TRUE) oder nicht (FALSE). Diese neue Variable nehmen wir her, um die Farbe, Größe und Form der Punkte zu bestimmen:

oecd_short_reordered %>% 
  ggplot(aes(x = Country_sorted, y = Life_satisfaction)) +
  geom_point(aes(color = is_Germany, shape = is_Germany, size = is_Germany)) +
  geom_hline(yintercept = 6.08, data = NA, color = "firebrick") + 
  geom_hline(yintercept = 6.08, data = NA, color = "grey60") %>% 
  geom_vline(xintercept = 16, data = NA, color = "grey80") +
  coord_flip()

2.4 Zusammenhang zweier metrischer Variablen – Punktediagramm

Hängt die Lebenszufriedenheit mit Civic_engagment zusammen?

Visualisieren wir diesen (möglichen) Zusammenhang.

2.4.1 Mit ggpubr

oecd_short_reordered |> 
  ggscatter(x = "Civic_engagement",
            y = "Life_satisfaction")

2.4.2 Mit DataExplorer

oecd_short_reordered |> 
  select(Civic_engagement, Life_satisfaction) |> 
  plot_scatterplot(by = "Life_satisfaction")

DataExplorer bietet den Vorteil, dass man einfach überprüfen kann, ob irgendeine Variable mit Lebenszufriedenheit zusammenhängt:

oecd_short_reordered |> 
  #select(Civic_engagement, Life_satisfaction) |> 
  plot_scatterplot(by = "Life_satisfaction")

2.4.3 Mit ggplot

oecd_short_reordered %>% 
  ggplot(aes(x = Civic_engagement, y = Life_satisfaction)) +
  geom_point()

2.4.4 Insgesamt wenig Zusammenhang

Hm, es ist kein starker Trend zu erkennen.

Was sagt die Korrelation dazu:

oecd_short_reordered %>% 
  summarise(cor_ce_ls = cor(Civic_engagement, Life_satisfaction))
#>   cor_ce_ls
#> 1 0.4021292

Immerhin, kein ganz unwesentlicher Wert.

2.4.5 Und so weiter

Dieses Prinzip mit dem Punktediagramm könnte man jetzt weiterführen ad nauseam.

2.4.6 Korrelationsdiagramm

oecd_short_reordered |> 
  plot_correlation()

2.5 Zusammenhang zweier Variablen unter Berücksichtigung von Drittvariablen

Oben haben wir gesehen, dass Lebenszufriedenheit und Civiv Engagement zusammenhängen (zumindest ein bisschen).

Aber vielleicht hängt dieser Zusammenhang wiederum von der finanziellen Absicherung ab? Nur wenn man materiell abgesichert ist, so könnte man argumentieren, wird bürgerliches Engagement (bzw. die Möglichkeit zu) eine Einflussgröße auf die Lebenszufriedenheit.

Anders gesagt: Man könnte behaupten, der Zusammenahng von Lebenszufriedenheit und Civiv Engagement ist abhängig von einer dritten Variable, dem Einkommen.

Um diese Frage zu untersuchen, teilen wir Income in zwei Stufen, hoch und gering. Dann untersuchen wir jeweils den Zusammenhang von Lebenszufriedenheit und bürgerlichem Engagement.

Achtung! Eine metrische Variablen in zwei Hälften zu spalten birgt einen hohen Informationsverlust. Da wir aber nur eine grobe Untersuchung vorhaben (und uns noch nicht fortgeschrittener Technik bedienen wollen), bleiben wir erstmal bei dieser sog. Dichotomisierung.

Nehmen wir den Median des Einkommen als Teilungspunkt; man spricht von einem “Mediansplit”:

oecd_short %>% 
  summarise(Income_md = median(Income))
#>   Income_md
#> 1      5.15

Zuerst erstellen wir eine Variable Income_high mit den Stufen 0 (nein) und 1 (ja):

oecd_short_reordered <- 
  oecd_short_reordered %>% 
    mutate(Income_high = 
           case_when( Income >= median(Income) ~ 1,
                      Income < median(Income) ~ 0))

2.5.1 Visualisierung

Jetzt plotten wir den Zusammenhang:

2.5.1.1 Mit ggpubr

oecd_short_reordered |> 
  ggscatter(y = "Country_sorted",
            x = "Life_satisfaction",
            facet.by = "Income_high")

2.5.1.2 Mit ggplot

income_labels <- c(`0` = "arm", 
                   `1` ="reich")

oecd_short_reordered %>% 
  ggplot(aes(x = Country_sorted, y = Life_satisfaction)) +
  geom_point() +
  facet_wrap(~ Income_high, 
             labeller = labeller(Income_high = income_labels))  +
  coord_flip() +
  labs(y = "Länder",
       x = "Lebenszufriedenheit",
       title = "Lebenszufriedenheit in armen und reichen Ländern ") +
  theme_minimal()

2.5.2 Vertiefung: Korrelation pro Gruppe

Um die Korrelation pro Gruppe zu erhalten, könnten wir jeweils einen Dataframe pro Gruppe erzeugen (mit filter()) und dann jeweils die Korrelation von Zufriedenheit und Engagement berechnen.

Eine andere, etwas elegantere Möglichkeit kann so aussehen:

oecd_short_reordered %>%
  group_by(Income_high) %>% 
  summarise(cor_zuf_eng = cor(Life_satisfaction, Civic_engagement))
#> # A tibble: 2 × 2
#>   Income_high cor_zuf_eng
#>         <dbl>       <dbl>
#> 1           0       0.367
#> 2           1       0.140

Interessanterweise ist die Korrelation durchaus verschieden in den beiden Gruppen.

Natürlich sind die beiden Gruppen nur Stichproben - es stellt sich die Frage, ob die Unterschiede nur durch Zufälligkeiten des Stichprobenziehens entstanden sind oder auch in der Grundgesatmtheit der “reichen” und “armen” Ländern existieren? Dazu später mehr!

2.6 Deskriptive Statistiken nach Ländern

2.6.1 Lebenszufriedenheit

2.6.1.1 Mit easystats

Das ist relativ einfach:

oecd_short_reordered %>% 
  select(Life_satisfaction) %>% 
  describe_distribution()
#> Variable          | Mean |   SD |  IQR |         Range | Skewness | Kurtosis |  n | n_Missing
#> ---------------------------------------------------------------------------------------------
#> Life_satisfaction | 6.07 | 3.38 | 6.33 | [0.00, 10.00] |    -0.58 |    -1.08 | 34 |         0

2.6.1.2 Mit tidyverse

oecd_short_reordered %>% 
  summarise(satis_mean = mean(Life_satisfaction),
            satis_median = median(Life_satisfaction),
            satis_sd = sd(Life_satisfaction),
            satis_iqr = IQR(Life_satisfaction))
#>   satis_mean satis_median satis_sd satis_iqr
#> 1   6.070588          7.3 3.379397     5.975

3 Reproducibility

#> ─ Session info ───────────────────────────────────────────────────────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.4.0 (2024-04-24 ucrt)
#>  os       Windows 11 x64 (build 22631)
#>  system   x86_64, mingw32
#>  ui       RTerm
#>  language (EN)
#>  collate  German_Germany.utf8
#>  ctype    German_Germany.utf8
#>  tz       Europe/Berlin
#>  date     2024-10-08
#>  pandoc   3.2 @ C:/Program Files/RStudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────────────────────────────────────────────
#>  package      * version    date (UTC) lib source
#>  abind          1.4-8      2024-09-12 [1] CRAN (R 4.4.1)
#>  assertthat     0.2.1      2019-03-21 [1] CRAN (R 4.4.1)
#>  backports      1.5.0      2024-05-23 [1] CRAN (R 4.4.0)
#>  bayestestR   * 0.14.0     2024-07-24 [1] CRAN (R 4.4.1)
#>  broom          1.0.5      2023-06-09 [1] CRAN (R 4.4.0)
#>  cachem         1.0.8      2023-05-01 [1] CRAN (R 4.4.0)
#>  car            3.1-2      2023-03-30 [1] CRAN (R 4.4.0)
#>  carData        3.0-5      2022-01-06 [1] CRAN (R 4.4.0)
#>  cli            3.6.2      2023-12-11 [1] CRAN (R 4.4.0)
#>  codetools      0.2-20     2024-03-31 [1] CRAN (R 4.4.0)
#>  colorspace     2.1-0      2023-01-23 [1] CRAN (R 4.4.0)
#>  correlation  * 0.8.5      2024-06-16 [1] CRAN (R 4.4.1)
#>  crayon         1.5.2      2022-09-29 [1] CRAN (R 4.4.0)
#>  data.table     1.15.4     2024-03-30 [1] CRAN (R 4.4.0)
#>  DataExplorer * 0.8.3      2024-01-24 [1] CRAN (R 4.4.0)
#>  datawizard   * 0.13.0     2024-10-05 [1] CRAN (R 4.4.1)
#>  devtools       2.4.5      2022-10-11 [1] CRAN (R 4.4.0)
#>  digest         0.6.35     2024-03-11 [1] CRAN (R 4.4.0)
#>  dplyr        * 1.1.4      2023-11-17 [1] CRAN (R 4.4.0)
#>  easystats    * 0.7.3      2024-07-22 [1] CRAN (R 4.4.1)
#>  effectsize   * 0.8.9      2024-07-03 [1] CRAN (R 4.4.1)
#>  ellipsis       0.3.2      2021-04-29 [1] CRAN (R 4.4.0)
#>  emo            0.0.0.9000 2024-10-07 [1] Github (hadley/emo@3f03b11)
#>  evaluate       0.23       2023-11-01 [1] CRAN (R 4.4.0)
#>  fansi          1.0.6      2023-12-08 [1] CRAN (R 4.4.0)
#>  farver         2.1.2      2024-05-13 [1] CRAN (R 4.4.0)
#>  fastmap        1.1.1      2023-02-24 [1] CRAN (R 4.4.0)
#>  forcats      * 1.0.0      2023-01-29 [1] CRAN (R 4.4.0)
#>  fs             1.6.4      2024-04-25 [1] CRAN (R 4.4.0)
#>  generics       0.1.3      2022-07-05 [1] CRAN (R 4.4.0)
#>  ggformula    * 0.12.0     2023-11-09 [1] CRAN (R 4.4.0)
#>  ggplot2      * 3.5.1      2024-04-23 [1] CRAN (R 4.4.0)
#>  ggpubr       * 0.6.0      2023-02-10 [1] CRAN (R 4.4.0)
#>  ggridges       0.5.6      2024-01-23 [1] CRAN (R 4.4.0)
#>  ggsignif       0.6.4      2022-10-13 [1] CRAN (R 4.4.0)
#>  glue           1.7.0      2024-01-09 [1] CRAN (R 4.4.0)
#>  gridExtra      2.3        2017-09-09 [1] CRAN (R 4.4.0)
#>  gtable         0.3.5      2024-04-22 [1] CRAN (R 4.4.0)
#>  haven          2.5.4      2023-11-30 [1] CRAN (R 4.4.0)
#>  hms            1.1.3      2023-03-21 [1] CRAN (R 4.4.0)
#>  htmltools      0.5.8.1    2024-04-04 [1] CRAN (R 4.4.0)
#>  htmlwidgets    1.6.4      2023-12-06 [1] CRAN (R 4.4.0)
#>  httpuv         1.6.15     2024-03-26 [1] CRAN (R 4.4.0)
#>  igraph         2.0.3      2024-03-13 [1] CRAN (R 4.4.0)
#>  insight      * 0.20.5     2024-10-02 [1] CRAN (R 4.4.1)
#>  jsonlite       1.8.8      2023-12-04 [1] CRAN (R 4.4.0)
#>  knitr          1.46       2024-04-06 [1] CRAN (R 4.4.0)
#>  labeling       0.4.3      2023-08-29 [1] CRAN (R 4.4.0)
#>  labelled       2.13.0     2024-04-23 [1] CRAN (R 4.4.0)
#>  later          1.3.2      2023-12-06 [1] CRAN (R 4.4.0)
#>  lattice      * 0.22-6     2024-03-20 [1] CRAN (R 4.4.0)
#>  lifecycle      1.0.4      2023-11-07 [1] CRAN (R 4.4.0)
#>  lubridate    * 1.9.3      2023-09-27 [1] CRAN (R 4.4.0)
#>  magrittr       2.0.3      2022-03-30 [1] CRAN (R 4.4.0)
#>  MASS           7.3-60.2   2024-04-24 [1] local
#>  Matrix       * 1.7-0      2024-03-22 [1] CRAN (R 4.4.0)
#>  memoise        2.0.1      2021-11-26 [1] CRAN (R 4.4.0)
#>  mime           0.12       2021-09-28 [1] CRAN (R 4.4.0)
#>  miniUI         0.1.1.1    2018-05-18 [1] CRAN (R 4.4.0)
#>  modelbased   * 0.8.8      2024-06-11 [1] CRAN (R 4.4.1)
#>  mosaic         1.9.1      2024-02-23 [1] CRAN (R 4.4.0)
#>  mosaicCore     0.9.4.0    2023-11-05 [1] CRAN (R 4.4.0)
#>  mosaicData   * 0.20.4     2023-11-05 [1] CRAN (R 4.4.0)
#>  munsell        0.5.1      2024-04-01 [1] CRAN (R 4.4.0)
#>  networkD3      0.4        2017-03-18 [1] CRAN (R 4.4.0)
#>  parameters   * 0.22.2     2024-09-03 [1] CRAN (R 4.4.1)
#>  performance  * 0.12.3     2024-09-02 [1] CRAN (R 4.4.1)
#>  pillar         1.9.0      2023-03-22 [1] CRAN (R 4.4.0)
#>  pkgbuild       1.4.4      2024-03-17 [1] CRAN (R 4.4.0)
#>  pkgconfig      2.0.3      2019-09-22 [1] CRAN (R 4.4.0)
#>  pkgload        1.3.4      2024-01-16 [1] CRAN (R 4.4.0)
#>  plyr           1.8.9      2023-10-02 [1] CRAN (R 4.4.0)
#>  profvis        0.3.8      2023-05-02 [1] CRAN (R 4.4.0)
#>  promises       1.3.0      2024-04-05 [1] CRAN (R 4.4.0)
#>  purrr        * 1.0.2      2023-08-10 [1] CRAN (R 4.4.0)
#>  R6             2.5.1      2021-08-19 [1] CRAN (R 4.4.0)
#>  Rcpp           1.0.12     2024-01-09 [1] CRAN (R 4.4.0)
#>  readr        * 2.1.5      2024-01-10 [1] CRAN (R 4.4.0)
#>  remotes        2.5.0      2024-03-17 [1] CRAN (R 4.4.1)
#>  report       * 0.5.9      2024-07-10 [1] CRAN (R 4.4.1)
#>  reshape2       1.4.4      2020-04-09 [1] CRAN (R 4.4.0)
#>  rlang          1.1.4      2024-06-04 [1] CRAN (R 4.4.1)
#>  rmarkdown      2.26       2024-03-05 [1] CRAN (R 4.4.0)
#>  rstatix        0.7.2      2023-02-01 [1] CRAN (R 4.4.0)
#>  rstudioapi     0.16.0     2024-03-24 [1] CRAN (R 4.4.0)
#>  scales         1.3.0      2023-11-28 [1] CRAN (R 4.4.0)
#>  see          * 0.9.0      2024-09-06 [1] CRAN (R 4.4.1)
#>  sessioninfo    1.2.2      2021-12-06 [1] CRAN (R 4.4.0)
#>  shiny          1.8.1.1    2024-04-02 [1] CRAN (R 4.4.0)
#>  stringi        1.8.4      2024-05-06 [1] CRAN (R 4.4.0)
#>  stringr      * 1.5.1      2023-11-14 [1] CRAN (R 4.4.0)
#>  tibble       * 3.2.1      2023-03-20 [1] CRAN (R 4.4.0)
#>  tidyr        * 1.3.1      2024-01-24 [1] CRAN (R 4.4.0)
#>  tidyselect     1.2.1      2024-03-11 [1] CRAN (R 4.4.0)
#>  tidyverse    * 2.0.0      2023-02-22 [1] CRAN (R 4.4.0)
#>  timechange     0.3.0      2024-01-18 [1] CRAN (R 4.4.0)
#>  tzdb           0.4.0      2023-05-12 [1] CRAN (R 4.4.0)
#>  urlchecker     1.0.1      2021-11-30 [1] CRAN (R 4.4.0)
#>  usethis        2.2.3      2024-02-19 [1] CRAN (R 4.4.0)
#>  utf8           1.2.4      2023-10-22 [1] CRAN (R 4.4.0)
#>  vctrs          0.6.5      2023-12-01 [1] CRAN (R 4.4.0)
#>  withr          3.0.1      2024-07-31 [1] CRAN (R 4.4.1)
#>  xfun           0.43       2024-03-25 [1] CRAN (R 4.4.0)
#>  xtable         1.8-4      2019-04-21 [1] CRAN (R 4.4.0)
#>  yaml           2.3.8      2023-12-11 [1] CRAN (R 4.4.0)
#> 
#>  [1] C:/Users/sebastian.sauer/AppData/Local/Programs/R/R-4.4.0/library
#> 
#> ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────