Piping

Nachdem nun die gängigsten Funktionen vorgestellt wurden, stellen wir vor, wie die Modularisierung bzw. das piping mit dplyr funktioniert. Wie schon oben genannt ist ein immenser Vorteil von dplyr, dass die Operationen gepipt werden, also in einzelne Bausteine aufgeteilt werden, die leicht nachzuvollziehen sind.

Über das Piping werden Datensätze oder tibbles aus vorherigen Operationen weitergegeben. Dies erfolgt über den Operator %>%. Schauen wir ein erstes Beispiel an:

pss <- pss %>%
  group_by(district) %>%
  mutate(
    wkhtotMean = mean(
      wkhtot, 
      na.rm = TRUE
    )
  ) %>%
  ungroup() 

Zuerst übergeben wir den geladenen Datensatz pss. Danach führen wir drei Operationen am Datensatz aus: group_by(), mutate() und ungroup(). Anschließend übergeben wir das bearbeitete Objekt mit den Zuordnungspfeilen -> wieder an das ursprüngliche Objekt (wir überschreiben es also!).

Das Beispiel berechnet die durchschnittliche Arbeitszeit nach Distrikt und speichert dies in der neuen Variable wkhtotMean. Damit diese auch im Datensatz pss gespeichert wird, speichern wir diese Schritte mit dem Zuordnungspfeil wieder in das Objekt pss.

Da wir den Datensatz übergeben, müssen wir diesen in den einzelnen Operationen nicht mehr aufrufen. Die Piping-Operatoren muss man nicht immer händisch eingeben, sondern dieser wird automatisch mit [Strg] + [Shift] + [M] (Windows) bzw. [Cmd] + [Shift] = [M] (Mac) eingefügt.

Im nachfolgenden wollen wir verschiedene Vorbereitungsschritte mit piping durchführen.

Berechnen und Recodieren von Variablen

Im Beispiel möchten wir nun eine neue Variable schaffen, die danach unterscheidet wie viel Vertrauen Personen in Politiker:innen haben (trstplt). So möchten wir zwischen geringem, mittlerem und hohem Vertrauen unterscheiden.

pss <- pss %>%
  mutate(
    trstpltG = case_when(
      trstplt <= 3 ~ "low", 
      trstplt > 3 & trstplt <= 6 ~ "medium", 
      trstplt > 6 ~ "high"
    )
  )
table(pss$trstpltG)
## 
##   high    low medium 
##    844   1275   2870

Wenn man nun die neue Variable prüft, wird ersichtlich, dass die neue Variable als Typ character gespeichert wurde.

str(pss$trstpltG)
##  chr [1:5000] "medium" "medium" "medium" "medium" "medium" "low" "medium" ...

Dies kann ganz normal geändert werden, oder man schreibt es direkt ins Piping:

pss <- pss %>%
  mutate(
    trstpltG = case_when(
      trstplt <= 3 ~ "low", 
      trstplt > 3 & trstplt <= 6 ~ "medium", 
      trstplt > 6 ~ "high"
    )
  ) %>% 
  mutate(trstpltG = factor(trstpltG)) #Schritt um von Character auf Factor zu kommen!

table(pss$trstpltG)
## 
##   high    low medium 
##    844   1275   2870
str(pss$trstpltG)
##  Factor w/ 3 levels "high","low","medium": 3 3 3 3 3 2 3 3 2 3 ...

Jetzt haben wir einen Faktor, aber noch ohne Ordnung, das können wir ebenfalls beheben:

pss <- pss %>%
  mutate(
    trstpltG = case_when(
      trstplt <= 3 ~ "low", 
      trstplt > 3 & trstplt <= 6 ~ "medium", 
      trstplt > 6 ~ "high"
    )
  ) %>% 
  mutate(
    trstpltG = factor(
      trstpltG,
      ordered = TRUE, 
      levels = c(
        "low", 
        "medium", 
        "high"
      )
    ) 
  )

table(pss$trstpltG)
## 
##    low medium   high 
##   1275   2870    844
str(pss$trstpltG)
##  Ord.factor w/ 3 levels "low"<"medium"<..: 2 2 2 2 2 1 2 2 1 2 ...

Etwas komplexer wäre folgende Aufgabe: Wir wollen nicht nur den Mittelwert der Arbeitszeit pro Distrikt berechnen, sondern die Abweichung einer Person im jeweiligen Distrikt vom Mittelwert des Distrikts!

pss <- pss %>%
  group_by(district) %>%
  mutate(
    wkhtotMean = mean(
      wkhtot, 
      na.rm = TRUE
    ),
    wkhtotDist = wkhtot - wkhtotMean  # wir fügen einfach diese einfache Berechnung des Abstands hinzu
  ) %>%
  ungroup()

head(
  pss[, 
      c(
        "district", 
        "wkhtot",
        "wkhtotMean",
        "wkhtotDist"
      )
  ]
)
## # A tibble: 6 × 4
##   district   wkhtot wkhtotMean wkhtotDist
##   <fct>       <dbl>      <dbl>      <dbl>
## 1 Distrikt 1     34       31.8       2.19
## 2 Distrikt 1     20       31.8     -11.8 
## 3 Distrikt 1     27       31.8      -4.81
## 4 Distrikt 1     30       31.8      -1.81
## 5 Distrikt 1     29       31.8      -2.81
## 6 Distrikt 1     30       31.8      -1.81

Hier können wir jetzt auch einen Vorteil des modularen Prinzips erkennen. Wenn wir neue Variablen (hier wkhtotMean) berechnen und weitergeben, können wir diese in den folgenden Operationen direkt nutzen.

Alternativ könnten wir die Daten auch hierarchisch gruppieren nach Distrikt und Bildung (edu) und uns dann einfach die unterschiedlichen Mittelwerte mit summarize() ausgeben lassen:

meansDistriktEdu <- pss %>%
  group_by(
    district,
    edu
  ) %>%
  summarize(mean(wkhtot)) 

meansDistriktEdu
## # A tibble: 29 × 3
## # Groups:   district [5]
##    district   edu          `mean(wkhtot)`
##    <fct>      <fct>                 <dbl>
##  1 Distrikt 1 ES-ISCED I             33.8
##  2 Distrikt 1 ES-ISCED II            33.2
##  3 Distrikt 1 ES-ISCED III           32.4
##  4 Distrikt 1 ES-ISCED IV            31.8
##  5 Distrikt 1 ES-ISCED V             29.5
##  6 Distrikt 1 <NA>                   31.0
##  7 Distrikt 5 ES-ISCED I             34.1
##  8 Distrikt 5 ES-ISCED II            33.6
##  9 Distrikt 5 ES-ISCED III           33.2
## 10 Distrikt 5 ES-ISCED IV            32.2
## # ℹ 19 more rows

Wir gehen jetzt nochmal einen Schritt zurück und schauen uns an, wie wir Datensätze teilen können. Dies ist relevant unter anderem in der Arbeit mit Sekundärdatensätze, da diese manchmal für mehr Personen erhoben wurden, als man selbst für seinen Forschungszweck benötigt.