Datenanalyse in 6 Schritten

Eine Anleitung in der statistischen Programmiersprache R

Autor:in

Patrik Häcki

Veröffentlichungsdatum

8. Oktober 2025

Version
5.2

Einführung

Was ist R?

R ist eine kostenlose Open Source-Software für statistische Datenverarbeitung, die über die Website https://stat.ethz.ch/CRAN bezogen werden kann. Dabei umfasst R zum einen eine Vielzahl an Möglichkeiten zur Verarbeitung und Auswertung von Daten, die sich ohne grossen Aufwand nutzen lassen. Zum anderen kann man statistische Verfahren auch selbst programmieren und R fast beliebig erweitern. Von Anwendern erstellte Erweiterungen werden als Pakete oder packages bezeichnet und von ihren Programmierern oftmals für alle zugänglich gemacht. Im Comprehensive R Archive Network (kurz: CRAN), einem Netz aus Webservern, die Pakete und Code für R bereitstellen, sind eine Vielzahl solcher Pakete gelistet. Daneben wird auch Base R durch ein Kern-Team von Entwicklern ständig weiterentwickelt. R ist open-source, d.h. der Source Code ist unter der GNU Public License frei verfügbar.

Vorteile von R

Die wesentlichen Vorteile von R lassen sich insgesamt wie folgt zusammenfassen:

  • R kann kostenlos heruntergeladen und installiert werden.

  • R steht für Windows-, Unix- und Mac-Systeme zur Verfügung.

  • R wird von einem Kern-Team von Entwicklern ständig weiterentwickelt.

  • Es gibt eine Vielzahl von frei zugänglichen Erweiterungen, die von der kontinuierlich wachsenden R-Community erstellt werden.

  • R kann durch den Nutzer selbst erweitert werden.

Aufgrund dieser Vorteile findet R zunehmend Verbreitung und wird nicht nur im wissenschaftlichen Bereich, sondern auch für Anwendungen in der Wirtschaft eingesetzt.

Installation

R

Zentrale Anlaufstelle für den Download von R, für Zusatzpakete sowie für frei verfügbare Literatur ist die R-Projektseite https://www.r-project.org (in Englisch) oder das Comprehensive R Archive Network für die Schweiz https://stat.ethz.ch/CRAN, welches von der ETH Zürich betreut wird.

R-Editor

Anders als manche seiner kommerziellen und kostenpflichtigen Konkurrenten (wie etwa SPSS) kommt die freie Programmiersprache R ohne grafische Benutzeroberfläche daher. Nach dem Download und der Installation von R ist es deshalb empfehlenswert, zusätzlich einen komfortableren, kostenlosen R-Editor zu installieren.

  • RStudio von Posit (https://posit.co) ist die wohl am weitesten verbreitete integrierte Entwicklungsumgebung (IDE) für die Programmiersprache R. Weitere nützliche Editoren sind
  • Jupyter Notebooks von https://jupyter.org oder
  • der kostenlose Quelltext-Editor Visual Studio Code von Microsoft (https://code.visualstudio.com).

Datenanalyse

Pakete laden

R-Pakete sind Sammlungen von Funktionen und Werkzeugen, die von der R-Community entwickelt wurden. Sie erhöhen die Leistungsfähigkeit von R, indem sie bestehende Basisfunktionen verbessern oder neue Funktionen hinzufügen.

Mit der Funktion install.packages() werden neue Pakete installiert (z.B. das Paket janitor).

Für die Datenanalyse in sechs Schritten laden Sie bitte folgende Pakete in die aktuelle R-Session:

  • corrplot
  • ggdist
  • ggExtra
  • ggforce
  • ggstatsplot
  • glue
  • janitor
  • paletteer
  • palmerpenguins
  • patchwork
  • psych
  • RColorBrewer
  • readxl
  • recipes
  • rjson
  • scales
  • skimr
  • summarytools
  • statip
  • tidyAML
  • TidyDensity
  • tidyverse
  • treemap
  • waffle

Daten laden

Beispieldaten

In R stehen zahlreiche Import-Funktionen zur Verfügung, um Daten aus unterschiedlichen Anwendungen und in verschiedensten Formaten zu laden.

Zur Veranschaulichung der verschiedenen Funktionen und Visualisierungen werden die folgenden Datensätze verwendet:

Code anzeigen
bgb_staat <- 
  read_xlsx(path = "data/je-d-15.02.02.01.03.xlsx", 
            sheet = 1, 
            col_names = c("Schulkanton", "Total", "Geschlecht_Mann", "Geschlecht_Frau", 
                          "Staatsangehörigkeit_Schweiz", "Staatsangehörigkeit_Ausland", 
                          "Staatsangehörigkeit_Unbekannt", "Charakter der Schule_Öffentlich", 
                          "Charakter der Schule_Privat subventioniert", 
                          "Charakter der Schule_Privat nicht subventioniert"), 
            trim_ws = TRUE, 
            skip = 6)

bgb_typ <- 
  read_xlsx(path = "data/je-d-15.02.02.01.02.xlsx", 
            sheet = 1, 
            col_names = c("Schulkanton", "Total", "Ausbildungsform_Vollschulisch", 
                          "Ausbildungsform_Dual", "Typ_EFZ", "Typ_EBA", 
                          "Typ_Nicht BBG-reglementierte berufliche Grundbildung"), 
            trim_ws = TRUE, 
            skip = 6)

Deskriptive Statistik

Explorative Datenanalyse

Die explorative Datenanalyse (Exploratory Data Analysis, abgekürzt EDA) ist ein wesentlicher Schritt in jedem Datenanalyseprojekt. Sie dient der Analyse und Untersuchung von Datensätzen und der deskriptiven Zusammenfassung ihrer wichtigsten Merkmale, wobei oft grafische Darstellungsmethoden verwendet werden. Mit Hilfe von Tabellen, Grafiken und der Ermittlung relevanter Kennzahlen wird versucht, einen Überblick über das gesamte Datenmaterial zu gewinnen, es zu ordnen und zusammenzufassen. Die EDA bildet damit die Grundlage für die weitere Analyse.

Objekte

Die Funktion ls() liefert eine Liste aller bisher gespeicherten Objekte wie Daten und Funktionen.

Code anzeigen
# Gespeicherte Objekte anzeigen
ls()
[1] "bgb_staat" "bgb_typ"  

Mit der Funktion rm() werden alle unerwünschten Dateien gelöscht.

Code anzeigen
# Unerwünschte Dateien entfernen
rm(bgb_typ)

Es ist auch möglich, alle Objekte auf einmal zu entfernen.

Code anzeigen
# Alle Objekte löschen
rm(list = ls())

Datentypen

Ein Datensatz kann Merkmale unterschiedlicher Datentypen enthalten. Einige Daten können Zahlen sein (z.B. Alter oder Gewicht), während andere aus Text bestehen (wie Name oder Adresse). R kennt die folgenden Haupttypen:

  • Numerisch: Zahlen, einschliesslich Ganzzahlen (ganze Zahlen) und Dezimalzahlen

  • Zeichen: Textstrings, wie Wörter oder Sätze

  • Logisch: Wahr- oder Falsch-Werte

  • Faktor: Kategoriale Daten mit definierten Stufen (z.B. Farben: rot, grün, blau).

Die Funktion class() bietet einen allgemeinen Überblick über den Datentyp, wie z.B. «numerisch» oder «Zeichen».

Code anzeigen
# Datentyp anzeigen
class(penguins$bill_length_mm)
[1] "numeric"

Die Funktion typeof() zeigt spezifischere Details innerhalb des Datentyps (beispielsweise «double» für Dezimalzahlen in «numerisch»).

Code anzeigen
# Detaillierter Datentyp anzeigen
typeof(penguins$bill_length_mm)
[1] "double"

Anfang und Ende

Mit der Funktion slice_head() werden die ersten Zeilen bzw. Beobachtungen ausgegeben. In diesem Beispiel wurde die Anzahl auf 10 festgelegt. Der Wert kann jedoch flexibel gewählt werden.

Code anzeigen
slice_head(.data = penguins, 
           n = 10)
# A tibble: 10 × 8
   species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
   <fct>   <fct>              <dbl>         <dbl>             <int>       <int>
 1 Adelie  Torgersen           39.1          18.7               181        3750
 2 Adelie  Torgersen           39.5          17.4               186        3800
 3 Adelie  Torgersen           40.3          18                 195        3250
 4 Adelie  Torgersen           NA            NA                  NA          NA
 5 Adelie  Torgersen           36.7          19.3               193        3450
 6 Adelie  Torgersen           39.3          20.6               190        3650
 7 Adelie  Torgersen           38.9          17.8               181        3625
 8 Adelie  Torgersen           39.2          19.6               195        4675
 9 Adelie  Torgersen           34.1          18.1               193        3475
10 Adelie  Torgersen           42            20.2               190        4250
# ℹ 2 more variables: sex <fct>, year <int>

Die Funktion first() gibt das erste Element eines Eingabevektors zurück.

Code anzeigen
# Erstes Datenelement ausgeben
first(x = penguins)
# A tibble: 1 × 8
  species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>   <fct>              <dbl>         <dbl>             <int>       <int>
1 Adelie  Torgersen           39.1          18.7               181        3750
# ℹ 2 more variables: sex <fct>, year <int>

Selbstverständlich ist es in R auch möglich, die letzten Zeilen eines Data Frames (dt. Datenrahmen) auszugeben. Die Funktion slice_tail() gibt die letzten n Zeilen eines Datenrahmens zurück (Standardwert ist 6).

Code anzeigen
slice_tail(.data = penguins, 
           n = 5)
# A tibble: 5 × 8
  species   island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>     <fct>           <dbl>         <dbl>             <int>       <int>
1 Chinstrap Dream            55.8          19.8               207        4000
2 Chinstrap Dream            43.5          18.1               202        3400
3 Chinstrap Dream            49.6          18.2               193        3775
4 Chinstrap Dream            50.8          19                 210        4100
5 Chinstrap Dream            50.2          18.7               198        3775
# ℹ 2 more variables: sex <fct>, year <int>

Verwenden Sie slice_tail(1), um nur die letzte Zeile zu erhalten.

Code anzeigen
slice_tail(.data = penguins, 
           n = 1)
# A tibble: 1 × 8
  species   island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>     <fct>           <dbl>         <dbl>             <int>       <int>
1 Chinstrap Dream            50.2          18.7               198        3775
# ℹ 2 more variables: sex <fct>, year <int>

Die Funktion last() ergänzt die Funktion first(), indem sie ebenfalls das letzte Element eines Vektors zurückgibt.

Code anzeigen
# Letztes Datenelement ausgeben
last(x = penguins)
# A tibble: 1 × 8
  species   island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>     <fct>           <dbl>         <dbl>             <int>       <int>
1 Chinstrap Dream            50.2          18.7               198        3775
# ℹ 2 more variables: sex <fct>, year <int>

Mit der Funktion slice() von dplyr können bestimmte Zeilen ausgewählt werden. Um die vorletzte Zeile zu bekommen, verwenden Sie n() -1.

Code anzeigen
slice(.data = penguins, 
      n() - 1)
# A tibble: 1 × 8
  species   island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>     <fct>           <dbl>         <dbl>             <int>       <int>
1 Chinstrap Dream            50.8            19               210        4100
# ℹ 2 more variables: sex <fct>, year <int>

Wenn Sie statt der ersten oder letzten Zeile eine zufällige Auswahl von Zeilen ausgeben möchten, steht Ihnen dafür die Funktion slice_sample() zur Verfügung.

Code anzeigen
slice_sample(.data = penguins, 
             n = 5)
# A tibble: 5 × 8
  species   island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>     <fct>              <dbl>         <dbl>             <int>       <int>
1 Gentoo    Biscoe              50            15.9               224        5350
2 Adelie    Biscoe              45.6          20.3               191        4600
3 Adelie    Torgersen           41.8          19.4               198        4450
4 Chinstrap Dream               49.5          19                 200        3800
5 Adelie    Biscoe              38.1          16.5               198        3825
# ℹ 2 more variables: sex <fct>, year <int>

Mit der Funktion nth() kann ein Vektorelement an einer beliebigen Stelle innerhalb des Vektors extrahiert werden. Durch Angabe des entsprechenden Elements erhalten Sie die gewünschte Ausgabe.

Code anzeigen
nth(x = penguins, 
    n = 7)
# A tibble: 1 × 8
  species island    bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>   <fct>              <dbl>         <dbl>             <int>       <int>
1 Adelie  Torgersen           38.9          17.8               181        3625
# ℹ 2 more variables: sex <fct>, year <int>

Durch das Voranstellen eines Minuszeichens vor die Position lassen sich Elemente vom Ende des Vektors abrufen.

Code anzeigen
nth(x = penguins, 
    n = -7)
# A tibble: 1 × 8
  species   island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>     <fct>           <dbl>         <dbl>             <int>       <int>
1 Chinstrap Dream            46.8          16.5               189        3650
# ℹ 2 more variables: sex <fct>, year <int>

Es ist auch möglich, nur die Namen der Spalten auszugeben.

Code anzeigen
# Spaltennamen ausgeben
names(penguins)
[1] "species"           "island"            "bill_length_mm"   
[4] "bill_depth_mm"     "flipper_length_mm" "body_mass_g"      
[7] "sex"               "year"             

Umfang

Interessieren Sie sich für den Umfang Ihres Datensatzes? Die Basisfunktion dim() liefert die Anzahl der Zeilen und Spalten.

Code anzeigen
# Umfang des Datensatzes
dim(penguins)
[1] 344   8

Sobald die Daten geladen sind, können Sie mit names() oder colnames() die Variablennamen überprüfen.

Code anzeigen
# Variablennamen prüfen
names(penguins)
[1] "species"           "island"            "bill_length_mm"   
[4] "bill_depth_mm"     "flipper_length_mm" "body_mass_g"      
[7] "sex"               "year"             

Der gesamte Datensatz kann mit der Funktion View() angezeigt werden. Die Darstellung ähnelt der von Microsoft Excel.

Code anzeigen
# Datensatz anzeigen
View(penguins)

Während View() eine Excel-ähnliche Darstellung bietet, ermöglicht die Funktion fix() das Editieren von Datenzellen vergleichbar wie in Excel.

Code anzeigen
# Datenzellen editieren
fix(penguins)

Mit glimpse() können Sie eine transponierte Version des Datenrahmens anzeigen, bei der die Spalten vertikal und die Daten horizontal dargestellt werden. glimpse() zeigt die Dimension des Datenrahmens und der zugrunde liegende Datentyp jedes Merkmals.

Code anzeigen
# Zusammenfassung der wichtigsten Kennzahlen in transponierter Form
glimpse(penguins)
Rows: 344
Columns: 8
$ species           <fct> Adelie, Adelie, Adelie, Adelie, Adelie, Adelie, Adel…
$ island            <fct> Torgersen, Torgersen, Torgersen, Torgersen, Torgerse…
$ bill_length_mm    <dbl> 39.1, 39.5, 40.3, NA, 36.7, 39.3, 38.9, 39.2, 34.1, …
$ bill_depth_mm     <dbl> 18.7, 17.4, 18.0, NA, 19.3, 20.6, 17.8, 19.6, 18.1, …
$ flipper_length_mm <dbl> 181, 186, 195, NA, 193, 190, 181, 195, 193, 190, 186…
$ body_mass_g       <dbl> 3750, 3800, 3250, NA, 3450, 3650, 3625, 4675, 3475, …
$ sex               <fct> male, female, female, NA, female, male, female, male…
$ year              <dbl> 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007, 2007…

Alternativ kann die Struktur der Daten auch mit der Funktion str() ermittelt werden.

Code anzeigen
# Datenstruktur anzeigen
str(penguins)
'data.frame':   344 obs. of  8 variables:
 $ species          : Factor w/ 3 levels "Adelie","Chinstrap",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ island           : Factor w/ 3 levels "Biscoe","Dream",..: 3 3 3 3 3 3 3 3 3 3 ...
 $ bill_length_mm   : num  39.1 39.5 40.3 NA 36.7 39.3 38.9 39.2 34.1 42 ...
 $ bill_depth_mm    : num  18.7 17.4 18 NA 19.3 20.6 17.8 19.6 18.1 20.2 ...
 $ flipper_length_mm: num  181 186 195 NA 193 190 181 195 193 190 ...
 $ body_mass_g      : num  3750 3800 3250 NA 3450 ...
 $ sex              : Factor w/ 2 levels "female","male": 2 1 1 NA 1 2 1 2 NA NA ...
 $ year             : num  2007 2007 2007 2007 2007 ...

Masse der zentralen Tendenz

Um die Verteilung der Daten besser zu verstehen, können Sie die so genannten Masse der zentralen Tendenz untersuchen, welche statistisch die Mitte der Daten beschreibt. Ziel ist es, einen typischen Wert zu finden. Gängige Methoden zur Bestimmung der Datenmitte sind:

  • Mittelwert: Ein einfacher Durchschnittswert, der berechnet wird, indem alle Werte des Stichprobensatzes addiert und dann die Gesamtsumme durch die Anzahl der Stichproben dividiert wird.

  • Median: Der Wert, der in der Mitte des Bereichs aller Stichprobenwerte liegt.

  • Modus: Der am häufigsten vorkommende Wert in der Stichprobenmenge.

Code anzeigen
mean(penguins$body_mass_g, 
     na.rm = TRUE)
[1] 4201.754
Code anzeigen
median(penguins$body_mass_g, 
       na.rm = TRUE)
[1] 4050
Code anzeigen
mfv(penguins$body_mass_g, 
    na_rm = TRUE)
[1] 3800
Code anzeigen
head(table(penguins$body_mass_g), 
     n = 10) 

2700 2850 2900 2925 2975 3000 3050 3075 3100 3150 
   1    2    4    1    1    2    4    1    1    4 

Mithilfe der Funktion colMeans() von Base R können die Mittelwerte mehrerer metrischer Vektoren gleichzeitig berechnet werden. Für die Zeilen gibt es die entsprechende Funktion rowMeans().

Code anzeigen
colMeans(x = penguins[, 3:6], 
         na.rm = TRUE)
   bill_length_mm     bill_depth_mm flipper_length_mm       body_mass_g 
         43.92193          17.15117         200.91520        4201.75439 

Apply-Familie

Schleifen sind grossartig, aber für sich wiederholende Aufgaben mit Datenstrukturen ist die Vektorisierung unschlagbar. Sie ist schneller, sauberer und ermöglicht es Ihnen, sich auf das «Was» statt auf das «Wie» Ihrer Analyse zu konzentrieren. Hier kommt die Apply-Funktion ins Spiel.

Der Mittelwert (FUN) wird mit lapply()auf die ausgewählten Spalten angewendet und als Liste zurückgegeben.

Code anzeigen
lapply(X = na.omit(penguins[, 3:6]), 
       FUN = mean)
$bill_length_mm
[1] 43.92193

$bill_depth_mm
[1] 17.15117

$flipper_length_mm
[1] 200.9152

$body_mass_g
[1] 4201.754

sapply() ist vergleichbar mit lapply(), versucht aber die Ausgabe zu vereinfachen. Sind alle Ergebnisse vom gleichen Typ (z.B. numerisch), ist die Rückgabe ein Vektor anstelle einer Liste.

Code anzeigen
sapply(X = na.omit(penguins[, 3:6]), 
       FUN = mean)
   bill_length_mm     bill_depth_mm flipper_length_mm       body_mass_g 
         43.92193          17.15117         200.91520        4201.75439 

Mit apply() wird eine eigene Funktion auf alle ausgewählten Spalten angewendet.

Code anzeigen
# Spannweite (Range) berechnen
apply(X = na.omit(penguins[, 3:6]), 
      MARGIN = 2, 
      FUN = function(every_column){max(every_column)-min(every_column)})
   bill_length_mm     bill_depth_mm flipper_length_mm       body_mass_g 
             27.5               8.4              59.0            3600.0 

Weitere Apply-Funktionen finden Sie im Abschnitt «Häufigkeitstabellen».

Streuungsmasse

Wie gross ist die Variabilität in den Daten? Zu den typischen Statistiken, welche die Variabilität messen, gehören:

  • Spannweite (Range): Die Differenz zwischen dem Maximum und Minimum. Dafür gibt es keine eigene Funktion, aber sie lässt sich leicht mit den Funktionen min() und max() berechnen. Ein anderer Ansatz ist die Verwendung der Funktion range() von Base R, welche einen Vektor zurückgibt, der das Minimum und Maximum aller angegebenen Argumente enthält. Wenn Sie diese mit diff() umschliessen, können Sie die Spannweite berechnen.

  • Interquartilsabstand (IQR): Zur Berechnung wird eine Stichprobe nach Grösse sortiert und das 25%-Quartil vom 75%-Quartil subtrahiert. In R können Sie dazu die Funktion IQR() aus dem stats-Paket verwenden. Im Gegensatz zur Spannweite können so Ausreisser, die das Ergebnis verzerren, umgangen werden.

  • Varianz: Entspricht dem Mittelwert der quadrierten Differenz zum Mittelwert. Sie können die eingebaute Funktion var() verwenden, um die Varianz zu ermitteln.

  • Standardabweichung: Entspricht der Quadratwurzel der Varianz. Sie können die integrierte Funktion sd() verwenden, um die Standardabweichung zu finden.

  • Variationskoeffizient: Dieser ist neben der Varianz und der Standardabweichung ein weiteres Streuungsmass der deskriptiven Statistik. Als relatives Streuungsmass bzw. normierte Standardabweichung hängt der Variationskoeffizient (sd() / mean()) im Gegensatz zu den beiden anderen Kennzahlen nicht von der Masseinheit der statistischen Variable ab. Der Variationskoeffizient ist jedoch nur sinnvoll für Messreihen mit ausschliesslich positiven (oder ausschliesslich negativen) Werten.

Die Position des grössten Wertes kann mit which.max() ermittelt werden. Für das Minimum gibt es das entsprechende Pendant mit which.min().

Code anzeigen
max(penguins$bill_length_mm, na.rm = TRUE)
[1] 59.6
Code anzeigen
which.max(penguins$bill_length_mm)
[1] 186

map

Durch die Verwendung der map()-Funktion des Pakets purrr können Sie viele for-Schleifen durch Code ersetzen, der sowohl kürzer als auch einfacher zu lesen ist.

Code anzeigen
# Spalten auswählen, um das Mass der Varianz zu analysieren
cols <- penguins %>% 
  select(c(bill_length_mm, bill_depth_mm)) %>% 
  drop_na()
Code anzeigen
# Eine Funktion auf jede Spalte anwenden
map(cols, function(column) {
  range <- diff(range(column)) # dasselbe wie: max(Spalte) - min(Spalte)
  var <- var(column)
  std <- sd(column)
  glue(
    '- Spannweite: {format(round(range, 2), nsmall = 2)}
    - Varianz: {format(round(var, 2), nsmall = 2)}
    - Standardabweichung: {format(round(std, 2), nsmall = 2)}',
    .sep = '\n'
  )
})
$bill_length_mm
- Spannweite: 27.50
- Varianz: 29.81
- Standardabweichung: 5.46

$bill_depth_mm
- Spannweite: 8.40
- Varianz: 3.90
- Standardabweichung: 1.97

map() bietet darüber hinaus einen konsistenten und gut lesbaren Ansatz für das Iterieren über Listen.

Code anzeigen
# Eine Funktion auf jedes Listenelement anwenden
list_1 <- list(1, 2, 3)

map(.x = list_1, .f = ~.x^2) # Alternative: map(.x = list_1, .f = function(x) x^2)
[[1]]
[1] 1

[[2]]
[1] 4

[[3]]
[1] 9

Wenn Sie über mehrere Listen gleichzeitig iterieren müssen, sind map2() und pmap() hilfreich.

Code anzeigen
# 
list_2 <- list("Waadt", "Genf", "Wallis")

map2(.x = list_1, 
     .y = list_2, 
     .f = ~paste0("Bei der Anzahl Lehrverhältnisse nimmt der Kanton ", 
                 .y, 
                 " den ", 
                 .x, 
                 ". Platz ein."))
[[1]]
[1] "Bei der Anzahl Lehrverhältnisse nimmt der Kanton Waadt den 1. Platz ein."

[[2]]
[1] "Bei der Anzahl Lehrverhältnisse nimmt der Kanton Genf den 2. Platz ein."

[[3]]
[1] "Bei der Anzahl Lehrverhältnisse nimmt der Kanton Wallis den 3. Platz ein."

quantile

Mit quantile() kann man die Streuung bzw. die Quantile einer Variablen bestimmen.

Code anzeigen
# Streuung von Variablen darstellen
quantile(penguins$bill_length_mm, na.rm = TRUE)
    0%    25%    50%    75%   100% 
32.100 39.225 44.450 48.500 59.600 

Doppelte Werte

Es ist immer möglich, dass Datensätze doppelte Einträge aufweisen. Deshalb ist es wichtig, dies zu prüfen.

Code anzeigen
# Duplikate im Datensatz prüfen
any(penguins[duplicated(penguins), ])
[1] FALSE
Code anzeigen
# Duplikate in bestimmten Spalten prüfen
any(duplicated(x = penguins$species))
[1] TRUE
Code anzeigen
# Duplikate in mehreren Spalten prüfen
any(duplicated(x = penguins[c("species", "island")]))
[1] TRUE
Code anzeigen
# NA-Werte vom Vergleich ausschliessen
# duplicated(x = penguins, incomparables = NA)

Nach der Identifizierung von Dubletten besteht der nächste Schritt oft darin, diese zu entfernen.

Code anzeigen
# Duplikate entfernen mit «duplicated»
ergebnis <- (penguins[!duplicated(penguins), ])
head(ergebnis)
  species    island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
1  Adelie Torgersen           39.1          18.7               181        3750
2  Adelie Torgersen           39.5          17.4               186        3800
3  Adelie Torgersen           40.3          18.0               195        3250
4  Adelie Torgersen             NA            NA                NA          NA
5  Adelie Torgersen           36.7          19.3               193        3450
6  Adelie Torgersen           39.3          20.6               190        3650
     sex year
1   male 2007
2 female 2007
3 female 2007
4   <NA> 2007
5 female 2007
6   male 2007
Code anzeigen
# Duplikate schnell entfernen mit «unique»
ergebnis <- unique(x = penguins)
head(ergebnis)
  species    island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
1  Adelie Torgersen           39.1          18.7               181        3750
2  Adelie Torgersen           39.5          17.4               186        3800
3  Adelie Torgersen           40.3          18.0               195        3250
4  Adelie Torgersen             NA            NA                NA          NA
5  Adelie Torgersen           36.7          19.3               193        3450
6  Adelie Torgersen           39.3          20.6               190        3650
     sex year
1   male 2007
2 female 2007
3 female 2007
4   <NA> 2007
5 female 2007
6   male 2007

Kennwerte zusammenfassen

Die Funktion summary() ermöglicht einen Überblick zu den wichtigsten Kennzahlen eines Datensatzes. Bei numerischen Merkmalen umfassen diese Minimum, 1. Quartil, Median, Mittelwert, 3. Quartil und Maximum.

Code anzeigen
# Zusammenfassung der wichtigsten Kennzahlen
summary(penguins)
      species          island    bill_length_mm  bill_depth_mm  
 Adelie   :152   Biscoe   :168   Min.   :32.10   Min.   :13.10  
 Chinstrap: 68   Dream    :124   1st Qu.:39.23   1st Qu.:15.60  
 Gentoo   :124   Torgersen: 52   Median :44.45   Median :17.30  
                                 Mean   :43.92   Mean   :17.15  
                                 3rd Qu.:48.50   3rd Qu.:18.70  
                                 Max.   :59.60   Max.   :21.50  
                                 NA's   :2       NA's   :2      
 flipper_length_mm  body_mass_g       sex           year     
 Min.   :172.0     Min.   :2700   female:165   Min.   :2007  
 1st Qu.:190.0     1st Qu.:3550   male  :168   1st Qu.:2007  
 Median :197.0     Median :4050   NA's  : 11   Median :2008  
 Mean   :200.9     Mean   :4202                Mean   :2008  
 3rd Qu.:213.0     3rd Qu.:4750                3rd Qu.:2009  
 Max.   :231.0     Max.   :6300                Max.   :2009  
 NA's   :2         NA's   :2                                 

Die Funktion describe() des Pakets psych liefert ebenfalls eine Zusammenfassung der deskriptiven Statistik. Sie enthält neben den üblichen Lagemassen auch Werte für Schiefe und Kurtosis.

Code anzeigen
describe(penguins$bill_length_mm, 
         na.rm = TRUE)
   vars   n  mean   sd median trimmed  mad  min  max range skew kurtosis  se
X1    1 342 43.92 5.46  44.45   43.91 7.04 32.1 59.6  27.5 0.05    -0.89 0.3

Mit der Funktion summarise() können beliebige Kennwerte ausgegeben werden. Beispielsweise können Sie das arithmetische Mittel (Mittelwert) und den Median einer numerischen Variablen finden.

Code anzeigen
summarise(.data = penguins, 
          "Mittelwert Gewicht" = mean(body_mass_g, na.rm = TRUE), 
          "Median Gewicht" = median(body_mass_g, na.rm = TRUE))
  Mittelwert Gewicht Median Gewicht
1           4201.754           4050

summarytools

Das R-Paket summarytools vereinfacht den Prozess der Datenexploration, indem es Funktionen bereitstellt, die mit minimalem Code umfangreiche Zusammenfassungen Ihrer Daten erzeugen.

Die Funktion dfSummary() liefert eine detaillierte Zusammenfassung, einschliesslich

  • Datentypen

  • Fehlende Werte

  • Eindeutige Werte

  • Grundlegende Statistiken

  • Grafische Darstellungen

Code anzeigen
dfSummary(x = penguins, 
          graph.col = TRUE, 
          graph.magnif = 0.75, 
          style = "grid") # %>% stview() Interaktiver HTML-Bericht
Data Frame Summary  
penguins  
Dimensions: 344 x 8  
Duplicates: 0  

+----+-------------------+--------------------------+---------------------+---------------------+----------+---------+
| No | Variable          | Stats / Values           | Freqs (% of Valid)  | Graph               | Valid    | Missing |
+====+===================+==========================+=====================+=====================+==========+=========+
| 1  | species           | 1. Adelie                | 152 (44.2%)         | IIIIIIII            | 344      | 0       |
|    | [factor]          | 2. Chinstrap             |  68 (19.8%)         | III                 | (100.0%) | (0.0%)  |
|    |                   | 3. Gentoo                | 124 (36.0%)         | IIIIIII             |          |         |
+----+-------------------+--------------------------+---------------------+---------------------+----------+---------+
| 2  | island            | 1. Biscoe                | 168 (48.8%)         | IIIIIIIII           | 344      | 0       |
|    | [factor]          | 2. Dream                 | 124 (36.0%)         | IIIIIII             | (100.0%) | (0.0%)  |
|    |                   | 3. Torgersen             |  52 (15.1%)         | III                 |          |         |
+----+-------------------+--------------------------+---------------------+---------------------+----------+---------+
| 3  | bill_length_mm    | Mean (sd) : 43.9 (5.5)   | 164 distinct values |     .     . :       | 342      | 2       |
|    | [numeric]         | min < med < max:         |                     |   . : : : : :       | (99.4%)  | (0.6%)  |
|    |                   | 32.1 < 44.5 < 59.6       |                     |   : : : : : :       |          |         |
|    |                   | IQR (CV) : 9.3 (0.1)     |                     |   : : : : : : .     |          |         |
|    |                   |                          |                     | : : : : : : : : .   |          |         |
+----+-------------------+--------------------------+---------------------+---------------------+----------+---------+
| 4  | bill_depth_mm     | Mean (sd) : 17.2 (2)     | 80 distinct values  |           :         | 342      | 2       |
|    | [numeric]         | min < med < max:         |                     |         : :         | (99.4%)  | (0.6%)  |
|    |                   | 13.1 < 17.3 < 21.5       |                     |   : . : : : .       |          |         |
|    |                   | IQR (CV) : 3.1 (0.1)     |                     | . : : : : : :       |          |         |
|    |                   |                          |                     | : : : : : : : . .   |          |         |
+----+-------------------+--------------------------+---------------------+---------------------+----------+---------+
| 5  | flipper_length_mm | Mean (sd) : 200.9 (14.1) | 55 distinct values  |       :             | 342      | 2       |
|    | [numeric]         | min < med < max:         |                     |     . :             | (99.4%)  | (0.6%)  |
|    |                   | 172 < 197 < 231          |                     |     : : :   . .     |          |         |
|    |                   | IQR (CV) : 23 (0.1)      |                     |   . : : :   : : :   |          |         |
|    |                   |                          |                     |   : : : : : : : : : |          |         |
+----+-------------------+--------------------------+---------------------+---------------------+----------+---------+
| 6  | body_mass_g       | Mean (sd) : 4201.8 (802) | 94 distinct values  |     :               | 342      | 2       |
|    | [numeric]         | min < med < max:         |                     |   . :               | (99.4%)  | (0.6%)  |
|    |                   | 2700 < 4050 < 6300       |                     |   : : : :           |          |         |
|    |                   | IQR (CV) : 1200 (0.2)    |                     |   : : : : : .       |          |         |
|    |                   |                          |                     | . : : : : : :       |          |         |
+----+-------------------+--------------------------+---------------------+---------------------+----------+---------+
| 7  | sex               | 1. female                | 165 (49.5%)         | IIIIIIIII           | 333      | 11      |
|    | [factor]          | 2. male                  | 168 (50.5%)         | IIIIIIIIII          | (96.8%)  | (3.2%)  |
+----+-------------------+--------------------------+---------------------+---------------------+----------+---------+
| 8  | year              | Mean (sd) : 2008 (0.8)   | 2007 : 110 (32.0%)  | IIIIII              | 344      | 0       |
|    | [numeric]         | min < med < max:         | 2008 : 114 (33.1%)  | IIIIII              | (100.0%) | (0.0%)  |
|    |                   | 2007 < 2008 < 2009       | 2009 : 120 (34.9%)  | IIIIII              |          |         |
|    |                   | IQR (CV) : 2 (0)         |                     |                     |          |         |
+----+-------------------+--------------------------+---------------------+---------------------+----------+---------+

Verwenden Sie die Funktion descr(), um detaillierte deskriptive Statistiken für Ihre numerischen Variablen zu erhalten. Sie können auswählen, welche Statistiken generiert werden sollen (z.B. «common», «fivenum», usw.).

Code anzeigen
descr(x = penguins, 
      stats = "fivenum")
Non-numerical variable(s) ignored: species, island, sex
Descriptive Statistics  
penguins  
N: 344  

               bill_depth_mm   bill_length_mm   body_mass_g   flipper_length_mm      year
------------ --------------- ---------------- ------------- ------------------- ---------
         Min           13.10            32.10       2700.00              172.00   2007.00
          Q1           15.60            39.20       3550.00              190.00   2007.00
      Median           17.30            44.45       4050.00              197.00   2008.00
          Q3           18.70            48.50       4750.00              213.00   2009.00
         Max           21.50            59.60       6300.00              231.00   2009.00

Für kategoriale Variablen erzeugt die Funktion freq() Häufigkeitstabellen, welche die Verteilung der Kategorien zeigen. Dies kann Ihnen helfen, die Verteilung und Häufigkeit jeder Kategorie in Ihren Daten zu verstehen.

Code anzeigen
# Häufigkeitsstatistik
freq(x = penguins)
Variable(s) ignored: bill_length_mm, bill_depth_mm, flipper_length_mm, body_mass_g
Frequencies  
penguins$species  
Type: Factor  

                  Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
--------------- ------ --------- -------------- --------- --------------
         Adelie    152     44.19          44.19     44.19          44.19
      Chinstrap     68     19.77          63.95     19.77          63.95
         Gentoo    124     36.05         100.00     36.05         100.00
           <NA>      0                               0.00         100.00
          Total    344    100.00         100.00    100.00         100.00

penguins$island  
Type: Factor  

                  Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
--------------- ------ --------- -------------- --------- --------------
         Biscoe    168     48.84          48.84     48.84          48.84
          Dream    124     36.05          84.88     36.05          84.88
      Torgersen     52     15.12         100.00     15.12         100.00
           <NA>      0                               0.00         100.00
          Total    344    100.00         100.00    100.00         100.00

penguins$sex  
Type: Factor  

               Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
------------ ------ --------- -------------- --------- --------------
      female    165     49.55          49.55     47.97          47.97
        male    168     50.45         100.00     48.84          96.80
        <NA>     11                               3.20         100.00
       Total    344    100.00         100.00    100.00         100.00

penguins$year  
Type: Numeric  

              Freq   % Valid   % Valid Cum.   % Total   % Total Cum.
----------- ------ --------- -------------- --------- --------------
       2007    110     31.98          31.98     31.98          31.98
       2008    114     33.14          65.12     33.14          65.12
       2009    120     34.88         100.00     34.88         100.00
       <NA>      0                               0.00         100.00
      Total    344    100.00         100.00    100.00         100.00

Die explorative Datenanalyse (EDA) ist entscheidend, um Ihre Daten zu verstehen, Trends zu erkennen und Probleme aufzuspüren, bevor Sie ausführlichere Analysen durchführen. Ohne die richtigen Werkzeuge kann EDA jedoch zeitaufwendig sein. Mit dem DataExplorer steht Ihnen eine schnellere und effizientere Methode zur Verfügung, um Ihre Daten zu analysieren und statistische Kennwerte zusammenzufassen.

skimr

Die Kernfunktion von skimr ist skim(), die für die Arbeit mit (gruppierten) Datenrahmen entwickelt wurde. Wie summary() zeigt skim() Statistiken bzw. Ergebnisse für jede Spalte.

Code anzeigen
# Zusammenfassung der wichtigsten Kennzahlen und fehlenden Werte
skim(penguins)
Data summary
Name penguins
Number of rows 344
Number of columns 8
_______________________
Column type frequency:
factor 3
numeric 5
________________________
Group variables None

Variable type: factor

skim_variable n_missing complete_rate ordered n_unique top_counts
species 0 1.00 FALSE 3 Ade: 152, Gen: 124, Chi: 68
island 0 1.00 FALSE 3 Bis: 168, Dre: 124, Tor: 52
sex 11 0.97 FALSE 2 mal: 168, fem: 165

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
bill_length_mm 2 0.99 43.92 5.46 32.1 39.23 44.45 48.5 59.6 ▃▇▇▆▁
bill_depth_mm 2 0.99 17.15 1.97 13.1 15.60 17.30 18.7 21.5 ▅▅▇▇▂
flipper_length_mm 2 0.99 200.92 14.06 172.0 190.00 197.00 213.0 231.0 ▂▇▃▅▂
body_mass_g 2 0.99 4201.75 801.95 2700.0 3550.00 4050.00 4750.0 6300.0 ▃▇▆▃▂
year 0 1.00 2008.03 0.82 2007.0 2007.00 2008.00 2009.0 2009.0 ▇▁▇▁▇

GWalkR

Ein neuer Ansatz zur explorativen Datenanalyse in R ist das Paket «GWalkR». Es kombiniert das Paket «htmlwidgets» mit der JavaScript-Bibliothek «Graphic Walker» und verwandelt so den Datenrahmen in eine Tableau-ähnliche Drag&Drop-Benutzeroberfläche. Für alle, die bereits mit Datenvisualisierungssoftware wie Microsoft Power BI oder Tableau gearbeitet haben, bietet GWalkR einen intuitiven Einstieg in die Datenanalyse mit R.

Weitere Pakete

Weitere umfassende und teilweise interaktive Einblicke in importierte Datensätze liefern die nachfolgenden Pakete. Diese bieten unter anderem auch eine erste gute Zusammenfassung der fehlenden Werte (n_missing).

  • esquisse: RStudio-Add-In für interaktive Datenvisualisierung

  • radiant: Browserbasierte Schnittstelle für Analysen in R, basierend auf dem shiny-Paket

  • explore: Vereinfacht die explorative Datenanalyse für bivariate Analysen

  • dataxray: Interaktive Tabellenschnittstelle für Zusammenfassungen von Daten

Häufigkeitstabellen

table

Die Arbeit mit Häufigkeitstabellen ist eine typische Aufgabe in der Datenanalyse. R bietet hierfür mehrere Möglichkeiten. Wenn Sie z.B. wissen möchten, wie viele Pinguine auf den drei Inseln untersucht wurden, können Sie die Funktion table() verwenden. Den prozentualen Anteil erhält man mit prop.table().

Code anzeigen
# Tabelle ausgeben
table(penguins$island)

   Biscoe     Dream Torgersen 
      168       124        52 
Code anzeigen
# Prozentwerte ausgeben
round(x = prop.table(table(penguins$island)) * 100, 
      digits = 2)

   Biscoe     Dream Torgersen 
    48.84     36.05     15.12 

Mit den Argumenten margin = 1 oder margin = 2 können die relativen Zeilen- oder Spaltenprozentsätze berechnet werden.

Code anzeigen
# Prozentwerte pro Zeile
round(x = prop.table(table(penguins$species, 
                           penguins$island), 
                     margin = 1) * 100, 
      digits = 2)
           
            Biscoe  Dream Torgersen
  Adelie     28.95  36.84     34.21
  Chinstrap   0.00 100.00      0.00
  Gentoo    100.00   0.00      0.00
Code anzeigen
# Prozentwerte pro Spalte
round(x = prop.table(table(penguins$species, 
                           penguins$island), 
                     margin = 2) * 100, 
      digits = 2)
           
            Biscoe  Dream Torgersen
  Adelie     26.19  45.16    100.00
  Chinstrap   0.00  54.84      0.00
  Gentoo     73.81   0.00      0.00

Die Funktion addmargins() fügt die Randsummen hinzu.

Code anzeigen
# Randsummen ausgeben
addmargins(table(penguins$species, 
                 penguins$island))
           
            Biscoe Dream Torgersen Sum
  Adelie        44    56        52 152
  Chinstrap      0    68         0  68
  Gentoo       124     0         0 124
  Sum          168   124        52 344

Manchmal ist es sinnvoll, die Tabelle zu transponieren (Spalten und Zeilen zu tauschen).

Code anzeigen
table(penguins$species, 
      penguins$sex)
           
            female male
  Adelie        73   73
  Chinstrap     34   34
  Gentoo        58   61
Code anzeigen
# Transponierte Tabelle
t(table(penguins$species, 
        penguins$sex))
        
         Adelie Chinstrap Gentoo
  female     73        34     58
  male       73        34     61

count

Die Ausgabe der Absolutwerte ist auch mit Hilfe der Funktion count() möglich.

Code anzeigen
count(x = penguins, 
      species, 
      island, 
      sort = TRUE)
    species    island   n
1    Gentoo    Biscoe 124
2 Chinstrap     Dream  68
3    Adelie     Dream  56
4    Adelie Torgersen  52
5    Adelie    Biscoe  44

xtabs

Die Funktion xtabs() bietet eine flexible und leistungsstarke Möglichkeit, Häufigkeits- und Summentabellen in R zu erstellen. Dank ihrer Formelschnittstelle ist sie besonders praktisch bei der Arbeit mit Datenrahmen. Für komplexere Aggregationen wie Mittelwerte oder Mediane muss sie jedoch mit anderen Funktionen, wie z.B. wie ftable(), kombiniert werden.

Ein grosser Vorteil von xtabs() gegenüber table() ist, dass die Funktion gut mit Datenrahmen zusammenarbeitet. Es ist nicht nötig, einzelne Spalten zu extrahieren.

Code anzeigen
# Häufigkeitstabelle
xtabs(formula = ~ species + sex, # Variablen rechts von ~, um Häufigkeiten zu zählen
      data = penguins, 
      na.action = na.pass) # Standardwert; NA mit Wert 0 in Tabelle aufnehmen
           sex
species     female male
  Adelie        73   73
  Chinstrap     34   34
  Gentoo        58   61
Code anzeigen
# Tabelle mit mehreren Dimensionen
by(data = penguins, INDICES = penguins$island, FUN = function(subset) {
  xtabs(formula = ~ species + sex, 
        data = subset)
})
penguins$island: Biscoe
           sex
species     female male
  Adelie        22   22
  Chinstrap      0    0
  Gentoo        58   61
------------------------------------------------------------ 
penguins$island: Dream
           sex
species     female male
  Adelie        27   28
  Chinstrap     34   34
  Gentoo         0    0
------------------------------------------------------------ 
penguins$island: Torgersen
           sex
species     female male
  Adelie        24   23
  Chinstrap      0    0
  Gentoo         0    0

Manchmal müssen Sie nicht nur Häufigkeiten zählen, sondern auch Werte summieren. Setzen Sie dazu eine numerische Variable auf die linke Seite der Formel.

Code anzeigen
# Summentabelle
print("Summierte Schnabellänge pro Pinguinart")
[1] "Summierte Schnabellänge pro Pinguinart"
Code anzeigen
xtabs(formula = bill_length_mm ~ species, 
      data = penguins, 
      na.rm = TRUE)
species
   Adelie Chinstrap    Gentoo 
   5857.5    3320.7    5843.1 

Grafische Darstellung

Grafische Darstellungen ermöglichen eine schnelle und einfache Interpretation von Daten, indem sie Trends und Muster visuell hervorheben. Zudem bieten sie einen klaren Überblick über grosse Datenmengen und erleichtern es, wichtige Informationen auf einen Blick zu erfassen. Sie unterstützen die effektive Kommunikation komplexer Daten, was besonders in Präsentationen und Berichten nützlich ist.

Die Funktion colors() gibt einen Vektor zurück, der alle in R eingebauten Farbnamen in alphabetischer Reihenfolge enthält, wobei das erste Element «white» ist.

Code anzeigen
head(colors(), n = 20)
 [1] "white"         "aliceblue"     "antiquewhite"  "antiquewhite1"
 [5] "antiquewhite2" "antiquewhite3" "antiquewhite4" "aquamarine"   
 [9] "aquamarine1"   "aquamarine2"   "aquamarine3"   "aquamarine4"  
[13] "azure"         "azure1"        "azure2"        "azure3"       
[17] "azure4"        "beige"         "bisque"        "bisque1"      

Säulendiagramm

Das Säulendiagramm dient dazu, die Werte unterschiedlicher Kategorien oder Gruppen gegenüberzustellen. Auf der x-Achse sind die Kategorien oder Gruppen dargestellt, während die y-Achse die entsprechenden Werte anzeigt.

Code anzeigen
# Nominalskalierte (kategoriale) oder metrische Variable
plot(penguins$species, 
     col = "grey", 
     border = NA, 
     ylim = c(0, 200))

Code anzeigen
# Häufigkeitstabellen mit der Plotfunktion von Base R darstellen
barplot(table(penguins$species), 
        col = "grey", 
        border = NA, 
        main = "Häufigkeitstabelle", 
        ylim = c(0, 200))

Code anzeigen
# Gruppiertes Säulendiagramm
barplot(prop.table(table(penguins$species, 
                         penguins$sex), 
                   margin = 2), 
        legend.text = TRUE, 
        beside = TRUE, 
        xlim = c(0, 11), 
        ylim = c(0, 0.5))

Code anzeigen
# Mittlere Schnabellänge für die drei Pinguinarten berechnen
mittlere_schnabellaenge <- 
  tapply(X = penguins$bill_length_mm, 
         INDEX = penguins$species, 
         FUN = mean, na.rm = TRUE)

# Säulen mit unterschiedlichen Farben
barplot(mittlere_schnabellaenge, 
        col = c("#9FC131", "#93257B", "#57AF2C"), 
        ylim = c(0, 50))

Histogramm

Ein Histogramm dient zur Darstellung der Verteilung kontinuierlicher Daten, wie beispielsweise Mess- oder Zeitdaten. Auf der x-Achse werden die Werte des Datensatzes abgebildet, während die y-Achse die Häufigkeit zeigt, d.h. wie oft jeder Wert im Datensatz vorkommt.

Code anzeigen
hist(x = penguins$body_mass_g, 
     breaks = 20, 
     col = "grey", 
     border = "white", 
     main = "Gewichtsverteilung der Pinguine", 
     xlim = c(2000, 7000), 
     ylim = c(0, 50), 
     xlab = "Gewicht in Gramm", 
     ylab = "Häufigkeit")

Dichteplot

Der Dichteplot ist eine grafische Darstellung der Verteilung einer numerischen Variablen und verwendet die Kerndichteschätzung, um eine glatte Kurve zu erzeugen. Dies ermöglicht eine kontinuierliche und detaillierte Ansicht der Datenverteilung im Vergleich zu einem Histogramm.

Code anzeigen
options(scipen = 999)

plot(density(x = penguins$body_mass_g, 
             na.rm = TRUE))

Boxplot

Ein Boxplot, auch Box-and-Whisker-Plot genannt, ist ein Diagramm zur grafischen Darstellung von Datenverteilungen. Er zeigt den Median, die Quartile und mögliche Ausreisser, wodurch man schnell einen Überblick über die Verteilung und Streuung der Daten erhält.

Code anzeigen
boxplot(penguins$body_mass_g ~ penguins$species)

Code anzeigen
boxplot(penguins$bill_length_mm, 
        penguins$bill_depth_mm, 
        names = c("Schnabellänge", "Schnabeltiefe"))

Streudiagramm

Das Streudiagramm, auch Scatterplot genannt, ist ein Diagramm, das die Beziehung zwischen zwei Variablen darstellt. Jeder Punkt im Diagramm repräsentiert ein Datenpaar, wodurch Muster, Trends oder Korrelationen zwischen den Variablen sichtbar werden.

Code anzeigen
plot(penguins$bill_depth_mm, penguins$bill_length_mm, 
     main = "Gegenüberstellung von Schnabeltiefe und Schnabellänge")

Streumatrix

Die Funktion pairs.panels() erstellt eine Streumatrix, welche die paarweisen Beziehungen zwischen mehreren Variablen in einem Datensatz darstellt. Jede Zelle der Matrix zeigt ein Streudiagramm für ein Variablenpaar, was es ermöglicht, Muster und Korrelationen zwischen allen Variablen gleichzeitig zu erkennen.

Code anzeigen
pairs.panels(x = penguins[3:6], 
             pch = 21, 
             hist.col = "#93257B", 
             line.col = "#9FC131")

Ein Streumatrixdiagramm, bestehend aus Histogrammen und Trendlinien, können Sie auch mit der Funktion pairs() erstellen und so Zusammenhänge sichtbar machen.

Code anzeigen
pairs(x = penguins[3:6], 
      main = "Streumatrix", 
      panel = panel.smooth,
      cex = 1, 
      pch = 21, 
      bg = "#9FC131",
      diag.panel = panel_hist, 
      cex.labels = 1.5, 
      font.labels = 2)

Die Funktion ggpairs() aus dem Paket GGally visualisiert ebenfalls paarweise Beziehungen.

Datenaufbereitung

Daten bereinigen

Die Bedeutung der Datenbereinigung wird häufig unterschätzt. Dabei ist sie ein grundlegender Schritt für eine erfolgreiche Datenanalyse. In vielen Fachportalen und Artikeln wird darauf hingewiesen, dass die Datenbereinigung nach dem Pareto-Prinzip ca. 80% der Zeit einer Datenanalyse in Anspruch nimmt und die eigentliche Analyse nur 20%.

Nachdem Sie Ihre Rohdaten importiert und sich einen ersten Überblick verschafft haben, ist es immer eine gute Idee, diese zu bereinigen. Dadurch werden Fehler und andere Probleme reduziert. Dabei werden fehlerhafte Datenpunkte entfernt oder die Daten in ein nützlicheres Format konvertiert. In anderen Situationen können Datenpunkte, die deutlich ausserhalb des erwarteten Bereichs liegen, auch Ausreisser genannt, manchmal aus Analysen entfernt werden. Dies sollte jedoch sorgfältig geprüft werden, um sicherzustellen, dass keine Datenpunkte gelöscht werden, die echte Informationen liefern.

janitor

Bestehende Spaltennamen sind oftmals intuitiv und leicht verständlich, aber nicht unbedingt einfach im Code zu handhaben. Mit der Funktion clean_names() aus dem Paket janitor können Sie Spaltennamen mühelos bereinigen. Sie können wählen, ob Sie alle Namen in Snake Case (alle Wörter klein geschriebenen, getrennt durch Unterstriche), Variationen von Camel Case (Grossbuchstaben zwischen den Wörtern), Title Case oder andere Stile ändern möchten. Weiter werden Leerzeichen in _ umgewandelt und Klammern entfernt. Auf diese Weise sind die Spaltenbezeichnungen leicht verständlich und gut im Code zu verarbeiten.

Datensätze mit leeren oder überflüssigen Zeilen oder Spalten sind keine Seltenheit. Dies gilt insbesondere für Excel-Dateien, die viele leere Zellen enthalten. Diese können mit der Funktion remove_empty() entfernt werden. Ohne Argument werden standardmässig sowohl Zeilen als auch Spalten mit remove_empty() gelöscht. Das kann man anpassen, indem man z.B. which = «rows» oder which = «cols» verwendet.

Code anzeigen
bgb_typ_clean <- bgb_typ %>% 
  clean_names() %>% 
  remove_empty()
value for "which" not specified, defaulting to c("rows", "cols")
Code anzeigen
# Numerische Vektoren transformieren
bgb_typ_clean <- bgb_typ_clean %>% 
  subset(select = total:typ_nicht_bbg_reglementierte_berufliche_grundbildung) %>% 
  mutate(across(where(is.character), as.numeric)) %>% 
  cbind(bgb_typ_clean$schulkanton) %>% 
  rename(schulkanton = 'bgb_typ_clean$schulkanton')

Spalten, die in jeder Zeile denselben Wert enthalten, werden mit remove_constant() entfernt.

Die Funktion round_half_up() kann zum Runden von Werten auf ganze Zahlen verwendet werden.

Code anzeigen
round_half_up(x = penguins$bill_depth_mm, digits = 0) %>% 
  head(n = 10)
 [1] 19 17 18 NA 19 21 18 20 18 20

round_to_fraction() wird verwendet, um auf einen beliebigen Bruch zu runden. Im Beispiel unten wurden die Zahlen auf die nächsten Viertel gerundet (Nenner = 4).

Code anzeigen
round_to_fraction(x = penguins$bill_depth_mm, denominator = 4) %>% 
  head(n = 10)
 [1] 18.75 17.50 18.00    NA 19.25 20.50 17.75 19.50 18.00 20.25

Verzerrung (Bias)

Ein weiteres häufiges Problem bei realen Daten sind Verzerrungen (Bias). «Verzerrung» bezieht sich auf eine menschliche Neigung, bestimmte Arten von Werten häufiger als andere auszuwählen, und zwar auf eine Weise, welche die zugrunde liegende Gesamtheit (Population) der «realen Welt» fehlerhaft darstellt. Verzerrungen lassen sich manchmal identifizieren und verhindern, indem Sie sich bei der Untersuchung von Daten vor Augen halten, woher diese stammen.

Pipe-Operator

R ist eine funktionale Sprache, was bedeutet, dass der Code oft viele Klammern enthält. Bei komplexem Code bedeutet dies, dass diese Klammern ineinander verschachtelt werden müssen. Dadurch ist der R-Code schwer zu lesen und zu verstehen. Hier kommt der Pipe-Operator ins Spiel.

Pipe ist ein Infix-Operator, der im Paket magrittr (Bestandteil von tidyverse) von Stefan Milton Bache eingeführt wurde. Er wird verwendet, um die Ausgabe einer Funktion als Eingabe an eine andere Funktion weiterzuleiten, was den Code im Idealfall leicht lesbar und effizient macht. Mit anderen Worten: Der Pipe-Operator %>% wird verwendet, um eine Folge von mehreren Operationen auf elegante Weise auszudrücken und die Abläufe intuitiver zu gestalten.

Code anzeigen
penguins %>% 
  filter(body_mass_g == 2900)
    species    island bill_length_mm bill_depth_mm flipper_length_mm
1    Adelie    Biscoe           34.5          18.1               187
2    Adelie     Dream           33.1          16.1               178
3    Adelie Torgersen           38.6          17.0               188
4 Chinstrap     Dream           43.2          16.6               187
  body_mass_g    sex year
1        2900 female 2008
2        2900 female 2008
3        2900 female 2009
4        2900 female 2007

Der Pipe-Operator kann wie folgt als Arbeitsanweisung formuliert werden: «Nehmen Sie den Datensatz «penguins» UND DANN filtern Sie nach Gewicht ist gleich 2850g.»

Fehlende Werte finden

Der Umgang mit fehlenden Daten ist eine häufige Herausforderung bei der Datenanalyse und bei Projekten des maschinellen Lernens. In R werden fehlende Werte mit NA (englische Abkürzung für «Not Available») gekennzeichnet. Bei der Arbeit mit Datensätzen ist es wichtig, NA-Werte zu identifizieren und angemessen zu behandeln, um eine verzerrte Analyse oder falsche Ergebnisse zu vermeiden.

Code anzeigen
# Gibt den Wert TRUE (wahr) oder FALSE (falsch) zurück
anyNA(penguins)
[1] TRUE
Code anzeigen
# NA-Werte finden
is.na(penguins_weight)
 [1] FALSE FALSE FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE

Die Anzahl der fehlenden Werte für einzelne Spalten wird mit der Funktion sum() berechnet.

Code anzeigen
sum(is.na(penguins$bill_length_mm) == TRUE)
[1] 2

Eine andere, intuitivere Methode ist, die Summe der fehlenden Werte für jede Spalte zu ermitteln. is.na(df) erzeugt eine logische Matrix, welche die NA-Positionen im Datenrahmen angibt. Die Funktion colSums() summiert dann die TRUE-Werte (die NA repräsentieren) in jeder Spalte und gibt die Anzahl der fehlenden Werte pro Spalte zurück.

Code anzeigen
# Summe der NA-Werte pro Spalte
colSums(is.na(penguins))
          species            island    bill_length_mm     bill_depth_mm 
                0                 0                 2                 2 
flipper_length_mm       body_mass_g               sex              year 
                2                 2                11                 0 

summarise_all() wendet die Funktion sum(is.na(.)) auf jede Spalte an (der Punkt steht hier für jede Spalte) und gibt die Anzahl der NA-Werte für jede Spalte zurück.

Code anzeigen
penguins %>% 
  summarise_all(~ sum(is.na(.)))
  species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex
1       0      0              2             2                 2           2  11
  year
1    0

Die Funktion which() hilft herauszufinden, welche Zeilen fehlende Werte enthalten.

Code anzeigen
which(x = is.na(penguins$bill_length_mm) == TRUE)
[1]   4 272

Sie können die Summe der fehlenden Werte auch für alle Zeilen berechnen. Dies kann bei kleinen Datensätzen nützlich sein.

Code anzeigen
penguins %>% 
  filter(rowSums(is.na(.)) > 0)
   species    island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
1   Adelie Torgersen             NA            NA                NA          NA
2   Adelie Torgersen           34.1          18.1               193        3475
3   Adelie Torgersen           42.0          20.2               190        4250
4   Adelie Torgersen           37.8          17.1               186        3300
5   Adelie Torgersen           37.8          17.3               180        3700
6   Adelie     Dream           37.5          18.9               179        2975
7   Gentoo    Biscoe           44.5          14.3               216        4100
8   Gentoo    Biscoe           46.2          14.4               214        4650
9   Gentoo    Biscoe           47.3          13.8               216        4725
10  Gentoo    Biscoe           44.5          15.7               217        4875
11  Gentoo    Biscoe             NA            NA                NA          NA
    sex year
1  <NA> 2007
2  <NA> 2007
3  <NA> 2007
4  <NA> 2007
5  <NA> 2007
6  <NA> 2007
7  <NA> 2007
8  <NA> 2008
9  <NA> 2009
10 <NA> 2009
11 <NA> 2009

Eine weitere Variante besteht darin, die fehlenden Zeilen mit der Funktion everything() zu filtern.

Code anzeigen
penguins %>% 
  filter(if_any(everything(), is.na))
   species    island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
1   Adelie Torgersen             NA            NA                NA          NA
2   Adelie Torgersen           34.1          18.1               193        3475
3   Adelie Torgersen           42.0          20.2               190        4250
4   Adelie Torgersen           37.8          17.1               186        3300
5   Adelie Torgersen           37.8          17.3               180        3700
6   Adelie     Dream           37.5          18.9               179        2975
7   Gentoo    Biscoe           44.5          14.3               216        4100
8   Gentoo    Biscoe           46.2          14.4               214        4650
9   Gentoo    Biscoe           47.3          13.8               216        4725
10  Gentoo    Biscoe           44.5          15.7               217        4875
11  Gentoo    Biscoe             NA            NA                NA          NA
    sex year
1  <NA> 2007
2  <NA> 2007
3  <NA> 2007
4  <NA> 2007
5  <NA> 2007
6  <NA> 2007
7  <NA> 2007
8  <NA> 2008
9  <NA> 2009
10 <NA> 2009
11 <NA> 2009

Ein anderer Ansatz zur Auswahl von Zeilen mit NA-Werten bzw. ohne NA ist die Verwendung der Funktion complete.cases().

Code anzeigen
# NA-Werte anzeigen
penguins[!complete.cases(penguins), ]
    species    island bill_length_mm bill_depth_mm flipper_length_mm
4    Adelie Torgersen             NA            NA                NA
9    Adelie Torgersen           34.1          18.1               193
10   Adelie Torgersen           42.0          20.2               190
11   Adelie Torgersen           37.8          17.1               186
12   Adelie Torgersen           37.8          17.3               180
48   Adelie     Dream           37.5          18.9               179
179  Gentoo    Biscoe           44.5          14.3               216
219  Gentoo    Biscoe           46.2          14.4               214
257  Gentoo    Biscoe           47.3          13.8               216
269  Gentoo    Biscoe           44.5          15.7               217
272  Gentoo    Biscoe             NA            NA                NA
    body_mass_g  sex year
4            NA <NA> 2007
9          3475 <NA> 2007
10         4250 <NA> 2007
11         3300 <NA> 2007
12         3700 <NA> 2007
48         2975 <NA> 2007
179        4100 <NA> 2007
219        4650 <NA> 2008
257        4725 <NA> 2009
269        4875 <NA> 2009
272          NA <NA> 2009

naniar

Die Funktion vis_miss() aus dem naniar-Paket visualisiert das Muster der fehlenden Daten in Ihrem Datensatz und erleichtert so die Entscheidung, wie mit fehlenden Daten umzugehen ist.

Fehlende Werte ersetzen

In R stehen für das Ersetzen von Werten und Löschen von Zeilen verschiedene Funktionen aus den Paketen tidyr und dplyr zur Verfügung. Beide Pakete sind in tidyverse enthalten.

Der Entscheid, ob fehlende Werte ersetzt oder die betroffenen Zeilen gelöscht werden, ist in erster Linie vom vorliegenden Datensatz abhängig. Bei umfangreichen Datensätzen ist ein Löschen von Zeilen weniger problematisch als bei solchen mit nur wenigen Beobachtungen.

Fehlende numerische Werte können durch die Lageparameter arithmetisches Mittel und Median der Variable oder durch die Zahl 0 ersetzt werden. Es ist für jede Spalte einzeln zu prüfen, welches Vorgehen sinnvoll ist.

Fehlende Werte durch Mittelwert ersetzen

Manchmal sagt ein Bild mehr als tausend Worte. Wenn Datenwissenschaftler eine Variable untersuchen (z.B. eine Stichprobe des Gewichts von Pinguinen), sind sie besonders an der Verteilung der Variable interessiert. Das heisst, sie wollen wissen, wie die verschiedenen Werte in der Stichprobe verteilt sind. Der Ausgangspunkt für diese Untersuchung ist oft die Visualisierung der Daten in Form eines Histogramms, um zu prüfen, wie häufig jeder Variablenwert auftritt.

Code anzeigen
hist(penguins$body_mass_g, 
     breaks = 10)

Code anzeigen
mean_weight <- mean(penguins$body_mass_g, na.rm = TRUE)
median_weight <- median(penguins$body_mass_g, na.rm = TRUE)
# Das Argument na.rm = TRUE wird ergänzt, um fehlende Werte für die Berechnung auszuschliessen.
cat("Mittelwert:", mean_weight, "\nMedian:", median_weight)
Mittelwert: 4201.754 
Median: 4050

Das Erstellen und Modifizieren von Spalten übernimmt die Funktion mutate() aus dem Paket dplyr. Die allgemeine Struktur für das Hinzufügen oder Ändern von Spalten ist im Grunde dieselbe wie beim Filtern.

df %>% mutate(neuer_spaltenname = was_sie_beinhaltet)

Code anzeigen
head(penguins)
  species    island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
1  Adelie Torgersen           39.1          18.7               181        3750
2  Adelie Torgersen           39.5          17.4               186        3800
3  Adelie Torgersen           40.3          18.0               195        3250
4  Adelie Torgersen             NA            NA                NA          NA
5  Adelie Torgersen           36.7          19.3               193        3450
6  Adelie Torgersen           39.3          20.6               190        3650
     sex year
1   male 2007
2 female 2007
3 female 2007
4   <NA> 2007
5 female 2007
6   male 2007
Code anzeigen
penguins_mean <- penguins %>% 
  mutate(body_mass_g = replace_na(as.numeric(body_mass_g), mean(body_mass_g, na.rm = TRUE)))

head(penguins_mean)
  species    island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
1  Adelie Torgersen           39.1          18.7               181    3750.000
2  Adelie Torgersen           39.5          17.4               186    3800.000
3  Adelie Torgersen           40.3          18.0               195    3250.000
4  Adelie Torgersen             NA            NA                NA    4201.754
5  Adelie Torgersen           36.7          19.3               193    3450.000
6  Adelie Torgersen           39.3          20.6               190    3650.000
     sex year
1   male 2007
2 female 2007
3 female 2007
4   <NA> 2007
5 female 2007
6   male 2007

Fehlende Werte durch Median ersetzen

Alternativ zum Mittelwert können die fehlenden Werte durch den Median der Variable «Age» ersetzt werden.

Code anzeigen
penguins_median <- penguins %>% 
  mutate(body_mass_g = replace_na(as.numeric(body_mass_g), median(body_mass_g, na.rm = TRUE)))

head(penguins_median)
  species    island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
1  Adelie Torgersen           39.1          18.7               181        3750
2  Adelie Torgersen           39.5          17.4               186        3800
3  Adelie Torgersen           40.3          18.0               195        3250
4  Adelie Torgersen             NA            NA                NA        4050
5  Adelie Torgersen           36.7          19.3               193        3450
6  Adelie Torgersen           39.3          20.6               190        3650
     sex year
1   male 2007
2 female 2007
3 female 2007
4   <NA> 2007
5 female 2007
6   male 2007

Fehlende Werte durch Wert 0 ersetzen

Fehlende Werte können Sie folgendermassen durch den Wert 0 ersetzen:

Code anzeigen
penguins_0 <- penguins %>% 
  mutate(body_mass_g = replace_na(body_mass_g, 0))

head(penguins_0)
  species    island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
1  Adelie Torgersen           39.1          18.7               181        3750
2  Adelie Torgersen           39.5          17.4               186        3800
3  Adelie Torgersen           40.3          18.0               195        3250
4  Adelie Torgersen             NA            NA                NA           0
5  Adelie Torgersen           36.7          19.3               193        3450
6  Adelie Torgersen           39.3          20.6               190        3650
     sex year
1   male 2007
2 female 2007
3 female 2007
4   <NA> 2007
5 female 2007
6   male 2007

Fehlende Werte mit Replace-Funktion ersetzen

Die Funktion replace() ist ein praktisches Werkzeug in der R-Werkzeugkiste, um bestimmte Elemente in Vektoren und Datensets zu ändern. Sie ermöglicht es Ihnen, unerwünschte Werte durch neue zu ersetzen.

replace(x, list, values)

Code anzeigen
mean_weight <- mean(penguins$body_mass_g, na.rm = TRUE) # Mittelwert ohne NA berechnen
new_penguins <- replace(x = penguins$body_mass_g, 
                        list = is.na(penguins$body_mass_g), 
                        values = mean_weight)

penguins$body_mass_g <- new_penguins # Datensatz aktualisieren
head(penguins$body_mass_g)
[1] 3750.000 3800.000 3250.000 4201.754 3450.000 3650.000

Zeilen mit fehlenden Werten entfernen

Zeilen mit fehlenden Werten können Sie mit der Funktion drop_na() aus dem Paket tidyr löschen.

Code anzeigen
penguins_def <- penguins %>% drop_na()

head(penguins_def)
  species    island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
1  Adelie Torgersen           39.1          18.7               181        3750
2  Adelie Torgersen           39.5          17.4               186        3800
3  Adelie Torgersen           40.3          18.0               195        3250
4  Adelie Torgersen           36.7          19.3               193        3450
5  Adelie Torgersen           39.3          20.6               190        3650
6  Adelie Torgersen           38.9          17.8               181        3625
     sex year
1   male 2007
2 female 2007
3 female 2007
4 female 2007
5   male 2007
6 female 2007

Eine alternative Funktion zum Entfernen von Zeilen mit fehlenden Werten ist na.omit().

Code anzeigen
penguins_def <- na.omit(penguins)

head(penguins_def)
  species    island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
1  Adelie Torgersen           39.1          18.7               181        3750
2  Adelie Torgersen           39.5          17.4               186        3800
3  Adelie Torgersen           40.3          18.0               195        3250
5  Adelie Torgersen           36.7          19.3               193        3450
6  Adelie Torgersen           39.3          20.6               190        3650
7  Adelie Torgersen           38.9          17.8               181        3625
     sex year
1   male 2007
2 female 2007
3 female 2007
5 female 2007
6   male 2007
7 female 2007

Zeilen filtern

Mit Funktionen aus dem Paket dplyr kann geprüft werden, ob ein bestimmter Wert in einer der Spalten vorkommt.

Code anzeigen
penguins %>% 
  filter(if_any( # Bedingung für eine der Spalten erfüllt?
    everything(), ~ .x == 4500)) # Alle Spalten berücksichtigen
    species    island bill_length_mm bill_depth_mm flipper_length_mm
1    Adelie Torgersen           42.5          20.7               197
2    Gentoo    Biscoe           46.1          13.2               211
3 Chinstrap     Dream           53.5          19.9               205
  body_mass_g    sex year
1        4500   male 2007
2        4500 female 2007
3        4500   male 2008

Base R bietet für das Auswählen von Zeilen eigene Funktionen. Mit rowSums() können die Zeilen mit dem angegebenen Wert identifiziert werden.

Code anzeigen
filtered_rows <- which(rowSums(penguins == 4500) > 0, 
                       arr.ind = TRUE) # Ausgabe enthält Zeilen- und Spaltenindizes
penguins[filtered_rows, ]
      species    island bill_length_mm bill_depth_mm flipper_length_mm
18     Adelie Torgersen           42.5          20.7               197
153    Gentoo    Biscoe           46.1          13.2               211
316 Chinstrap     Dream           53.5          19.9               205
    body_mass_g    sex year
18         4500   male 2007
153        4500 female 2007
316        4500   male 2008

Die Kombination der beiden Funktionen filter() und grepl() ermöglicht das Filtern von Zeilen anhand eines Musters.

Code anzeigen
# Zeilen filtern, die «Chin» in der Spalte «species» enthalten
penguins %>% 
  filter(grepl(x = species, "Chin")) %>% 
  head()
    species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
1 Chinstrap  Dream           46.5          17.9               192        3500
2 Chinstrap  Dream           50.0          19.5               196        3900
3 Chinstrap  Dream           51.3          19.2               193        3650
4 Chinstrap  Dream           45.4          18.7               188        3525
5 Chinstrap  Dream           52.7          19.8               197        3725
6 Chinstrap  Dream           45.2          17.8               198        3950
     sex year
1 female 2007
2   male 2007
3   male 2007
4 female 2007
5   male 2007
6 female 2007

Für die Suche nach mehreren Mustern gleichzeitig, können Sie die Funktionen grepl() und paste() kombinieren.

Code anzeigen
bgb_typ_clean %>% 
  select(schulkanton) %>% 
  filter(grepl(paste(c("ern", "den"), collapse = "|"), schulkanton))
  schulkanton
1        Bern
2  Graubünden
3      Luzern
4    Obwalden
5   Nidwalden

Zeilen sortieren

Um die Zeilen eines Datensatzes zu sortieren, können Sie die Funktion arrange() aus dem Paket dplyr verwenden, welche die Zeilen eines Datenrahmens nach den Spaltenwerten sortiert.

Code anzeigen
# Nach Gewicht aufsteigend sortieren
penguins %>% 
  select(species, island, body_mass_g, sex) %>% 
  arrange(body_mass_g) %>% 
  head(n = 10)
     species    island body_mass_g    sex
1  Chinstrap     Dream        2700 female
2     Adelie    Biscoe        2850 female
3     Adelie    Biscoe        2850 female
4     Adelie    Biscoe        2900 female
5     Adelie     Dream        2900 female
6     Adelie Torgersen        2900 female
7  Chinstrap     Dream        2900 female
8     Adelie    Biscoe        2925 female
9     Adelie     Dream        2975   <NA>
10    Adelie     Dream        3000 female
Code anzeigen
# Nach Gewicht absteigend sortieren
penguins %>% 
  select(species, island, body_mass_g, sex) %>% 
  arrange(desc(body_mass_g)) %>% 
  head(n = 10)
   species island body_mass_g  sex
1   Gentoo Biscoe        6300 male
2   Gentoo Biscoe        6050 male
3   Gentoo Biscoe        6000 male
4   Gentoo Biscoe        6000 male
5   Gentoo Biscoe        5950 male
6   Gentoo Biscoe        5950 male
7   Gentoo Biscoe        5850 male
8   Gentoo Biscoe        5850 male
9   Gentoo Biscoe        5850 male
10  Gentoo Biscoe        5800 male

Eine alternative Variante ist das Verwenden der Funktion order() von Base R.

Code anzeigen
penguins[order(penguins$bill_length_mm), ] %>% 
  head(n = 10)
    species    island bill_length_mm bill_depth_mm flipper_length_mm
143  Adelie     Dream           32.1          15.5               188
99   Adelie     Dream           33.1          16.1               178
71   Adelie Torgersen           33.5          19.0               190
93   Adelie     Dream           34.0          17.1               185
9    Adelie Torgersen           34.1          18.1               193
19   Adelie Torgersen           34.4          18.4               184
55   Adelie    Biscoe           34.5          18.1               187
15   Adelie Torgersen           34.6          21.1               198
81   Adelie Torgersen           34.6          17.2               189
53   Adelie    Biscoe           35.0          17.9               190
    body_mass_g    sex year
143        3050 female 2009
99         2900 female 2008
71         3600 female 2008
93         3400 female 2008
9          3475   <NA> 2007
19         3325 female 2007
55         2900 female 2008
15         4400   male 2007
81         3200 female 2008
53         3450 female 2008

Zeilen entfernen

Code anzeigen
# Zeilen bzw. Pinguine entfernen, die leichter als 3000 Gramm sind
penguins_filtered <- subset(penguins, body_mass_g <= 3000)

dim(penguins)
[1] 344   8
Code anzeigen
dim(penguins_filtered)
[1] 11  8
Code anzeigen
# Zeilen nach Index entfernen
penguins_filtered <- penguins[-c(2, 4, 6), ]

head(penguins_filtered)
  species    island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
1  Adelie Torgersen           39.1          18.7               181        3750
3  Adelie Torgersen           40.3          18.0               195        3250
5  Adelie Torgersen           36.7          19.3               193        3450
7  Adelie Torgersen           38.9          17.8               181        3625
8  Adelie Torgersen           39.2          19.6               195        4675
9  Adelie Torgersen           34.1          18.1               193        3475
     sex year
1   male 2007
3 female 2007
5 female 2007
7 female 2007
8   male 2007
9   <NA> 2007

Spalten auswählen

Datensätze enthalten oft mehr Informationen, als für eine bestimmte Analyse benötigt werden. Durch das Weglassen irrelevanter Spalten können Sie Ihre Daten straffen und sich auf das Wesentliche konzentrieren. Dies macht nicht nur den Code sauberer, sondern verbessert auch die Leistung bei der Arbeit mit grossen Datensätzen.

Code anzeigen
penguins[, c(1, 2, 6)] %>% 
  head(n = 10)
   species    island body_mass_g
1   Adelie Torgersen    3750.000
2   Adelie Torgersen    3800.000
3   Adelie Torgersen    3250.000
4   Adelie Torgersen    4201.754
5   Adelie Torgersen    3450.000
6   Adelie Torgersen    3650.000
7   Adelie Torgersen    3625.000
8   Adelie Torgersen    4675.000
9   Adelie Torgersen    3475.000
10  Adelie Torgersen    4250.000
Code anzeigen
penguins %>% 
  select(species, island, bill_length_mm, bill_depth_mm, flipper_length_mm, body_mass_g) %>% 
  head(n = 10)
   species    island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
1   Adelie Torgersen           39.1          18.7               181    3750.000
2   Adelie Torgersen           39.5          17.4               186    3800.000
3   Adelie Torgersen           40.3          18.0               195    3250.000
4   Adelie Torgersen             NA            NA                NA    4201.754
5   Adelie Torgersen           36.7          19.3               193    3450.000
6   Adelie Torgersen           39.3          20.6               190    3650.000
7   Adelie Torgersen           38.9          17.8               181    3625.000
8   Adelie Torgersen           39.2          19.6               195    4675.000
9   Adelie Torgersen           34.1          18.1               193    3475.000
10  Adelie Torgersen           42.0          20.2               190    4250.000
Code anzeigen
penguins %>% 
  select(species:body_mass_g) %>% 
  head(n = 10)
   species    island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
1   Adelie Torgersen           39.1          18.7               181    3750.000
2   Adelie Torgersen           39.5          17.4               186    3800.000
3   Adelie Torgersen           40.3          18.0               195    3250.000
4   Adelie Torgersen             NA            NA                NA    4201.754
5   Adelie Torgersen           36.7          19.3               193    3450.000
6   Adelie Torgersen           39.3          20.6               190    3650.000
7   Adelie Torgersen           38.9          17.8               181    3625.000
8   Adelie Torgersen           39.2          19.6               195    4675.000
9   Adelie Torgersen           34.1          18.1               193    3475.000
10  Adelie Torgersen           42.0          20.2               190    4250.000

Select verfügt über eine Reihe von Hilfsfunktionen, mit denen Sie Variablen anhand ihrer Eigenschaften auswählen können. Zum Beispiel kann es sein, dass Sie nur an numerischen Merkmalen interessiert sind.

Code anzeigen
penguins %>% 
  select(where(is.numeric)) %>% 
  head(n = 10)
   bill_length_mm bill_depth_mm flipper_length_mm body_mass_g year
1            39.1          18.7               181    3750.000 2007
2            39.5          17.4               186    3800.000 2007
3            40.3          18.0               195    3250.000 2007
4              NA            NA                NA    4201.754 2007
5            36.7          19.3               193    3450.000 2007
6            39.3          20.6               190    3650.000 2007
7            38.9          17.8               181    3625.000 2007
8            39.2          19.6               195    4675.000 2007
9            34.1          18.1               193    3475.000 2007
10           42.0          20.2               190    4250.000 2007

Die Select-Funktion in Kombination mit contains() erleichtert die Auswahl von Spalten, welche eine bestimmte Zeichenfolge enthalten. Weitere Auswahlhilfen sind z.B. starts_with() oder ends_with().

Code anzeigen
penguins %>% 
  select(contains("length")) %>% 
  head(n = 10)
   bill_length_mm flipper_length_mm
1            39.1               181
2            39.5               186
3            40.3               195
4              NA                NA
5            36.7               193
6            39.3               190
7            38.9               181
8            39.2               195
9            34.1               193
10           42.0               190

Mit einem vorangestellten Minus- oder Ausrufezeichen lassen sich Spalten aus dem Datensatz entfernen.

Code anzeigen
penguins %>% 
  select(!c(island, year)) %>% 
  head(n = 10)
   species bill_length_mm bill_depth_mm flipper_length_mm body_mass_g    sex
1   Adelie           39.1          18.7               181    3750.000   male
2   Adelie           39.5          17.4               186    3800.000 female
3   Adelie           40.3          18.0               195    3250.000 female
4   Adelie             NA            NA                NA    4201.754   <NA>
5   Adelie           36.7          19.3               193    3450.000 female
6   Adelie           39.3          20.6               190    3650.000   male
7   Adelie           38.9          17.8               181    3625.000 female
8   Adelie           39.2          19.6               195    4675.000   male
9   Adelie           34.1          18.1               193    3475.000   <NA>
10  Adelie           42.0          20.2               190    4250.000   <NA>

Eine andere Möglichkeit zum Löschen von Spalten ist die Verwendung der Funktion subset().

Code anzeigen
penguins %>% 
  subset(select = -c(island, year)) %>% 
  head(n = 10)
   species bill_length_mm bill_depth_mm flipper_length_mm body_mass_g    sex
1   Adelie           39.1          18.7               181    3750.000   male
2   Adelie           39.5          17.4               186    3800.000 female
3   Adelie           40.3          18.0               195    3250.000 female
4   Adelie             NA            NA                NA    4201.754   <NA>
5   Adelie           36.7          19.3               193    3450.000 female
6   Adelie           39.3          20.6               190    3650.000   male
7   Adelie           38.9          17.8               181    3625.000 female
8   Adelie           39.2          19.6               195    4675.000   male
9   Adelie           34.1          18.1               193    3475.000   <NA>
10  Adelie           42.0          20.2               190    4250.000   <NA>

In R stehen weitere Optionen zur Verfügung, um bestimmte Spalten in einem Datensatz zu adressieren. Eine Variante ist der «Accessor» (Dollar-Notation) und eine andere ist das Verwenden der Pull-Funktion aus dem Paket dplyr.

Code anzeigen
# Accessor
head(penguins$bill_length_mm, 
     n = 5)
[1] 39.1 39.5 40.3   NA 36.7
Code anzeigen
# Pull-Funktion
head(pull(.data = penguins, 
          all_of(bill_length_mm)), 
     n = 5)
[1] 39.1 39.5 40.3   NA 36.7

Präfix zu Spaltennamen hinzufügen

Das Hinzufügen eines Präfixes zum Spaltennamen kann nützlich sein, um Variablen zu organisieren, die Lesbarkeit zu verbessern oder Namenskonflikte beim Zusammenführen von Datensätzen zu vermeiden.

Code anzeigen
# Präfix mit paste() und colnames() hinzufügen
colnames(penguins_mean) <- paste("pingu_", 
                                 colnames(penguins_mean), 
                                 sep = "")

head(penguins_mean)
  pingu_species pingu_island pingu_bill_length_mm pingu_bill_depth_mm
1        Adelie    Torgersen                 39.1                18.7
2        Adelie    Torgersen                 39.5                17.4
3        Adelie    Torgersen                 40.3                18.0
4        Adelie    Torgersen                   NA                  NA
5        Adelie    Torgersen                 36.7                19.3
6        Adelie    Torgersen                 39.3                20.6
  pingu_flipper_length_mm pingu_body_mass_g pingu_sex pingu_year
1                     181          3750.000      male       2007
2                     186          3800.000    female       2007
3                     195          3250.000    female       2007
4                      NA          4201.754      <NA>       2007
5                     193          3450.000    female       2007
6                     190          3650.000      male       2007

Spalten zusammenführen

Das Kombinieren von Spalten in R ist eine gängige Operation bei der Arbeit mit Datensätzen. Die Funktion unite() ist dabei eine komfortable Möglichkeit, mehrere Spalten zu einer Spalte zusammenzufassen.

Code anzeigen
# Mehrere Spalten vereinen und Originalspalten löschen
penguins %>% 
  unite(col = "penguins_gesamt", 
        species, 
        island, 
        year, 
        sep = ", ", 
        remove = TRUE) %>% 
  head()
          penguins_gesamt bill_length_mm bill_depth_mm flipper_length_mm
1 Adelie, Torgersen, 2007           39.1          18.7               181
2 Adelie, Torgersen, 2007           39.5          17.4               186
3 Adelie, Torgersen, 2007           40.3          18.0               195
4 Adelie, Torgersen, 2007             NA            NA                NA
5 Adelie, Torgersen, 2007           36.7          19.3               193
6 Adelie, Torgersen, 2007           39.3          20.6               190
  body_mass_g    sex
1    3750.000   male
2    3800.000 female
3    3250.000 female
4    4201.754   <NA>
5    3450.000 female
6    3650.000   male
Code anzeigen
# Spalten zusammenführen mit paste()
paste(penguins$species, 
      "Pinguine leben auf", 
      penguins$island, 
      "und sind", 
      # Zahlen-, Faktor- oder Datumsspalten: Vor Kombi. mit as.character() in Zeichen umwandeln
      as.character(penguins$body_mass_g), 
      "Gramm schwer.") %>% 
  first()
[1] "Adelie Pinguine leben auf Torgersen und sind 3750 Gramm schwer."

Datensätze zusammenführen

Das Zusammenführen mehrerer Datensätze ist eine wichtige Fähigkeit bei der Datenaufbereitung. Unabhängig davon, ob Sie mit kleinen oder grossen Datensätzen arbeiten, kann das Zusammenführen die Effizienz erheblich steigern.

cbind und rbind

Code anzeigen
# Daten spaltenweise zusammenführen
cbined_df <- cbind(bgb_typ_clean, bgb_staat_clean[, 2:3])

head(cbined_df[, 7:10])
  schulkanton            region geschlecht_mann geschlecht_frau
1       Waadt   Genferseeregion           11443            7355
2      Wallis   Genferseeregion            5150            2956
3        Genf   Genferseeregion            5642            3365
4        Bern Espace Mittelland           16579           12310
5    Freiburg Espace Mittelland            4491            2517
6   Solothurn Espace Mittelland            3262            2383
Code anzeigen
# Daten zeilenweise zusammenführen, sinnvoll bei gleichen Spalten
# rbind(sample1, sample2)

list2DF

Die Funktion list2DF() erstellt einen Datenrahmen aus einer Liste.

list2DF(x = random_list)

ldply

ldply() kann aus den Elementen einer Liste einen Datenrahmen erzeugen.

ldply(.data = random_list, .fun = data.frame)

Datensätze zusammenführen

Das Zusammenführen von Datensätzen, die auf mehreren Spalten basieren, ist ein gängiger Vorgang in der Datenanalyse. Durch das Verwenden von Funktionen wie merge() oder den Join-Funktionen des Pakets dplyr können Sie Daten aus verschiedenen Quellen effizient kombinieren und gleichzeitig flexibel mit nicht übereinstimmenden Werten umgehen.

Mit den Funktionen merge() und *_join() lässt sich auch die SVERWEIS-Funktionalität von Excel replizieren.

Code anzeigen
# Zur Veranschaulichung werden einige Regionen und Schulkantone durch «unbekannt» ersetzt.
bgb_staat_clean_ab <- bgb_staat_clean %>% 
  select(geschlecht_mann, geschlecht_frau, schulkanton, region) %>% 
  mutate(schulkanton = ifelse(schulkanton %in% c("Aargau", "Appenzell A. Rh.", 
                                                 "Appenzell I. Rh.", "Basel-Landschaft", 
                                                 "Basel-Stadt", "Bern"), 
                              yes = "unbekannt", no = schulkanton)) %>% 
  mutate(region = ifelse(schulkanton == "unbekannt", yes = "unbekannt", no = region)) %>% 
  # Probleme mit der Gross-/Kleinschreibung des Schlüssels beheben:
  mutate(schulkanton = tolower(schulkanton), 
         region = tolower(region))

Überprüfen Sie die Datentypen und die Eindeutigkeit der Schlüssel, bevor Sie mit dem Zusammenführen der Datensätze beginnen.

Code anzeigen
# Datentypen vor dem Zusammenführen prüfen
class(bgb_staat_clean_ab$region)
[1] "character"
Code anzeigen
class(bgb_typ_clean_efz_eba$region)
[1] "character"
Code anzeigen
# Prüfen, ob Schlüssel doppelt vorhanden sind
# Die Kombination Region = «unbekannt» und Schulkanton = «unbekannt» kommt hier mehrfach vor
bgb_staat_clean_ab %>% 
  group_by(region, schulkanton) %>% 
  filter(n() > 1)
# A tibble: 6 × 4
# Groups:   region, schulkanton [1]
  geschlecht_mann geschlecht_frau schulkanton region   
            <dbl>           <dbl> <chr>       <chr>    
1           16579           12310 unbekannt   unbekannt
2            2955            2696 unbekannt   unbekannt
3            3801            2039 unbekannt   unbekannt
4            9323            6340 unbekannt   unbekannt
5             526             348 unbekannt   unbekannt
6              NA              NA unbekannt   unbekannt
Code anzeigen
# Auf fehlende Übereinstimmungen prüfen
missing_matches <- setdiff(bgb_staat_clean_ab$region, 
                           bgb_typ_clean_efz_eba$region)

if (length(missing_matches) > 0) {
  warning("Nicht übereinstimmende Werte gefunden: ", 
          paste(missing_matches, 
                collapse = ", "))
} else {
  "Es wurden keine Fehler gefunden."
}
Warning: Nicht übereinstimmende Werte gefunden: unbekannt

Inner Join kombiniert Zeilen aus beiden Datensätzen, die auf der Grundlage der angegebenen Spalten übereinstimmen. Zeilen mit nicht übereinstimmenden Werten werden ausgeschlossen.

Code anzeigen
# Datensatz auf Basis von «Region» und «Schulkanton» mit Inner Join von dplyr zusammenführen
bgb_staat_clean_ab %>% 
  inner_join(y = bgb_typ_clean_efz_eba, 
             by = c("region", "schulkanton"))
   geschlecht_mann geschlecht_frau  schulkanton            region typ_efz
1            11443            7355        waadt   genferseeregion   17754
2             5150            2956       wallis   genferseeregion    7634
3             5642            3365         genf   genferseeregion    8387
4             4491            2517     freiburg espace mittelland    6682
5             3262            2383    solothurn espace mittelland    5150
6             3091            1934    neuenburg espace mittelland    4756
7             1206             741         jura espace mittelland    1876
8            22793           18562       zürich            zürich   38197
9              678             392       glarus        ostschweiz    1000
10            1117             910 schaffhausen        ostschweiz    1917
11            9655            6705   st. gallen        ostschweiz   15382
12            2971            1917   graubünden        ostschweiz    4569
13            3509            2141      thurgau        ostschweiz    5317
14            8317            5642       luzern    zentralschweiz   13035
15             367             231          uri    zentralschweiz     589
16            1920             823       schwyz    zentralschweiz    2642
17             532             224     obwalden    zentralschweiz     630
18             370             231    nidwalden    zentralschweiz     590
19            1793            1274          zug    zentralschweiz    2885
20            5613            3477       tessin            tessin    8436
   typ_eba
1     1004
2      467
3      521
4      320
5      495
6      259
7       71
8     2580
9       70
10     110
11     978
12     199
13     333
14     924
15       9
16     101
17     126
18      11
19     182
20     654
Code anzeigen
# Datensatz auf Basis von «Region» und «Schulkanton» mit merge() zusammenführen
merge(x = bgb_staat_clean_ab, 
      y = bgb_typ_clean_efz_eba, 
      by = c("region", "schulkanton"))
              region  schulkanton geschlecht_mann geschlecht_frau typ_efz
1  espace mittelland     freiburg            4491            2517    6682
2  espace mittelland         jura            1206             741    1876
3  espace mittelland    neuenburg            3091            1934    4756
4  espace mittelland    solothurn            3262            2383    5150
5    genferseeregion         genf            5642            3365    8387
6    genferseeregion        waadt           11443            7355   17754
7    genferseeregion       wallis            5150            2956    7634
8         ostschweiz       glarus             678             392    1000
9         ostschweiz   graubünden            2971            1917    4569
10        ostschweiz schaffhausen            1117             910    1917
11        ostschweiz   st. gallen            9655            6705   15382
12        ostschweiz      thurgau            3509            2141    5317
13            tessin       tessin            5613            3477    8436
14    zentralschweiz       luzern            8317            5642   13035
15    zentralschweiz    nidwalden             370             231     590
16    zentralschweiz     obwalden             532             224     630
17    zentralschweiz       schwyz            1920             823    2642
18    zentralschweiz          uri             367             231     589
19    zentralschweiz          zug            1793            1274    2885
20            zürich       zürich           22793           18562   38197
   typ_eba
1      320
2       71
3      259
4      495
5      521
6     1004
7      467
8       70
9      199
10     110
11     978
12     333
13     654
14     924
15      11
16     126
17     101
18       9
19     182
20    2580

Left Join behält alle Zeilen des linken Datensatzes (bgb_staat_clean_ab) bei und fügt die entsprechenden Zeilen des rechten Datensatzes (bgb_typ_clean_efz_eba) ein. Wenn es keine Übereinstimmung gibt, werden NA-Werte für die Spalten von «bgb_typ_clean_efz_eba» eingefügt.

Die Funktion left_join() aus dem dplyr-Paket kann auch verwendet werden, um Werte zu ersetzen.

Code anzeigen
# Datensatz auf Basis von «Region» und «Schulkanton» mit Left Join von dplyr zusammenführen
bgb_staat_clean_ab %>% 
  left_join(y = bgb_typ_clean_efz_eba, 
            by = c("region", "schulkanton"))
   geschlecht_mann geschlecht_frau  schulkanton            region typ_efz
1            11443            7355        waadt   genferseeregion   17754
2             5150            2956       wallis   genferseeregion    7634
3             5642            3365         genf   genferseeregion    8387
4            16579           12310    unbekannt         unbekannt      NA
5             4491            2517     freiburg espace mittelland    6682
6             3262            2383    solothurn espace mittelland    5150
7             3091            1934    neuenburg espace mittelland    4756
8             1206             741         jura espace mittelland    1876
9             2955            2696    unbekannt         unbekannt      NA
10            3801            2039    unbekannt         unbekannt      NA
11            9323            6340    unbekannt         unbekannt      NA
12           22793           18562       zürich            zürich   38197
13             678             392       glarus        ostschweiz    1000
14            1117             910 schaffhausen        ostschweiz    1917
15             526             348    unbekannt         unbekannt      NA
16              NA              NA    unbekannt         unbekannt      NA
17            9655            6705   st. gallen        ostschweiz   15382
18            2971            1917   graubünden        ostschweiz    4569
19            3509            2141      thurgau        ostschweiz    5317
20            8317            5642       luzern    zentralschweiz   13035
21             367             231          uri    zentralschweiz     589
22            1920             823       schwyz    zentralschweiz    2642
23             532             224     obwalden    zentralschweiz     630
24             370             231    nidwalden    zentralschweiz     590
25            1793            1274          zug    zentralschweiz    2885
26            5613            3477       tessin            tessin    8436
   typ_eba
1     1004
2      467
3      521
4       NA
5      320
6      495
7      259
8       71
9       NA
10      NA
11      NA
12    2580
13      70
14     110
15      NA
16      NA
17     978
18     199
19     333
20     924
21       9
22     101
23     126
24      11
25     182
26     654
Code anzeigen
# Datensatz auf Basis von «Region» und «Schulkanton» mit merge() zusammenführen
merge(x = bgb_staat_clean_ab, 
      y = bgb_typ_clean_efz_eba, 
      by = c("region", "schulkanton"), 
      all.x = TRUE)
              region  schulkanton geschlecht_mann geschlecht_frau typ_efz
1  espace mittelland     freiburg            4491            2517    6682
2  espace mittelland         jura            1206             741    1876
3  espace mittelland    neuenburg            3091            1934    4756
4  espace mittelland    solothurn            3262            2383    5150
5    genferseeregion         genf            5642            3365    8387
6    genferseeregion        waadt           11443            7355   17754
7    genferseeregion       wallis            5150            2956    7634
8         ostschweiz       glarus             678             392    1000
9         ostschweiz   graubünden            2971            1917    4569
10        ostschweiz schaffhausen            1117             910    1917
11        ostschweiz   st. gallen            9655            6705   15382
12        ostschweiz      thurgau            3509            2141    5317
13            tessin       tessin            5613            3477    8436
14         unbekannt    unbekannt            2955            2696      NA
15         unbekannt    unbekannt            3801            2039      NA
16         unbekannt    unbekannt            9323            6340      NA
17         unbekannt    unbekannt           16579           12310      NA
18         unbekannt    unbekannt             526             348      NA
19         unbekannt    unbekannt              NA              NA      NA
20    zentralschweiz       luzern            8317            5642   13035
21    zentralschweiz    nidwalden             370             231     590
22    zentralschweiz     obwalden             532             224     630
23    zentralschweiz       schwyz            1920             823    2642
24    zentralschweiz          uri             367             231     589
25    zentralschweiz          zug            1793            1274    2885
26            zürich       zürich           22793           18562   38197
   typ_eba
1      320
2       71
3      259
4      495
5      521
6     1004
7      467
8       70
9      199
10     110
11     978
12     333
13     654
14      NA
15      NA
16      NA
17      NA
18      NA
19      NA
20     924
21      11
22     126
23     101
24       9
25     182
26    2580

Right Join behält alle Zeilen des rechten Datensatzes (bgb_typ_clean_efz_eba) bei und fügt die entsprechenden Zeilen des linken Datensatzes (bgb_staat_clean_ab) ein. Wenn es keine Übereinstimmung gibt, werden NA-Werte für die Spalten von «bgb_staat_clean_ab» eingefügt.

Code anzeigen
# Datensatz auf Basis von «Region» und «Schulkanton» mit Right Join von dplyr zusammenführen
bgb_staat_clean_ab %>% 
  right_join(y = bgb_typ_clean_efz_eba, 
             by = c("region", "schulkanton"))
   geschlecht_mann geschlecht_frau      schulkanton            region typ_efz
1            11443            7355            waadt   genferseeregion   17754
2             5150            2956           wallis   genferseeregion    7634
3             5642            3365             genf   genferseeregion    8387
4             4491            2517         freiburg espace mittelland    6682
5             3262            2383        solothurn espace mittelland    5150
6             3091            1934        neuenburg espace mittelland    4756
7             1206             741             jura espace mittelland    1876
8            22793           18562           zürich            zürich   38197
9              678             392           glarus        ostschweiz    1000
10            1117             910     schaffhausen        ostschweiz    1917
11            9655            6705       st. gallen        ostschweiz   15382
12            2971            1917       graubünden        ostschweiz    4569
13            3509            2141          thurgau        ostschweiz    5317
14            8317            5642           luzern    zentralschweiz   13035
15             367             231              uri    zentralschweiz     589
16            1920             823           schwyz    zentralschweiz    2642
17             532             224         obwalden    zentralschweiz     630
18             370             231        nidwalden    zentralschweiz     590
19            1793            1274              zug    zentralschweiz    2885
20            5613            3477           tessin            tessin    8436
21              NA              NA             bern espace mittelland   27079
22              NA              NA      basel-stadt   nordwestschweiz    5305
23              NA              NA basel-landschaft   nordwestschweiz    5299
24              NA              NA           aargau   nordwestschweiz   14450
25              NA              NA appenzell a. rh.        ostschweiz     832
26              NA              NA appenzell i. rh.        ostschweiz      NA
   typ_eba
1     1004
2      467
3      521
4      320
5      495
6      259
7       71
8     2580
9       70
10     110
11     978
12     199
13     333
14     924
15       9
16     101
17     126
18      11
19     182
20     654
21    1718
22     346
23     541
24    1213
25      42
26      NA
Code anzeigen
# Datensatz auf Basis von «Region» und «Schulkanton» mit merge() zusammenführen
merge(x = bgb_staat_clean_ab, 
      y = bgb_typ_clean_efz_eba, 
      by = c("region", "schulkanton"), 
      all.y = TRUE)
              region      schulkanton geschlecht_mann geschlecht_frau typ_efz
1  espace mittelland             bern              NA              NA   27079
2  espace mittelland         freiburg            4491            2517    6682
3  espace mittelland             jura            1206             741    1876
4  espace mittelland        neuenburg            3091            1934    4756
5  espace mittelland        solothurn            3262            2383    5150
6    genferseeregion             genf            5642            3365    8387
7    genferseeregion            waadt           11443            7355   17754
8    genferseeregion           wallis            5150            2956    7634
9    nordwestschweiz           aargau              NA              NA   14450
10   nordwestschweiz basel-landschaft              NA              NA    5299
11   nordwestschweiz      basel-stadt              NA              NA    5305
12        ostschweiz appenzell a. rh.              NA              NA     832
13        ostschweiz appenzell i. rh.              NA              NA      NA
14        ostschweiz           glarus             678             392    1000
15        ostschweiz       graubünden            2971            1917    4569
16        ostschweiz     schaffhausen            1117             910    1917
17        ostschweiz       st. gallen            9655            6705   15382
18        ostschweiz          thurgau            3509            2141    5317
19            tessin           tessin            5613            3477    8436
20    zentralschweiz           luzern            8317            5642   13035
21    zentralschweiz        nidwalden             370             231     590
22    zentralschweiz         obwalden             532             224     630
23    zentralschweiz           schwyz            1920             823    2642
24    zentralschweiz              uri             367             231     589
25    zentralschweiz              zug            1793            1274    2885
26            zürich           zürich           22793           18562   38197
   typ_eba
1     1718
2      320
3       71
4      259
5      495
6      521
7     1004
8      467
9     1213
10     541
11     346
12      42
13      NA
14      70
15     199
16     110
17     978
18     333
19     654
20     924
21      11
22     126
23     101
24       9
25     182
26    2580

Bei einem Full Join werden alle Zeilen aus beiden Datensätzen beibehalten, wobei für Spalten, für die keine Übereinstimmung besteht, NA-Werte verwendet werden.

Code anzeigen
# Datensatz auf Basis von «Region» und «Schulkanton» mit Full Join von dplyr zusammenführen
bgb_staat_clean_ab %>% 
  full_join(y = bgb_typ_clean_efz_eba, 
            by = c("region", "schulkanton"))
   geschlecht_mann geschlecht_frau      schulkanton            region typ_efz
1            11443            7355            waadt   genferseeregion   17754
2             5150            2956           wallis   genferseeregion    7634
3             5642            3365             genf   genferseeregion    8387
4            16579           12310        unbekannt         unbekannt      NA
5             4491            2517         freiburg espace mittelland    6682
6             3262            2383        solothurn espace mittelland    5150
7             3091            1934        neuenburg espace mittelland    4756
8             1206             741             jura espace mittelland    1876
9             2955            2696        unbekannt         unbekannt      NA
10            3801            2039        unbekannt         unbekannt      NA
11            9323            6340        unbekannt         unbekannt      NA
12           22793           18562           zürich            zürich   38197
13             678             392           glarus        ostschweiz    1000
14            1117             910     schaffhausen        ostschweiz    1917
15             526             348        unbekannt         unbekannt      NA
16              NA              NA        unbekannt         unbekannt      NA
17            9655            6705       st. gallen        ostschweiz   15382
18            2971            1917       graubünden        ostschweiz    4569
19            3509            2141          thurgau        ostschweiz    5317
20            8317            5642           luzern    zentralschweiz   13035
21             367             231              uri    zentralschweiz     589
22            1920             823           schwyz    zentralschweiz    2642
23             532             224         obwalden    zentralschweiz     630
24             370             231        nidwalden    zentralschweiz     590
25            1793            1274              zug    zentralschweiz    2885
26            5613            3477           tessin            tessin    8436
27              NA              NA             bern espace mittelland   27079
28              NA              NA      basel-stadt   nordwestschweiz    5305
29              NA              NA basel-landschaft   nordwestschweiz    5299
30              NA              NA           aargau   nordwestschweiz   14450
31              NA              NA appenzell a. rh.        ostschweiz     832
32              NA              NA appenzell i. rh.        ostschweiz      NA
   typ_eba
1     1004
2      467
3      521
4       NA
5      320
6      495
7      259
8       71
9       NA
10      NA
11      NA
12    2580
13      70
14     110
15      NA
16      NA
17     978
18     199
19     333
20     924
21       9
22     101
23     126
24      11
25     182
26     654
27    1718
28     346
29     541
30    1213
31      42
32      NA
Code anzeigen
# Datensatz auf Basis von «Region» und «Schulkanton» mit merge() zusammenführen
merge(x = bgb_staat_clean_ab, 
      y = bgb_typ_clean_efz_eba, 
      by = c("region", "schulkanton"), 
      all = TRUE)
              region      schulkanton geschlecht_mann geschlecht_frau typ_efz
1  espace mittelland             bern              NA              NA   27079
2  espace mittelland         freiburg            4491            2517    6682
3  espace mittelland             jura            1206             741    1876
4  espace mittelland        neuenburg            3091            1934    4756
5  espace mittelland        solothurn            3262            2383    5150
6    genferseeregion             genf            5642            3365    8387
7    genferseeregion            waadt           11443            7355   17754
8    genferseeregion           wallis            5150            2956    7634
9    nordwestschweiz           aargau              NA              NA   14450
10   nordwestschweiz basel-landschaft              NA              NA    5299
11   nordwestschweiz      basel-stadt              NA              NA    5305
12        ostschweiz appenzell a. rh.              NA              NA     832
13        ostschweiz appenzell i. rh.              NA              NA      NA
14        ostschweiz           glarus             678             392    1000
15        ostschweiz       graubünden            2971            1917    4569
16        ostschweiz     schaffhausen            1117             910    1917
17        ostschweiz       st. gallen            9655            6705   15382
18        ostschweiz          thurgau            3509            2141    5317
19            tessin           tessin            5613            3477    8436
20         unbekannt        unbekannt            2955            2696      NA
21         unbekannt        unbekannt            3801            2039      NA
22         unbekannt        unbekannt            9323            6340      NA
23         unbekannt        unbekannt           16579           12310      NA
24         unbekannt        unbekannt             526             348      NA
25         unbekannt        unbekannt              NA              NA      NA
26    zentralschweiz           luzern            8317            5642   13035
27    zentralschweiz        nidwalden             370             231     590
28    zentralschweiz         obwalden             532             224     630
29    zentralschweiz           schwyz            1920             823    2642
30    zentralschweiz              uri             367             231     589
31    zentralschweiz              zug            1793            1274    2885
32            zürich           zürich           22793           18562   38197
   typ_eba
1     1718
2      320
3       71
4      259
5      495
6      521
7     1004
8      467
9     1213
10     541
11     346
12      42
13      NA
14      70
15     199
16     110
17     978
18     333
19     654
20      NA
21      NA
22      NA
23      NA
24      NA
25      NA
26     924
27      11
28     126
29     101
30       9
31     182
32    2580

Kategoriale Variablen

Faktoren sind wichtige Datenstrukturen in R, die häufig zur Darstellung kategorialer Variablen verwendet werden. Sie speichern sowohl die Werte der kategorialen Variablen als auch die entsprechenden Stufen. Jede Faktorstufe repräsentiert eine eindeutige Kategorie innerhalb der Variablen.

Numerische in kategoriale Werte konvertieren

Bei manchen Variablen ist es sinnvoll, sie von einem numerischen Wert in eine kategoriale Grösse zu konvertieren. Aber auch nichtnumerische Variablen können in einen Faktor transformiert werden.

Code anzeigen
# Aktueller Datentyp bestimmen
class(penguins$year)
[1] "numeric"
Code anzeigen
penguins_cat <- penguins %>% mutate(year = factor(year))

class(penguins_cat$year)
[1] "factor"

Numerische Variablen kategorisieren

Mit der Funktion cut() können kontinuierliche Variablen in Intervalle oder sogenannte «Bins» unterteilt werden, die auf bestimmten Messpunkten basieren. Auf diese Weise können Sie numerische Daten in kategorische Daten umwandeln, die sich leichter analysieren und interpretieren lassen.

cut(x, breaks, labels = NULL, right = TRUE, ...)

Code anzeigen
gewichtsgruppen <- cut(x = penguins$body_mass_g, 
                       breaks = c(0, 3900, 5100, Inf), 
                       labels = c("leicht", "mittel", "schwer"))

tail(gewichtsgruppen)
[1] leicht mittel leicht leicht mittel leicht
Levels: leicht mittel schwer

Faktorstufen umbenennen

Die Umbenennung von Faktorstufen kann die Lesbarkeit und Interpretierbarkeit Ihrer kategorialen Daten erheblich verbessern. Das Paket forcats bietet dafür leistungsstarke Werkzeuge.

Code anzeigen
penguins_cln <- penguins %>% 
  mutate(sex = fct_recode(sex, "M" = "male", "F" = "female"))

head(penguins_cln[, c(1:2, 7)])
  species    island  sex
1  Adelie Torgersen    M
2  Adelie Torgersen    F
3  Adelie Torgersen    F
4  Adelie Torgersen <NA>
5  Adelie Torgersen    F
6  Adelie Torgersen    M

Textmanipulation

Code anzeigen
# Beispiel-Text
text <- c("Fähigkeitszeugnis, Zeugnis, Zeugnisse, EFZ")

Auf vorhandene Zeichen prüfen

Bei der Arbeit mit Textdaten besteht eine häufige Aufgabe darin, zu prüfen, ob ein Zeichen oder eine Teilzeichenkette in einer längeren Zeichenkette enthalten ist. R stellt für diesen Zweck leistungsfähige Instrumente zur Verfügung, z.B. die Funktion grepl() von Base R, str_detect() von stringr oder stri_detect_fixed() von stringi.

Code anzeigen
str_detect(string = text, 
           regex(pattern = "fähigkeitszeugnis", 
                 ignore_case = TRUE))
[1] TRUE

Auf vorhandene Teilstrings prüfen

Code anzeigen
teilstrings <- c("Fähigkeitszeugnis", "EFZ")

# Prüfen, ob einzelne Werte wahr sind
str_detect(string = text, pattern = teilstrings)
[1] TRUE TRUE
Code anzeigen
# Prüfen, ob alle Werte wahr sind
all(str_detect(string = text, pattern = teilstrings))
[1] TRUE

Anzahl Zeichen verwalten

Code anzeigen
tibble(schulkanton = bgb_typ_clean_efz_eba$schulkanton, 
       anzahl_zeichen = str_count(string = bgb_typ_clean_efz_eba$schulkanton, 
                                  pattern = "a|s")) # Suchmuster mit OR kombinieren
# A tibble: 26 × 2
   schulkanton      anzahl_zeichen
   <chr>                     <int>
 1 waadt                         2
 2 wallis                        2
 3 genf                          0
 4 bern                          0
 5 freiburg                      0
 6 solothurn                     1
 7 neuenburg                     0
 8 jura                          1
 9 basel-stadt                   4
10 basel-landschaft              5
# ℹ 16 more rows

Die Funktion str_length() gibt die Anzahl der Zeichen (einschliesslich Leer- und Satzzeichen) zurück. Sonderzeichen, die mit dem Escape-Zeichen «\» beginnen, zählen dabei als ein Zeichen.

Code anzeigen
str_length(string = text)
[1] 42

Bei manuell eingegebenen Daten können versehentlich zusätzliche Leerzeichen eingefügt worden sein. Die Funktion str_squish() entfernt unsichtbare Leerzeichen am Anfang und am Ende einer Zeichenkette und fasst mehrere Leerzeichen in der Mitte zu einem zusammen.

Code anzeigen
# Beispiel-Text
text <- c(" Fähigkeitszeugnis,   Zeugnis, Zeugnisse, EFZ ")
Code anzeigen
str_squish(string = text)
[1] "Fähigkeitszeugnis, Zeugnis, Zeugnisse, EFZ"

Mustervergleich in Zeichenkette

Die Funktion grep() ist ein leistungsfähiges Werkzeug von Base R für Mustervergleiche und das Suchen in Zeichenketten. Standardmässig führt grep() einen Teilabgleich durch, was zu unerwarteten Ergebnissen führen kann, wenn Sie nach exakten Übereinstimmungen suchen. Eine effektive Methode für den exakten Abgleich ist die Verwendung der Anker ^ (Anfang der Zeichenfolge) und $ (Ende der Zeichenfolge). Dadurch wird sichergestellt, dass der gesuchte Begriff die gesamte Zeichenkette ist und nicht nur ein Teil davon.

Code anzeigen
# Beispiel-Text
text <- c("Fähigkeitszeugnis", "Zeugnis", "Zeugnisse", "EFZ")
Code anzeigen
grep(pattern = "^Zeugnis$", 
     x = text) # Weitere Argumente: ignore.case = TRUE, value = TRUE
[1] 2
Code anzeigen
# Reguläre Ausdrücke für komplexe Suchmuster
grep(pattern = "^[ZE]", 
     x = text)
[1] 2 3 4
Code anzeigen
# Positionen zurückgeben, bei denen eine Übereinstimmung vorliegt
grep(pattern = "Zeugnis|EFZ", # Suchmuster mit OR kombinieren
     x = text)
[1] 2 3 4

Um einen Vergleich zu ermöglichen, wird derselbe Vorgang mit dem Paket stringr durchgeführt.

Code anzeigen
# Zeichenketten zurückgeben, bei denen eine Übereinstimmung vorliegt
str_subset(string = text, 
           pattern = "Zeugnis|EFZ", 
           negate = FALSE) # «negate = TRUE» gibt diejenigen ohne Übereinstimmung zurück
[1] "Zeugnis"   "Zeugnisse" "EFZ"      

Bei der Arbeit mit grossen Datensätzen kann die Leistung der verschiedenen Abgleichsmethoden erheblich sein. Im Allgemeinen ist die Verwendung von == oder %in% für exakte Vergleiche in einfachen Fällen schneller. grep() ist jedoch effizienter, wenn Sie mit komplexen Mustern arbeiten oder wenn Sie die zusätzlichen Funktionen wie ignore.case oder die value-Optionen verwenden wollen.

Code anzeigen
any(text == "Zeugnis")
[1] TRUE
Code anzeigen
text[text == "Zeugnis"]
[1] "Zeugnis"

Ungefähre Übereinstimmung finden

Die Funktion agrep() von Base R wird für die annähernde Übereinstimmung von Zeichenketten verwendet, auch bekannt als Fuzzy Matching.

Die Funktion ist besonders nützlich für

  • Suche nach ähnlichen Zeichenfolgen in einem Datensatz

  • Durchführung unscharfer Suchen in Textfeldern

  • Korrektur von Rechtschreibfehlern in Textdaten

agrep() ist ein leistungsfähiges Werkzeug für das Fuzzy Matching, aber es ist wichtig, geeignete Parameter zu wählen (insbesondere max.distance), um die richtige Balance zwischen dem Erkennen relevanter Übereinstimmungen und dem Vermeiden falsch positiver Ergebnisse zu finden. Bei sehr umfangreichen Abgleichsaufgaben kann die Verwendung der Funktion langsam sein.

Code anzeigen
agrep(pattern = "zügnisse", 
      x = text, 
      max.distance = 0.4) # Maximal zulässige Distanz für einen Treffer
[1] 1 2 3

Zeichenketten ver­bin­den

Beim Zusammenfügen von Zeichenketten werden zwei oder mehrere Elemente miteinander verbunden. Dabei spielt es keine Rolle, ob Sie mit Textdaten arbeiten oder dynamische Ausgaben erzeugen.

Code anzeigen
text <- str_c(bgb_typ_clean$typ_efz[1], 
              " Lernende wurden im Kanton ",  
              bgb_typ_clean$schulkanton[1], 
              " mit einem eidg. Fähigkeitszeugnis (EFZ) ausgezeichnet.", 
              sep = "") # Ohne Separator ist str_c() äquivalent zu paste0()

writeLines(text = text)
17754 Lernende wurden im Kanton Waadt mit einem eidg. Fähigkeitszeugnis (EFZ) ausgezeichnet.

Mithilfe der Funktion str_glue() lassen sich Zeichenketten mit dem dynamischen Wert einer Variablen oder Funktion kombinieren. Dies kann beispielsweise bei Textelementen in Diagrammen eine nützliche Alternative zu paste() und paste0() sein.

Code anzeigen
str_glue("Der Datensatz «bgb_typ_clean_efz_eba» umfasst insgesamt", 
         length(unique(bgb_typ_clean_efz_eba$region)), 
         "Regionen", 
         .sep = " ")
Der Datensatz «bgb_typ_clean_efz_eba» umfasst insgesamt 7 Regionen

Zeichenkette aufteilen und Element extrahieren

Code anzeigen
ergebnis <- str_split(string = text, 
                      pattern = " ", 
                      simplify = FALSE) # TRUE: Rückgabe als Matrix

sapply(X = ergebnis, `[`, 1)
[1] "17754"

Zeichenkette zwischen bestimmten Zeichen extrahieren

Die Funktion str_extract() extrahiert die erste Teilzeichenkette, die einem Regex-Muster entspricht. Sie verwendet Lookbehind (?<=\\[) und Lookahead (?=\\]), um Text zwischen [ und ] zu finden und einen einfachen Abgleich für Text zwischen ( und ) durchzuführen.

Code anzeigen
# Text zwischen eckigen Klammern extrahieren
str_extract(string = text, 
            pattern = "(?<=\\[).*?(?=\\])") # Alternative: "\\[.*?\\]"
[1] NA
Code anzeigen
# Alle Übereinstimmungen extrahieren
str_extract_all(string = text, 
                pattern = "(?<=\\[).*?(?=\\])|(?<=\\().*?(?=\\))")
[[1]]
[1] "EFZ"

Zeichenkette vor Leerzeichen extrahieren

Um den Teil der Zeichenkette vor dem ersten Leerzeichen zu finden und zu extrahieren, können Sie str_extract() mit einem regulären Ausdruck verwenden. Das Muster ^[^ ]+ entspricht dem Anfang der Zeichenkette (^), gefolgt von einem oder mehreren Zeichen, die keine Leerzeichen sind ([^ ]+).

Code anzeigen
# Zeichenkette vor erstem Leerzeichen extrahieren
str_extract(string = text, 
            pattern = "^[^ ]+")
[1] "17754"

Zahlen aus Zeichenkette extrahieren

Drei Methoden im Vergleich:

  • Base R ist flexibel und benötigt keine zusätzlichen Pakete, aber die Syntax kann etwas umständlich sein.

  • stringr, Bestandteil von tidyverse, vereinfacht den Prozess mit intuitiven Funktionen, so dass der Code leichter zu lesen und zu schreiben ist.

  • stringi bietet leistungsfähige und effiziente String-Operationen, die sich für leistungskritische Aufgaben eignen.

Code anzeigen
zahlen <- str_extract_all(string = text, 
                          pattern = "\\d+") # \\d+ extrahiert eine oder mehrere Zahlen
as.numeric(unlist(zahlen))
[1] 17754

Zahl in Ziffern aufteilen

Code anzeigen
# Funktion zum Aufteilen einer einzelnen Zahl in Ziffern
split_number <- function(number){
  number_str <- as.character(number)
  number_with_spaces <- gsub(pattern = "(.)", 
                             replacement = "\\1 ", # Leerzeichen zwischen den Ziffern einfügen
                             x = number_str)
  digits <- strsplit(x = number_with_spaces, split = " ")[[1]]
  as.numeric(digits)
}
Code anzeigen
# Funktion auf jede Zahl des Vektors anwenden
lapply(X = zahlen, 
       FUN = split_number)
[[1]]
[1] 1 7 7 5 4

Führende Nullen bei Zahlen hinzufügen

Manchmal ist es erforderlich, dass Zahlen ein bestimmtes Format haben. Das Hinzufügen von führenden Nullen ist eine Möglichkeit, die erforderliche Konsistenz der Datendarstellung zu gewährleisten.

Code anzeigen
# Ausgangslage
head(bgb_typ_clean$typ_eba)
[1] 1004  467  521 1718  320  495
Code anzeigen
ergebnis <- sprintf("%05d", bgb_typ_clean$typ_eba) # %d = Ganzzahl, 05 = Ausgabe 5 Zeichen lang

head(ergebnis)
[1] "01004" "00467" "00521" "01718" "00320" "00495"

Zeichen ersetzen

Code anzeigen
# Zur Veranschaulichung wird der Begriff «Genferseeregion» durch zusätzlichen Text ergänzt
bgb_typ_clean_region <- bgb_typ_clean %>% 
  mutate(region = ifelse(region == "Genferseeregion", 
                         yes = "Region 1201 Genferseeregion", 
                         no = region)) %>% 
  filter(region == "Region 1201 Genferseeregion") %>% 
  pull(region)

bgb_typ_clean_region
[1] "Region 1201 Genferseeregion" "Region 1201 Genferseeregion"
[3] "Region 1201 Genferseeregion"
Code anzeigen
# case_when() ist eine Alternative zu ifelse(), insbesondere bei mehr als zwei Formeln
bgb_typ_clean_region <- 
  case_when(bgb_typ_clean$region == "Genferseeregion" ~ "Region 1201 Genferseeregion", 
            bgb_typ_clean$region != "Genferseeregion" ~ bgb_typ_clean$region)

bgb_typ_clean_region[1:3]
[1] "Region 1201 Genferseeregion" "Region 1201 Genferseeregion"
[3] "Region 1201 Genferseeregion"

Die Funktion sub() ersetzt die erste Übereinstimmung in einer Zeichenfolge durch neue Zeichen, während die Funktion gsub() alle Übereinstimmungen in einer Zeichenfolge durch neue Zeichen ersetzt.

Code anzeigen
# Erste Übereinstimmung ersetzen
bgb_typ_clean_region %>% 
  sub(pattern = "region", 
      replacement = "", 
      ignore.case = TRUE)
 [1] " 1201 Genferseeregion" " 1201 Genferseeregion" " 1201 Genferseeregion"
 [4] "Espace Mittelland"     "Espace Mittelland"     "Espace Mittelland"    
 [7] "Espace Mittelland"     "Espace Mittelland"     "Nordwestschweiz"      
[10] "Nordwestschweiz"       "Nordwestschweiz"       "Zürich"               
[13] "Ostschweiz"            "Ostschweiz"            "Ostschweiz"           
[16] "Ostschweiz"            "Ostschweiz"            "Ostschweiz"           
[19] "Ostschweiz"            "Zentralschweiz"        "Zentralschweiz"       
[22] "Zentralschweiz"        "Zentralschweiz"        "Zentralschweiz"       
[25] "Zentralschweiz"        "Tessin"               
Code anzeigen
# Alle Übereinstimmungen ersetzen
bgb_typ_clean_region %>% 
  # Für verschiedene Muster (pattern) den Operator | verwenden
  gsub(pattern = "region", # Auch reguläre Ausdrücke möglich, z.B. ".*\\$" (bis/mit $-Zeichen)
       replacement = "", 
       ignore.case = TRUE)
 [1] " 1201 Genfersee"   " 1201 Genfersee"   " 1201 Genfersee"  
 [4] "Espace Mittelland" "Espace Mittelland" "Espace Mittelland"
 [7] "Espace Mittelland" "Espace Mittelland" "Nordwestschweiz"  
[10] "Nordwestschweiz"   "Nordwestschweiz"   "Zürich"           
[13] "Ostschweiz"        "Ostschweiz"        "Ostschweiz"       
[16] "Ostschweiz"        "Ostschweiz"        "Ostschweiz"       
[19] "Ostschweiz"        "Zentralschweiz"    "Zentralschweiz"   
[22] "Zentralschweiz"    "Zentralschweiz"    "Zentralschweiz"   
[25] "Zentralschweiz"    "Tessin"           

Eine einfache Methode ist auch die Verwendung der match()-Funktion von Base R.

Code anzeigen
# Daten für Beispiel aufbereiten
lookup_tbl <- data.frame(gender = c("female", "male"), # Referenztabelle
                         code = c("f", "m"))
Code anzeigen
# match() gibt die Pos. der ersten Übereinstimmung des ersten Arguments im zweiten Arg. zurück
penguins_df$gender_new <- 
  lookup_tbl$code[match(x = penguins_def$sex, 
                        table = lookup_tbl$gender)]

glue(
  "Bisher: {penguins_df$sex[1]}, {penguins_df$sex[2]}, {penguins_df$sex[3]}
  Neu: {penguins_df$gender_new[1]}, {penguins_df$gender_new[2]}, {penguins_df$gender_new[3]}"
)
Bisher: male, female, female
Neu: m, f, f

Kontrollieren Sie die Daten stichprobenartig, nachdem Sie sie ersetzt haben.

Code anzeigen
table(penguins_df$gender_new, 
      useNA = "ifany")

  f   m 
165 168 

map

Die Funktion map() erlaubt, verschiedene Textmanipulationen anzuwenden.

Code anzeigen
# Namen in Grossbuchstaben umwandeln
map(penguins_df$species, toupper) %>% 
  sample(size = 5)
[[1]]
[1] "GENTOO"

[[2]]
[1] "ADELIE"

[[3]]
[1] "ADELIE"

[[4]]
[1] "GENTOO"

[[5]]
[1] "ADELIE"
Code anzeigen
# Zusätzliche Argumente übergeben
map(penguins_df$species, substr, start = 1, stop = 3) %>% 
  sample(size = 5)
[[1]]
[1] "Ade"

[[2]]
[1] "Ade"

[[3]]
[1] "Gen"

[[4]]
[1] "Gen"

[[5]]
[1] "Ade"

Ausreisser identifizieren

Ausreisser visualisieren

Ausreisser (engl. outlier) sind Werte, die eine signifikante Abweichung vom erwarteten Muster aufweisen. Ausreisser können durch natürliche Variabilität zustande kommen, aber auch auf einen experimentellen Fehler hindeuten. Ihre Identifizierung ist ein kritischer Schritt in der Datenanalyse, um statistische Ergebnisse nicht zu verfälschen und die Datenqualität zu sichern.

Mit der Funktion stats_dist() lassen sich die Verteilung und eine zusammenfassende Statistik für eine spezifische Spalte anzeigen.

Code anzeigen
# Standardthema für ggplot2-Plots festlegen
ggplot2::theme_set(theme_dv())
Code anzeigen
# Spalte auswählen
df_col <- penguins %>% 
  select(bill_length_mm) %>% 
  drop_na()

# Aufruf der Funktion stats_dist
stats_dist(df_col, 2)
[[1]]
Minimum: 32.10
Mittelwert: 43.92
Median: 44.45
Modus: 41.10
Maximum: 59.60

[[2]]

Ausreisser erkennen

Eine häufig verwendete Regel zur Identifizierung von Ausreissern besagt, dass ein Wert ein Ausreisser ist, wenn er mehr als 1.5 x IQR über dem oberen Quartil (Q3) oder unter dem unteren Quartil (Q1) liegt. Mit anderen Worten, untere Ausreisser liegen unter Q1 - 1.5 x IQR und obere Ausreisser liegen über Q3 + 1.5 x IQR.

Code anzeigen
outlier_function <- function(x) {
  df_col <- na.omit(x)
  iqr <- IQR(df_col)
  first_quantile <- quantile(df_col, probs = 0.25)
  third_quantile <- quantile(df_col, probs = 0.75)
  lower_threshold <- first_quantile - 1.5 * iqr
  upper_threshold <- third_quantile + 1.5 * iqr
  outliers <- list(lower_outliers = df_col[df_col < lower_threshold], 
                   upper_outliers = df_col[df_col > upper_threshold])
  return(outliers)
}
Code anzeigen
# Funktion «outlier_function» auf Variable anwenden
outlier_function(x = bgb_typ_clean$typ_eba)
$lower_outliers
numeric(0)

$upper_outliers
[1] 1718 2580

Ausreisser mit Z-Score erkennen

Der Z-Score bezieht sich auf die Anzahl der Standardabweichungen der einzelnen Datenwerte vom Mittelwert. Ein Z-Score von Null entspricht dem exakten Mittelwert. Ein üblicher Schwellenwert für die Identifizierung von Ausreissern ist ein Z-Score grösser als 3 oder kleiner als -3.

Code anzeigen
z_score <- scale(bgb_typ_clean$typ_eba)
ausreisser <- abs(z_score) > 3

head(ausreisser, n = 12)
       [,1]
 [1,] FALSE
 [2,] FALSE
 [3,] FALSE
 [4,] FALSE
 [5,] FALSE
 [6,] FALSE
 [7,] FALSE
 [8,] FALSE
 [9,] FALSE
[10,] FALSE
[11,] FALSE
[12,]  TRUE

Ausreisser bereinigen

Variablen können auf der Grundlage eines bestimmten Perzentils angepasst werden. Perzentile sind Lageparameter, die einen der Grösse nach geordneten Datensatz in 100 gleich grosse Teile zerlegen. Sie unterteilen den Datensatz also in 1%-Schritte.

Um sicherzustellen, dass keine wertvollen Informationen gelöscht werden, sollte das Entfernen eines bestimmten Perzentils der Daten sorgfältig geprüft werden.

Code anzeigen
# Quantile, die 1% und 99% der Daten entsprechen
pcntile01 <- penguins %>% 
  pull(bill_length_mm) %>% 
  quantile(probs = 1/100, names = FALSE, na.rm = TRUE)

pcntile99 <- penguins %>% 
  pull(bill_length_mm) %>% 
  quantile(probs = 99/100, names = FALSE, na.rm = TRUE)

# 1. und 99. Perzentil ausgeben
cat("Minimum:", min(penguins$bill_length_mm, na.rm = TRUE), "\n1. Perzentil:", pcntile01, 
    "\n99. Perzentil:", pcntile99, "\nMaximum:", max(penguins$bill_length_mm, na.rm = TRUE))
Minimum: 32.1 
1. Perzentil: 34.041 
99. Perzentil: 55.513 
Maximum: 59.6

Durch das Erstellen einer Funktion können Sie das Entfernen von Ausreissern automatisieren.

Code anzeigen
remove_outliers <- function(data) {
  data_cleaned <- data
  for (variable in names(data)) {
    z_score <- scale(data)
    outliers <- abs(z_score) > 3
    data_cleaned <- data[!apply(X = outliers, MARGIN = 1, FUN = any), ]
  }
  return(data_cleaned)
}
Code anzeigen
# Funktion «remove_outliers» anwenden
remove_outliers(data = penguins$bill_length_mm) %>% 
  head()
[1] 39.1 39.5 40.3   NA 36.7 39.3

Ausführliche Analyse

Bootstrapping

Angenommen, Sie haben einen Datensatz und möchten den Mittelwert einer Variable verstehen. Wird dieser durch wenige Ausreisser verzerrt, ist der Aussagewert jedoch gering.

Bootstrapping ist eine statistische Technik, bei der mehrere Kopien der Daten erstellt werden, von denen jede eine leichte Abweichung aufweist. Die Statistik, die Sie interessiert (z.B. der Mittelwert), wird dann für jede Kopie berechnet.

Die Funktion bootstrap_stat_plot() berechnet und visualisiert die Verteilung, so dass Sie ein klares Bild davon erhalten, wie die Statistik zwischen den verschiedenen Versionen der Daten variiert. Detaillierte Infos zur Funktion finden Sie auf der dazugehörenden Website.

Code anzeigen
x <- penguins$body_mass_g # Variable bestimmen
ns <- 1000 # Anzahl Simulationen festlegen

# Mittelwert
var_gewicht_1 <- tidy_bootstrap(.x = x, .num_sims = ns) %>% 
  bootstrap_stat_plot(.value = y, 
                      .stat = "cmean", 
                      .show_groups = TRUE, 
                      .show_ci_labels = TRUE, 
                      .interactive = FALSE)

# Minimum
var_gewicht_2 <- tidy_bootstrap(.x = x, .num_sims = ns) %>% 
  bootstrap_stat_plot(.value = y, 
                      .stat = "cmin", 
                      .show_groups = TRUE, 
                      .show_ci_labels = TRUE, 
                      .interactive = FALSE)

# Maximum
var_gewicht_3 <- tidy_bootstrap(.x = x, .num_sims = ns) %>% 
  bootstrap_stat_plot(.value = y, 
                      .stat = "cmax", 
                      .show_groups = TRUE, 
                      .show_ci_labels = TRUE, 
                      .interactive = FALSE)

# Standardabweichung
var_gewicht_4 <- tidy_bootstrap(.x = x, .num_sims = ns) %>% 
  bootstrap_stat_plot(.value = y, 
                      .stat = "csd", 
                      .show_groups = TRUE, 
                      .show_ci_labels = TRUE, 
                      .interactive = FALSE)
wrap_plots(var_gewicht_1, var_gewicht_2, var_gewicht_3, var_gewicht_4, 
           ncol = 2, 
           nrow = 2, 
           widths = c(1, 1), 
           heights = c(1, 1))

Korrelation prüfen

Die Korrelation ist ein statistisches Mass, das angibt, inwieweit zwei Variablen in einer linearen Beziehung zueinander stehen (d.h. sich in einem festen Verhältnis zueinander verändern).

Code anzeigen
# Metrisch skalierte Variablen
cor(x = penguins$bill_length_mm, 
    y = penguins$bill_depth_mm, 
    use = "complete.obs", 
    method = "pearson") # Alternativen: Spearmans Rho und Kendalls Tau für ordinale Variablen
[1] -0.2350529
Code anzeigen
# Korrelationsmatrix
cor(x = penguins[, 3:6], 
    use = "complete.obs")
                  bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
bill_length_mm         1.0000000    -0.2350529         0.6561813   0.5951098
bill_depth_mm         -0.2350529     1.0000000        -0.5838512  -0.4719156
flipper_length_mm      0.6561813    -0.5838512         1.0000000   0.8712018
body_mass_g            0.5951098    -0.4719156         0.8712018   1.0000000

Unter der Voraussetzung einer Normalverteilung und der Annahme, dass es sich bei den vorliegenden Daten um eine Stichprobe aus einer Grundgesamtheit (Population) handelt, kann mit cor.test() die Signifikanz geprüft werden.

Code anzeigen
cor.test(x = penguins_def$bill_length_mm, 
         y = penguins_def$bill_depth_mm, 
         method = "pearson")

    Pearson's product-moment correlation

data:  penguins_def$bill_length_mm and penguins_def$bill_depth_mm
t = -4.2726, df = 331, p-value = 0.00002528
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.3280409 -0.1242017
sample estimates:
       cor 
-0.2286256 
Code anzeigen
# Datensatz auf hoch korrelierte Merkmale prüfen
penguins_def %>% 
  select(where(is.numeric)) %>% 
  cor() %>% 
  corrplot(method = "circle", # Alternative: "number"
           addCoef.col = "white", 
           order = "hclust", 
           addrect = 2, 
           rect.col = "grey")

Gruppierte Zusammenfassung

In R können gruppierte Zusammenfassungen mit group_by() %>% summarise() erstellt werden. group_by() ändert dabei die Analyseeinheit vom gesamten Datensatz zu einzelnen Gruppen. summarise() erstellt einen neuen Datenrahmen für die zusammenfassende Statistik.

Code anzeigen
penguins_def %>% 
  group_by(species) %>% 
  summarise(Mittelwert_Gewicht = mean(body_mass_g)) %>% 
  arrange(desc(Mittelwert_Gewicht))
# A tibble: 3 × 2
  species   Mittelwert_Gewicht
  <fct>                  <dbl>
1 Gentoo                 5092.
2 Chinstrap              3733.
3 Adelie                 3706.

Angenommen, Sie haben viele numerische Spalten und möchten die Mittelwertfunktion auf alle Spalten anwenden. Mit across() ist es einfach, eine Funktion für mehrere Spalten zu verwenden.

Code anzeigen
penguins_def %>% 
  select(-year) %>% 
  group_by(species) %>% 
  summarise(across(where(is.numeric), mean)) # Alt.: summarise(across(c(Var1, Var2), mean))
# A tibble: 3 × 5
  species   bill_length_mm bill_depth_mm flipper_length_mm body_mass_g
  <fct>              <dbl>         <dbl>             <dbl>       <dbl>
1 Adelie              38.8          18.3              190.       3706.
2 Chinstrap           48.8          18.4              196.       3733.
3 Gentoo              47.6          15.0              217.       5092.
Code anzeigen
# Mit list() mehrere Masse der zentralen Tendenz berechnen
penguins_def %>% 
  select(-year) %>% 
  group_by(species) %>% 
  summarise(across(all_of(c("bill_length_mm", "bill_depth_mm")), 
                   list(Mittelwert = mean, 
                        Median = median)), Anzahl = n())
# A tibble: 3 × 6
  species   bill_length_mm_Mittel…¹ bill_length_mm_Median bill_depth_mm_Mittel…²
  <fct>                       <dbl>                 <dbl>                  <dbl>
1 Adelie                       38.8                  38.8                   18.3
2 Chinstrap                    48.8                  49.6                   18.4
3 Gentoo                       47.6                  47.4                   15.0
# ℹ abbreviated names: ¹​bill_length_mm_Mittelwert, ²​bill_depth_mm_Mittelwert
# ℹ 2 more variables: bill_depth_mm_Median <dbl>, Anzahl <int>
Code anzeigen
# Für komplexe zeilenweise Operationen
bgb_typ_clean_efz_eba %>% 
  rowwise() %>% 
  mutate(mittelwert_je_zeile = mean(c(typ_efz, typ_eba))) %>% 
  select(schulkanton, typ_efz, typ_eba, mittelwert_je_zeile)
# A tibble: 26 × 4
# Rowwise: 
   schulkanton      typ_efz typ_eba mittelwert_je_zeile
   <chr>              <dbl>   <dbl>               <dbl>
 1 waadt              17754    1004               9379 
 2 wallis              7634     467               4050.
 3 genf                8387     521               4454 
 4 bern               27079    1718              14398.
 5 freiburg            6682     320               3501 
 6 solothurn           5150     495               2822.
 7 neuenburg           4756     259               2508.
 8 jura                1876      71                974.
 9 basel-stadt         5305     346               2826.
10 basel-landschaft    5299     541               2920 
# ℹ 16 more rows

Top-Werte finden

Bei der Datenanalyse besteht oft die Notwendigkeit, die besten Werte innerhalb jeder Gruppe eines Datensatzes zu extrahieren. Unabhängig davon, ob es sich um Verkaufsdaten, Umfrageantworten oder eine andere Art von gruppierten Daten handelt, kann die Identifizierung der Top-Werte oder Ausreisser innerhalb jeder Gruppe wertvolle Erkenntnisse liefern.

Code anzeigen
penguins_def %>% 
  select(-c(bill_depth_mm:year)) %>% 
  group_by(species) %>% 
  top_n(n = 1, bill_length_mm) %>% 
  arrange(species, desc(bill_length_mm))
# A tibble: 3 × 3
# Groups:   species [3]
  species   island    bill_length_mm
  <fct>     <fct>              <dbl>
1 Adelie    Torgersen           46  
2 Chinstrap Dream               58  
3 Gentoo    Biscoe              59.6

Zweithöchster Wert finden

Der zweithöchste Wert einer Variable wird in R mit folgendem Code gefunden.

Code anzeigen
sort(x = penguins_def$bill_length_mm)[length(penguins_def$bill_length_mm) - 1]
[1] 58

Prozent- und Absolutwerte ausgeben

Dank tabyl() aus dem Paket janitor können Prozent- und Absolutwerte zusammen ausgegeben werden. Mit adorn() lässt sich tabyl() zudem leicht anpassen. Sie können z.B. Summen hinzufügen oder die Anzahl der Nachkommastellen für Prozentwerte festlegen.

Code anzeigen
penguins_def %>% 
  tabyl(var1 = species) %>% 
  # Gesamtsumme hinzufügen
  adorn_totals() %>% 
  # Prozentsätze formatieren
  adorn_pct_formatting() %>% 
  as_tibble()
# A tibble: 4 × 3
  species       n percent
  <fct>     <dbl> <chr>  
1 Adelie      146 43.8%  
2 Chinstrap    68 20.4%  
3 Gentoo      119 35.7%  
4 Total       333 100.0% 

Apply-Familie

Mit tapply() können Sie eine Funktion auf Untergruppen anwenden. Dies können in R vorhandene Funktionen wie mean() oder sd() sein, aber auch von Ihnen selbst geschriebene Funktionen.

tapply(X, INDEX, FUN, simplify = TRUE)

Code anzeigen
tapply(X = penguins_def$bill_length_mm, # Numerischer Wert
       INDEX = penguins_def$species, # Faktor
       FUN = mean) # Funktion
   Adelie Chinstrap    Gentoo 
 38.82397  48.83382  47.56807 

Die Funktion tapply() kann auch zusammen mit summary() verwendet werden, um einen schnellen Überblick über die Verteilung einer Variable innerhalb von Gruppen zu erhalten.

Code anzeigen
tapply(X = penguins_def$bill_length_mm, 
       INDEX = penguins_def$species, 
       FUN = summary, 
       na.rm = TRUE) # Optional
$Adelie
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  32.10   36.73   38.85   38.82   40.77   46.00 

$Chinstrap
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  40.90   46.35   49.55   48.83   51.08   58.00 

$Gentoo
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  40.90   45.35   47.40   47.57   49.60   59.60 
Code anzeigen
schnabellaenge <- function(bill, avg_bill) {
  bill > avg_bill
}

# Pinguine finden, die einen längeren Schnabel haben als der Durchschnitt
tapply(X = head(penguins_def$bill_length_mm, n = 15), 
       INDEX = head(penguins_def$species, n = 15), 
       mean(penguins_def$bill_length_mm), 
       FUN = schnabellaenge)
$Adelie
 [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[13] FALSE FALSE  TRUE

$Chinstrap
NULL

$Gentoo
NULL

Für jede Variable berechnet vapply() den Mittelwert und die Standardabweichung und gibt eine Matrix mit numerischen Werten zurück.

Code anzeigen
zahlen <- penguins_def[, c(3:5)]
vapply(X = zahlen, 
       FUN = function(x) c(m = mean(x), 
                           sd = sd(x)), 
       FUN.VALUE = numeric(2))
   bill_length_mm bill_depth_mm flipper_length_mm
m       43.992793     17.164865         200.96697
sd       5.468668      1.969235          14.01577

describeBy

Die Funktion describeBy() aus dem psych-Paket berechnet verschiedene Kennwerte für jede Faktorstufe.

Code anzeigen
describeBy(x = penguins_def$bill_length_mm, penguins_def$species, mat = TRUE)
    item    group1 vars   n     mean       sd median  trimmed     mad  min  max
X11    1    Adelie    1 146 38.82397 2.662597  38.85 38.77881 2.96520 32.1 46.0
X12    2 Chinstrap    1  68 48.83382 3.339256  49.55 48.90536 3.63237 40.9 58.0
X13    3    Gentoo    1 119 47.56807 3.106116  47.40 47.45155 3.11346 40.9 59.6
    range        skew   kurtosis        se
X11  13.9  0.15456020 -0.2197601 0.2203581
X12  17.1 -0.08661785 -0.1396985 0.4049443
X13  18.7  0.59674134  1.0696437 0.2847372

Numerische Variablen in Gruppen einteilen

Mithilfe von ntile() wird ein Eingabevektor in eine bestimmte Anzahl von Bereichen bzw. Rängen unterteilt.

Code anzeigen
# Pinguine in zwei Gewichtsgruppen einteilen
penguins_grouped <- ntile(x = penguins_def$body_mass_g, 
                          n = 2)

slice_head(.data = merge(x = penguins_grouped, y = penguins_def[, c(1, 2, 7)]), 
           n = 10) %>% 
  rename(gruppe = x)
   gruppe species    island  sex
1       1  Adelie Torgersen male
2       1  Adelie Torgersen male
3       1  Adelie Torgersen male
4       1  Adelie Torgersen male
5       1  Adelie Torgersen male
6       1  Adelie Torgersen male
7       2  Adelie Torgersen male
8       1  Adelie Torgersen male
9       1  Adelie Torgersen male
10      2  Adelie Torgersen male

Numerische Variablen vergleichen

Um zwei numerische Variablen zu vergleichen, werden die Daten zunächst mit pivot_longer() in ein Langformat umgewandelt.

Code anzeigen
# Daten von breit nach lang transformieren
penguins_long <- penguins_def %>% 
  select(-c(bill_length_mm, bill_depth_mm, sex, year)) %>% 
  pivot_longer(cols = flipper_length_mm:body_mass_g, 
               names_to = "variable", 
               values_to = "wert")

head(penguins_long, n = 10)
# A tibble: 10 × 4
   species island    variable           wert
   <fct>   <fct>     <chr>             <dbl>
 1 Adelie  Torgersen flipper_length_mm   181
 2 Adelie  Torgersen body_mass_g        3750
 3 Adelie  Torgersen flipper_length_mm   186
 4 Adelie  Torgersen body_mass_g        3800
 5 Adelie  Torgersen flipper_length_mm   195
 6 Adelie  Torgersen body_mass_g        3250
 7 Adelie  Torgersen flipper_length_mm   193
 8 Adelie  Torgersen body_mass_g        3450
 9 Adelie  Torgersen flipper_length_mm   190
10 Adelie  Torgersen body_mass_g        3650

Stack und Unstack

Das Stapeln von numerischen Variablen ist auch mit Hilfe der Funktion stack() möglich.

Code anzeigen
penguins_stack <- penguins_def %>% 
  select(bill_length_mm:flipper_length_mm) %>% 
  stack()

head(penguins_stack)
  values            ind
1   39.1 bill_length_mm
2   39.5 bill_length_mm
3   40.3 bill_length_mm
4   36.7 bill_length_mm
5   39.3 bill_length_mm
6   38.9 bill_length_mm

Für das Entstapeln wird die Funktion unstack() verwendet.

Code anzeigen
unstack(penguins_stack) %>% 
  head()
  bill_length_mm bill_depth_mm flipper_length_mm
1           39.1          18.7               181
2           39.5          17.4               186
3           40.3          18.0               195
4           36.7          19.3               193
5           39.3          20.6               190
6           38.9          17.8               181

Numerische Variablen in Balkendiagramm

Code anzeigen
options(scipen = 999)

penguins_long %>% 
  group_by(species, variable) %>% 
  summarise(summe_lv = sum(wert), .groups = "keep") %>% 
  ggplot() +
  geom_bar(mapping = aes(x = species, y = summe_lv, fill = variable), 
           alpha = 0.7, 
           stat = "identity", 
           position = position_dodge(width = 0.9)) +
  scale_y_continuous(labels = comma_format(big.mark = "'")) +
  scale_fill_paletteer_d("nbapalettes::pacers_classic") +
  labs(title = "Pinguine im Vergleich", 
       x = "Pinguinarten", 
       y = "Wert") +
  theme_minimal(base_size = 10) +
  theme_dv(axis.text.x = element_text(angle = 90, 
                                      hjust = 1), 
           panel.grid.major.y = element_line(color = "#5D5A59", 
                                             linetype = "dashed", 
                                             linewidth = 0.5)) +
  theme(legend.title = element_blank())

Numerische Variablen normalisieren

Wenn die Werte, wie im obigen Beispiel, auf unterschiedlichen Skalen liegen, sind sie nicht ohne weiteres vergleichbar. Eine gebräuchliche Technik im Umgang mit numerischen Daten besteht darin, diese so zu normalisieren, dass die Werte ihre proportionale Verteilung behalten, aber auf derselben Skala gemessen werden. Zu diesem Zweck wird eine Technik namens Min/Max-Skalierung verwendet, bei der die Werte proportional auf einer Skala von 0 bis 1 verteilt werden.

Code anzeigen
# group_by() stellt sicher, dass die Variablen unabhängig voneinander normalisiert werden.
penguins_normalized <- penguins_long %>% 
  group_by(variable) %>% 
  mutate(wert = rescale(wert, to = c(0, 1)))

head(penguins_normalized)
# A tibble: 6 × 4
# Groups:   variable [2]
  species island    variable           wert
  <fct>   <fct>     <chr>             <dbl>
1 Adelie  Torgersen flipper_length_mm 0.153
2 Adelie  Torgersen body_mass_g       0.292
3 Adelie  Torgersen flipper_length_mm 0.237
4 Adelie  Torgersen body_mass_g       0.306
5 Adelie  Torgersen flipper_length_mm 0.390
6 Adelie  Torgersen body_mass_g       0.153

Alternativ können numerische Variablen im Datensatz mit der Funktion scale() normalisiert werden. Jede Variable wird so standardisiert, dass sie einen Mittelwert von 0 und eine Standardabweichung von 1 hat.

Code anzeigen
penguins_normalized_scale <- penguins_long %>% 
  mutate(wert_normalisiert = scale(wert))
  
head(penguins_normalized_scale)
# A tibble: 6 × 5
  species island    variable           wert wert_normalisiert[,1]
  <fct>   <fct>     <chr>             <dbl>                 <dbl>
1 Adelie  Torgersen flipper_length_mm   181                -0.971
2 Adelie  Torgersen body_mass_g        3750                 0.742
3 Adelie  Torgersen flipper_length_mm   186                -0.968
4 Adelie  Torgersen body_mass_g        3800                 0.766
5 Adelie  Torgersen flipper_length_mm   195                -0.964
6 Adelie  Torgersen body_mass_g        3250                 0.502

Vergleichen Sie die numerischen Variablen erneut in einem Balkendiagramm. Diesmal wird jedoch der Datensatz mit den normalisierten Werten verwendet.

Code anzeigen
options(scipen = 999)

penguins_normalized %>% 
  group_by(species, variable) %>% 
  summarise(summe_lv = sum(wert), .groups = "keep") %>% 
  ggplot() +
  geom_bar(mapping = aes(x = species, y = summe_lv, fill = variable), 
           alpha = 0.7, 
           stat = "identity", 
           position = position_dodge(width = 0.9)) +
  scale_y_continuous(labels = comma_format(big.mark = "'")) +
  scale_fill_paletteer_d("nbapalettes::pacers_classic") +
  labs(title = "Pinguine im Vergleich", 
       x = "Pinguinarten", 
       y = "Wert") +
  theme_minimal(base_size = 10) +
  theme_dv(axis.text.x = element_text(angle = 90, 
                                      hjust = 1), 
           panel.grid.major.y = element_line(color = "#5D5A59", 
                                             linetype = "dashed", 
                                             linewidth = 0.5)) +
  theme(legend.title = element_blank())

Daten exportieren

In R bearbeitete Datensätze können in verschiedenen Formaten exportiert werden, um sie in anderen Anwendungen weiterzuverwenden. Beispielsweise kann das Paket writexl() Datensätze im Excel-Format speichern.

Datenvisualisierung

Bedeutung

Die Visualisierung von Daten ist eine effiziente Methode, neues Wissen zu entdecken und dieses Nicht-Experten mit Hilfe visueller Darstellungen auf eine zugängliche Weise zu vermitteln.

ggplot2

ggplot2 ist ein Paket zur Erstellung eleganter Datenvisualisierungen in R.

ggplot(data = df) + geom_col(mapping = aes(x = Variable_1, y = Variable_2))

Eine Visualisierung initialisieren Sie mit der Funktion ggplot() und dem Datensatz, der für die Darstellung verwendet werden soll. ggplot(data = df) erstellt im Grunde ein leeres Diagramm, dem Sie mittels Pluszeichen (+) Ebenen hinzufügen können.

geom_col() fügt dann eine Ebene von Balken hinzu, deren Höhe den Variablen entspricht, die durch das Mapping-Argument angegeben sind. Das Argument mapping ist immer mit aes() gekoppelt, das bestimmt, wie die Variablen auf der X- und Y-Achse abgebildet werden.

Code anzeigen
options(scipen = 999)

# Kombiniertes Histogramm und Dichtediagramm erstellen
penguins_def %>% 
  ggplot(mapping = aes(x = body_mass_g)) +
  geom_histogram(mapping = aes(y = after_stat(density)), 
                 bins = 10, 
                 color = "black", 
                 fill = "white") +
  geom_density(color = "#9FC131", 
               fill = "#9FC131", 
               linewidth = 1, 
               alpha = 0.2) +
  labs(title = "Histogramm und Dichtediagramm", 
       x = NULL, 
       y = "Dichte") +
  theme_minimal(base_size = 10) +
  theme_dv()

Mehrere Plots zusammen ausgeben

Mit der Funktion par() lassen sich mehrere Plots nebeneinander ausgegeben. Dies ist hilfreich, wenn man beispielsweise die Verteilung mehrerer Variablen vergleichen möchte.

Code anzeigen
par(mfrow = c(2, 2))

hist(penguins_def$bill_length_mm)
hist(penguins_def$bill_depth_mm)
hist(penguins_def$flipper_length_mm)
hist(penguins_def$body_mass_g)

Säulendiagramm

Vergrössertes Säulendiagramm

Wenn kleine Abweichungen im Säulendiagramm von Bedeutung sind, wird empfohlen, beides darzustellen. Ein normales Säulendiagramm, das bei Null beginnt, aber auch eine vergrösserte Version, die es dem Leser ermöglicht, die einzelnen Säulenwerte besser zu erkennen. Das folgende Beispiel zeigt das normale Säulendiagramm auf der rechten Seite und eine vergrösserte Version, die einen Teil der Achse zeigt, auf der linken Seite. Die Verbindungslinien zwischen den beiden Versionen zeigen, auf welchen Datenbereich sich die abgeschnittene Achse bezieht.

Ähnlich kann verfahren werden, wenn eine Säule viel länger ist als die anderen, so dass es schwierig ist, alle kleinen Säulen zu unterscheiden.

Code anzeigen
# Daten für Beispiel aufbereiten
mittlere_schnabellaenge_df <- 
  as.data.frame(mittlere_schnabellaenge) %>% 
  rownames_to_column()

colnames(mittlere_schnabellaenge_df) <- c("species", "mean_bill_length_mm")

Für die Darstellung von Diagrammen kann in R eine eigene Farbpalette definiert werden.

Code anzeigen
# Benutzerdefinierte Farbpalette erstellen
palette <- c("#9FC131", "#93257B", "#57AF2C")
Code anzeigen
mittlere_schnabellaenge_df %>% 
  ggplot(mapping = aes(x = species, y = mean_bill_length_mm, fill = species)) +
  geom_col() +
  facet_zoom(ylim = c(35, 50)) +
  scale_fill_manual(values = palette) +
  scale_y_continuous(breaks = seq(0, 50, by = 10), 
                     labels = seq(0, 50, by = 10), 
                     limits = c(0, 50), 
                     expand = c(0, 0)) +
  labs(title = "Vergrössertes Säulendiagramm", 
       x = "", 
       y = "Mittlere Schnabellänge") +
  theme_dv(legend.position = "none") +
  theme(axis.text = element_text(size = rel(0.9)), 
        panel.spacing = unit(x = c(0, 8, 0, -3.25), 
                             units = "pt"), 
        plot.title = element_text(margin = margin(t = 0, r = 0, b = 15, l = 0, 
                                                  unit = "pt")))

Verschachteltes Säulendiagramm

Gestapelte Säulen- und Flächendiagramme erschweren den Vergleich von Untergruppen, da eine gemeinsame Basislinie fehlt. Ein gruppiertes Säulendiagramm löst dieses Problem teilweise, indem die Säulen nebeneinander statt übereinander angeordnet werden. Auf diese Weise sind die Untergruppen leicht zu vergleichen, aber die Gesamtsumme jeder Gruppe ist sehr schwer zu erfassen oder muss im Kopf addiert werden. Das verschachtelte Säulendiagramm ermöglicht es, sowohl die Untergruppen als auch die Gesamtzahl auf einen Blick zu vergleichen.

Code anzeigen
# Daten für Beispiel aufbereiten
bgb_typ_clean_stacked <- bgb_typ_clean %>% 
  select(starts_with("typ"), region) %>% 
  pivot_longer(cols = !region, names_to = "typ", values_to = "wert")

bgb_typ_clean_stacked$typ[bgb_typ_clean_stacked$typ == "typ_nicht_bbg_reglementierte_berufliche_grundbildung"] <- "typ_nicht_reglementiert"
Code anzeigen
bgb_typ_clean_stacked_grouped <- bgb_typ_clean_stacked %>% 
  group_by(region, typ) %>% 
  summarise(wert = sum(wert, na.rm = TRUE))
`summarise()` has grouped output by 'region'. You can override using the
`.groups` argument.
Code anzeigen
# Summe der Lehrverträge pro Region für graue Balken berechnen
region_totals <- bgb_typ_clean_stacked %>% 
  group_by(region) %>% 
  summarise(total = sum(wert, na.rm = TRUE), 
            .groups = "drop") # Probleme mit gruppiertem Datenrahmen vermeiden
Code anzeigen
# Sicherstellen, dass Faktoren in gewünschter Reihenfolge sind
bgb_typ_clean_stacked_grouped$region <- 
  factor(x = bgb_typ_clean_stacked_grouped$region, 
         levels = c("Espace Mittelland", "Zürich", "Genferseeregion", "Ostschweiz", 
                    "Nordwestschweiz", "Zentralschweiz", "Tessin"))

bgb_typ_clean_stacked_grouped$typ <- factor(x = bgb_typ_clean_stacked_grouped$typ)

region_totals$region <- 
  factor(x = region_totals$region, 
         levels = c("Espace Mittelland", "Zürich", "Genferseeregion", "Ostschweiz", 
                    "Nordwestschweiz", "Zentralschweiz", "Tessin"))
Code anzeigen
# Ebene 1: Summe der Lehrverträge pro Region für Säulen im Hintergrund erstellen
ggplot() +
  geom_col(data = region_totals, 
           mapping = aes(x = region, y = total), 
           width = 0.8, 
           fill = "grey85", # Hellgraue Füllung
           alpha = 0.8) +
  
  # Ebene 2: Säulen nebeneinander anordnen
  geom_col(data = bgb_typ_clean_stacked_grouped, 
           mapping = aes(x = region, y = wert, fill = typ), 
           position = position_dodge(width = 0.8), 
           width = 0.7) + # Säulen etwas schmaler gestalten als graue Säulen im Hintergrund
  
  # Ebene 3: Labels für einzelne Typensäulen
  geom_text(data = bgb_typ_clean_stacked_grouped, 
            mapping = aes(x = region, y = wert, label = wert, group = typ), 
            position = position_dodge(width = 0.8), 
            size = 2.5, # Textgrösse anpassen
            vjust = -0.5, # Label über der Säule positionieren
            family = "Manrope") +
  
  # Ebene 4: Labels für die gesamte Region
  geom_text(data = region_totals, 
            mapping = aes(x = region, y = total, label = total), 
            size = 3, 
            vjust = -2.0, # Position über der grauen Säule, vertikale Position anpassen
            family = "Manrope") +
  
  # Ebene 5: Labels für Regionsnamen
  geom_text(data = region_totals, 
            mapping = aes(x = region, 
                          y = total, 
                          label = as.character(region)), # Label muss Character sein
            size = 3, 
            vjust = -3.5, # Position über dem Label mit den Gesamtwerten
            family = "Manrope", 
            fontface = "bold") +
  
  # Benutzerdefinierte Farbskala anwenden und Titel festlegen
  scale_fill_manual(labels = c("EBA", "EFZ", "Nicht reglementiert"), 
                    values = palette) +
  labs(title = "Verschachteltes Säulendiagramm") +
  
  # Theme anpassen
  theme_minimal(base_size = 10) +
  theme_dv(legend.key.size = unit(x = 0.5, units = "cm"), 
           legend.margin = margin(b = -10), 
           legend.position = "top", ) +
  theme(axis.title = element_blank(), 
        axis.text = element_blank(), 
        legend.text = element_text(size = rel(0.9)), 
        legend.title = element_blank(), 
        panel.grid.major = element_blank(), 
        plot.title = element_text(margin = margin(b = 12))
        ) +
  
  # Platz für Beschriftungen über grauen Säulen schaffen
  scale_y_continuous(limits = c(0, max(region_totals$total) * 1.25), # Oben ca. 25% zus. Platz 
                     expand = expansion(mult = c(0, 0))) # Y-Achse bei 0 beginnen

Balkendiagramm

Gestapeltes Balkendiagramm

Ein gestapeltes Balkendiagramm wird verwendet, um die kumulierten Prozentsätze pro Gruppe anzuzeigen.

Code anzeigen
bgb_typ_clean_stacked %>% 
  na.omit() %>% 
  ggplot(mapping = aes(x = factor(region), y = wert, fill = factor(typ))) +
  geom_bar(stat = "identity", position = "fill") +
  scale_fill_manual(labels = c("EBA", "EFZ", "Nicht reglementiert"), 
                    values = palette, na.value = "#5D5A59") +
  scale_y_continuous(labels = scales::percent_format()) +
  labs(title = "Gestapeltes Balkendiagramm", 
       x = "Region", 
       y = "Prozentualer Anteil", 
       fill = "Typ") +
  theme_minimal(base_size = 10) +
  theme_dv() +
  coord_flip()

Waffeldiagramm

Waffeldiagramm für Zeitreihen

Das Waffeldiagramm eignet sich für verschiedene Anwendungsfälle, wie z.B. Verteilungsdiagramme oder Zeitreihen.

Code anzeigen
# Daten für Beispiel aufbereiten
penguins_df <- penguins_def %>% 
  count(year, species)
Code anzeigen
penguins_df %>% 
  ggplot(mapping = aes(fill = species, values = n)) +
  geom_waffle(n_rows = 5, flip = TRUE, size = 0.25, colour = "white") +
  facet_wrap(~ year, nrow = 1, strip.position = "bottom") +
  scale_x_discrete() +
  scale_y_continuous(labels = function(x) x * 5, # Multiplikator mit n_rows gleichsetzen
                     expand = c(0, 0)) +
  scale_fill_manual(values = palette) +
  coord_equal() +
  labs(title = "Waffeldiagramm für Zeitreihen", 
       subtitle = "Anzahl erfasster Pinguine nach Art und Messjahr") +
  theme_minimal(base_size = 10) +
  theme_dv(legend.key.height = unit(x = 14, 
                                    units = "pt"), 
           legend.key.width = unit(x = 20, 
                                   units = "pt"), 
           legend.spacing = unit(x = 14, 
                                 units = "pt"), 
           legend.position = "top", 
           plot.title.position = "plot") +
  theme(axis.title = element_blank(), 
        legend.title = element_blank(), 
        panel.spacing.x = unit(x = 18, 
                               units = "pt"), 
        plot.subtitle = element_text(margin = margin(t = 2, r = 0, b = 8, l = 0, 
                                                     unit = "pt")), 
        plot.margin = unit(x = c(19, 64, 8, 64), 
                           units = "pt"))

Dichteplot

In der Statistik geht es oft darum, Stichproben von Daten zu nehmen und mithilfe von Wahrscheinlichkeitsfunktionen Informationen über die gesamte Datenpopulation (Grundgesamtheit) zu extrapolieren. Mit einer ausreichenden Anzahl dieser Zufallsvariablen können Sie eine sogenannte Wahrscheinlichkeitsdichtefunktion berechnen, welche die Verteilung der Variable für die gesamte Population schätzt.

Ein Dichteplot ist eine Darstellung der Verteilung einer numerischen Variable. Es handelt sich um eine geglättete Version des Histogramms und wird häufig in der gleichen Situation verwendet. geom_density() berechnet und zeichnet eine solche Kernel-Dichte-Schätzung.

Code anzeigen
# Spalte auswählen
df_col <- penguins_def %>% 
  select(body_mass_g)

# Aufruf der Funktion show_dens
show_dens(var_data = df_col)

Boxplot

Boxplot mit Jitter

Ein Boxplot fasst die Verteilung einer numerischen Variablen in einer oder mehreren Gruppen zusammen und ist daher ein praktisches Werkzeug, um Unterschiede zwischen diesen Gruppen schnell zu erfassen. Diese Zusammenfassung kann jedoch auch dazu führen, dass wichtige Informationen verloren gehen, was ein potenzieller Stolperstein sein kann. Wenn die Datenmenge, mit der Sie arbeiten, nicht zu gross ist, kann das Hinzufügen von Jitter zu Ihrem Boxplot das Diagramm aussagekräftiger machen.

Code anzeigen
penguins_group <- penguins_def %>% 
  group_by(species) %>% 
  summarise(num = n())

penguins_def %>% 
  left_join(y = penguins_group, 
            by = join_by(species)) %>% 
  mutate(myaxis = paste0(species, "\n", "n = ", num)) %>% 
  ggplot(mapping = aes(x = myaxis, y = body_mass_g)) +
  geom_boxplot() +
  geom_jitter(colour = "grey", size = 1.1, alpha = 0.6) +
  labs(title = "Boxplot mit Jitter", 
       x = "Pinguinarten", 
       y = "Wert") +
  theme_minimal(base_size = 10) +
  theme_dv(legend.position = "none")

Boxplot mit Streudiagramm

Code anzeigen
penguins_def %>% 
  ggplot(mapping = aes(x = body_mass_g, y = 1)) +
  stat_dist_halfeye(fill = "#93257B") +
  geom_point(mapping = aes(y = 0.75), 
             shape = 21, 
             colour = "#9FC131", 
             size = 4, 
             fill = "#9FC131", 
             alpha = 0.7, 
             position = position_jitter(height = 0.1, 
                                        seed = 1234)) +
  geom_boxplot(width = 0.25, 
               colour = "black", 
               linewidth = 1) +
  labs(title = "Boxplot mit Streudiagramm", 
       x = "Wert", 
       y = element_blank()) +
  theme_minimal(base_size = 10) +
  theme_dv(legend.position = "none", panel.grid.major.y = element_blank()) +
  coord_cartesian(xlim = range(penguins_def$body_mass_g))
Warning: `label` cannot be a <ggplot2::element_blank> object.

Regenwolkenplot

Das Regenwolkendiagramm ist eine Kombination aus Boxplot und Violinplot mit einem Histogramm zur detaillierten Darstellung der Daten.

Code anzeigen
penguins_def %>% 
  ggplot(mapping = aes(x = body_mass_g, y = 1)) +
  stat_halfeye(fill = "#93257B") +
  stat_dots(mapping = aes(y = 0.8), 
            colour = "#9FC131", 
            fill = "#9FC131", 
            side = "bottom") +
  geom_boxplot(width = 0.25, 
               colour = "black", 
               linewidth = 1) +
  labs(title = "Regenwolkenplot", 
       x = "Wert", 
       y = element_blank()) +
  theme_minimal(base_size = 10) +
  theme_dv(legend.position = "none", panel.grid.major.y = element_blank()) +
  coord_cartesian(xlim = range(penguins_def$body_mass_g))
Warning: `label` cannot be a <ggplot2::element_blank> object.

Violinplot

Violinplot mit statistischen Kennwerten

Ein Violinplot (manchmal auch als Geigenplot bezeichnet) ist eine Art der Datenvisualisierung, die einen Boxplot und ein Kerndichtediagramm kombiniert, um die Verteilung einer numerischen Variablen über verschiedene Gruppen oder Kategorien darzustellen. Er kann dabei helfen, Form, Verteilung und Ausreisser der Daten zu vergleichen und multimodale Muster zu identifizieren.

Code anzeigen
penguins_def %>% 
  ggbetweenstats(x = species, y = bill_length_mm) +
  labs(title = "Violinplot mit statistischen Kennwerten", 
       x = "Pinguinarten", 
       y = "Schnabellänge") +
  theme_minimal(base_size = 10) +
  theme_dv(legend.position = "none", 
           plot.title.position = "plot") +
  theme(plot.subtitle = element_text(size = rel(1.1), 
                                     margin = margin(t = 0, r = 0, b = 8, l = 0, 
                                                     unit = "pt")))

Streudiagramm

Symmetrisches Streudiagramm

Bei der Darstellung der Residuen eines linearen Regressionsmodells wird u. a. darauf geachtet, wie die Punkte um die Nulllinie verteilt sind. Bei Residuendiagrammen führen die Standardeinstellungen oft zu einer y-Achse, die nicht symmetrisch um 0 ist. Dies kann die Vergleichbarkeit erschweren. Wenn die y-Achse symmetrisch um den Nullpunkt gelegt und eine Nulllinie hinzugefügt wird, ist es einfacher zu erkennen, ob mehr Punkte über oder unter dem Nullpunkt liegen.

Code anzeigen
# Daten für Beispiel aufbereiten
penguins_adelie <- 
  penguins_def %>% 
  filter(species == "Adelie")

# Modell erstellen
fit <- lm(formula = body_mass_g ~ bill_length_mm, data = penguins_adelie)

fit_df <- broom::augment(fit)
Code anzeigen
fit_df %>% 
  ggplot(mapping = aes(x = .fitted, y = .resid)) +
  geom_point() +
  geom_hline(yintercept = 0, 
             colour = "#9FC131") +
  scale_y_continuous(limits = c(-1200, 1200), 
                     expand = c(0, 0)) +
  labs(title = "Symmetrisches Streudiagramm", 
       x = "", 
       y = "") +
  theme_minimal(base_size = 10) +
  theme_dv()

Streudiagramm mit Quantilsanzeige

Das Quantil kann für den ausgewählten Datensatz und die Variable flexibel gewählt werden.

Code anzeigen
highlight_points(var_data = penguins_def, 
                 df_col = penguins_def$bill_length_mm, 
                 quantiles = c(0.25, 0.5))
Warning: `label` cannot be a <ggplot2::element_blank> object.

Randdiagramm

Ein Randdiagramm ist ein Streudiagramm mit Histogrammen, Boxplots oder Dichtediagrammen an den Rändern der x- und y-Achse. Es ermöglicht die Untersuchung der Beziehung zwischen zwei numerischen Variablen. Die Randdiagramme werden in der Regel am oberen und rechten Rand des Basisdiagramms dargestellt und zeigen die Verteilung der Variablen. Dies hilft, die Verteilung für verschiedene Variablenwerte entlang der beiden Achsen zu visualisieren.

Code anzeigen
plot <- penguins_def %>% 
  ggplot(mapping = aes(x = bill_depth_mm, y = bill_length_mm)) +
  geom_point() +
  labs(title = "Randdiagramm", 
       subtitle = "Streudiagramm mit Histogramm", 
       x = "Schnabeltiefe", 
       y = "Schnabellänge") +
  theme_minimal(base_size = 10) +
  theme_dv(legend.position = "none") +
  theme(text = element_text(family = "Arial"), 
        plot.subtitle = element_text(margin = margin(t = 0, r = 0, b = 8, l = 0, 
                                                     unit = "pt")))
Code anzeigen
ggExtra::ggMarginal(p = plot, 
                    type = "histogram", 
                    size = 10, 
                    colour = NA, 
                    fill = "#9FC131")

Treemap

Eine Treemap stellt hierarchische Daten als eine Reihe von verschachtelten Rechtecken dar. Jede Gruppe wird durch ein Rechteck dargestellt, dessen Fläche proportional zu ihrem Wert ist.

Code anzeigen
penguins_def %>% 
  group_by(island, species) %>% 
  summarise(mittelwert_gewicht = mean(body_mass_g)) %>% 
  treemap(index = c("island", "species"), 
          vSize = "mittelwert_gewicht", 
          vColor = "island", 
          type = "categorical", 
          title = "Verteilung der Pinguinarten", 
          palette = alpha(palette, alpha = 0.8), # Alt.: brewer.pal(n = 3, name = "Pastel1")
          fontsize.title = 17.5, 
          fontsize.labels = 13, 
          bg.labels = 0, 
          align.labels = list(c("left", "top"), c("right", "bottom")), 
          position.legend = "none")
`summarise()` has grouped output by 'island'. You can override using the
`.groups` argument.

Multidimensionale Skalierung

Die Visualisierung von Ähnlichkeiten zwischen Datenpunkten kann schwierig sein, insbesondere wenn es sich um viele Merkmale handelt. Hier kommt die multidimensionale Skalierung (MDS) ins Spiel. Sie ermöglicht die Untersuchung dieser Beziehungen in einem niedrigdimensionalen Raum, typischerweise 2D oder 3D, um die Interpretation zu erleichtern.

Code anzeigen
# Relevante numerische Merkmale auswählen (für eine bestimmte Anzahl Zeilen)
mds_features <- penguins_def[11:20, c(3:6)]

# Paarweise Abstände zwischen Merkmalen berechnen
mds_matrix <- dist(mds_features)

# head(mds_matrix)
Code anzeigen
# MDS durchführen, um eine 2D-Darstellung zu erhalten
mds_results <- cmdscale(d = mds_matrix, k = 2)

# head(mds_results, n = 3)
Code anzeigen
# R-Basisplot erstellen
plot(x = mds_results[, 1], y = mds_results[, 2], 
     main = "Multidimensionale Skalierung für Pinguine", 
     xlab = "Dimension 1", 
     ylab = "Dimension 2")

# Textbeschriftungen hinzufügen (optional)
text(mds_results, labels = penguins_def$species, col = "#9FC131", cex = 0.62, pos = 1)

Dynamische Grafiken

Ergänzend zu den statischen Datenvisualisierungen mit plot() oder ggplot2 gibt es für R verschiedene Pakete, mit denen Sie interaktive und dynamische Grafiken erstellen können.

Beispiele:

Interaktive Tabellen

gt

Ob für Berichte, Präsentationen oder wissenschaftliche Arbeiten, gt ermöglicht die Erstellung optisch ansprechender Tabellen mit detaillierter Kontrolle über die Formatierung und ist damit ein unverzichtbares Werkzeug für die professionelle Präsentation Ihrer Daten.

reactable

Das reactable-Paket basiert auf der JavaScript-Bibliothek «React Table» und ist ein flexibles Werkzeug zur Erstellung interaktiver und anpassbarer Tabellen in Webanwendungen und R Shiny Dashboards.

Abschliessende Worte

Fazit

Durch die Verwendung der sechs Verben (filtern, anordnen, auswählen, mutieren, gruppieren und zusammenfassen), die Sie in dieser Anleitung gelernt haben, sind Sie auf dem besten Weg, die meisten Herausforderungen bei der Datenanalyse in R zu lösen. Datenvisualisierungen mit ggplot2 erleichtern zudem das Erkennen komplexer Zusammenhänge während der Datenanalyse und schaffen Klarheit bei der Präsentation vor dem Auftraggeber.

Ausblick auf Machine Learning

Prolog

Maschinelles Lernen wird in R mit dem Paket caret oder dem tidymodels-Framework (https://www.tidymodels.org) realisiert. Ein einfacher Ansatz für maschinelles Lernen (ML) ist z.B. die Erstellung eines linearen Regressionsmodells mit der Funktion lm().

tidyAML

tidyAML ist ein R-Paket, das es ermöglicht, das tidymodels-Ökosystem zu nutzen, um automatisiertes maschinelles Lernen (AutoML) durchzuführen, insbesondere wenn keine Feinabstimmung erforderlich ist. Mit tidyAML können Benutzer viele hochwertige maschinelle Lernmodelle und Vorhersagen auf einmal erstellen. Ein Sicherheitsmechanismus stellt sicher, dass das Paket korrekt fehlschlägt, wenn die erforderlichen Erweiterungspakete nicht installiert sind.

Es ist möglich, die gewünschten Modelle auszuwählen, indem man entweder die unterstützten Parsnip-Funktionen wie linear_reg() oder die gewünschte Engine auswählt; man kann auch beide zusammen verwenden.

Code anzeigen
fast_regression_parsnip_spec_tbl(.parsnip_fns = "linear_reg", 
                                 .parsnip_eng = c("lm", "glm"))
# A tibble: 2 × 5
  .model_id .parsnip_engine .parsnip_mode .parsnip_fns model_spec
      <int> <chr>           <chr>         <chr>        <list>    
1         1 lm              regression    linear_reg   <spec[+]> 
2         2 glm             regression    linear_reg   <spec[+]> 

Lineare Regression

Die Funktion fast_regression() verwendet Ihre Daten und das Rezeptobjekt, um mehrere Regressionsmodelle mit einer Vielzahl von Engines und Funktionen aus dem Paket parsnip zu generieren.

Code anzeigen
rec_obj <- recipe(formula = mpg ~ ., data = mtcars) #  Vorverarbeitungsschritte festlegen

rec_obj
── Recipe ──────────────────────────────────────────────────────────────────────
── Inputs 
Number of variables by role
outcome:    1
predictor: 10
Code anzeigen
fast_reg_tbl <- fast_regression(.data = mtcars, 
                                .rec_obj = rec_obj, 
                                .parsnip_fns = "linear_reg", # Standardwert: "all"
                                .parsnip_eng = c("lm", "glm")) # Standardwert: "all"
# Weitere Funktionsargumente:
# .split_type: (Standardwert: "initial_split"), .split_args, .drop_na (Standardwert: TRUE)

fast_reg_tbl
# A tibble: 2 × 8
  .model_id .parsnip_engine .parsnip_mode .parsnip_fns model_spec wflw      
      <int> <chr>           <chr>         <chr>        <list>     <list>    
1         1 lm              regression    linear_reg   <spec[+]>  <workflow>
2         2 glm             regression    linear_reg   <spec[+]>  <workflow>
# ℹ 2 more variables: fitted_wflw <list>, pred_wflw <list>

Mit der Funktion extract_regression_residuals() lassen sich die Residuen der angepassten Modelle zusammen mit den ursprünglichen und den vorhergesagten Daten extrahieren.

Code anzeigen
extract_regression_residuals(.model_tbl = fast_reg_tbl)
[[1]]
# A tibble: 32 × 4
   .model_type     .actual .predicted .resid
   <chr>             <dbl>      <dbl>  <dbl>
 1 lm - linear_reg    17.3      16.1   1.18 
 2 lm - linear_reg    18.7      18.6   0.120
 3 lm - linear_reg    10.4       9.26  1.14 
 4 lm - linear_reg    21.4      21.8  -0.422
 5 lm - linear_reg    15.8      18.4  -2.65 
 6 lm - linear_reg    14.3      14.7  -0.360
 7 lm - linear_reg    10.4      11.2  -0.769
 8 lm - linear_reg    15.2      18.4  -3.18 
 9 lm - linear_reg    33.9      30.1   3.83 
10 lm - linear_reg    24.4      23.6   0.819
# ℹ 22 more rows

[[2]]
# A tibble: 32 × 4
   .model_type      .actual .predicted .resid
   <chr>              <dbl>      <dbl>  <dbl>
 1 glm - linear_reg    17.3      16.1   1.18 
 2 glm - linear_reg    18.7      18.6   0.120
 3 glm - linear_reg    10.4       9.26  1.14 
 4 glm - linear_reg    21.4      21.8  -0.422
 5 glm - linear_reg    15.8      18.4  -2.65 
 6 glm - linear_reg    14.3      14.7  -0.360
 7 glm - linear_reg    10.4      11.2  -0.769
 8 glm - linear_reg    15.2      18.4  -3.18 
 9 glm - linear_reg    33.9      30.1   3.83 
10 glm - linear_reg    24.4      23.6   0.819
# ℹ 22 more rows

Die Qualität der Modelle kann durch Visualisierung mit den beiden Funktionen plot_regression_residuals() und plot_regression_predictions() überprüft werden. Damit können die Residuen sowie ein Vergleich zwischen Vorhersage und Wirklichkeit dargestellt und mögliche Probleme identifiziert werden.

Code anzeigen
extract_regression_residuals(.model_tbl = fast_reg_tbl) %>% 
  plot_regression_residuals()
[[1]]


[[2]]

Code anzeigen
extract_wflw_pred(.data = fast_reg_tbl, 
                  .model_id = 1:nrow(fast_reg_tbl)) %>% 
  plot_regression_predictions()
[[1]]
Warning: Removed 32 rows containing missing values or values outside the scale range
(`geom_line()`).
Warning: Removed 40 rows containing missing values or values outside the scale range
(`geom_line()`).
Warning: Removed 56 rows containing missing values or values outside the scale range
(`geom_line()`).


[[2]]
Warning: Removed 32 rows containing missing values or values outside the scale range
(`geom_line()`).
Warning: Removed 40 rows containing missing values or values outside the scale range
(`geom_line()`).
Warning: Removed 56 rows containing missing values or values outside the scale range
(`geom_line()`).

Quarto

Quarto ermöglicht es, Inhalte und ausführbaren Code in einem Dokument zu kombinieren. Mehr über Quarto erfahren Sie unter https://quarto.org.