Kapitel 6 Tidyverse

Das Tidyverse ist eine Weiterentwicklung von R, die maßgeblich von Hadley Wickham vorangetrieben wurde (weshalb auch die Bezeichung Hadleyverse noch gebräuchlich ist. Wickham ist mittlerweile Chefentwickler von RStudio). Das Standardwerk zum Tiddyverse “R for Data Science” (kurz R4DS) stammt ebenfalls von Wickham,5 und ist online frei verfügbar unter https://r4ds.had.co.nz/ (eine physische Kopie des Buches kann ebenfalls gekauft werden).

Das Tidyverse folgt streng dem Konzept Tidy Data6, welches besagt, dass ein Datensatz so aufgebaut sein muss, dass jeweils ein Fall pro Zeile abgebildet wird. Das bedeutet, dass jede Beobachtung (auch Wiederholungen) in einer eigenen Zeile steht, und die jeweiligen Variablen durch die Spalten repräsentiert werden.

Abbildung 6.1: Tidy Data Konzept

Abbildung 6.1 zeigt die Sicht auf ein Datenobjekt nach dem Tidy Data Konzept. Jede Variable wird als eigene Spalte dargestellt. Jede Reihe entspricht einer Beobachtung. Somit entsprechen die einzelnen Werte in der Tabelle genau einer Variable zu einer Beobachtung.

Man spricht in diesem Zusammenhang von “long table” und “wide table.”

Die Matrix der Pflegeberufe, die wir aus Abbildung 4.5 übernommen haben, stellt dabei die wide table, die breite Tabelle dar.

                         1999   2001   2003   2005   2007   2009   2011   2013   2015
Krankenpflegeassistenz  16624  19061  19478  21537  27731  36481  46517  54371  64127
Altenpflegehilfe        55770  52710  49727  45776  48326  47903  47978  48363  49507
Kinderkrankenpflege     47779  48203  48822  48519  49080  49307  48291  48937  48913
Krankenpflege          430983 436767 444783 449355 457322 465446 468192 472580 476416
Altenpflege            109161 124879 141965 158817 178902 194195 208304 227154 246412

“Breit” bedeutet, dass die Tabelle, wenn wir ihr nun 10 weitere Jahrgänge hinzufügen würden, immer breiter und breiter werden würde. Die wide table ist als Darstellung der Daten sicherlich gut geeignet, und die Leser erhalten eine gute Übersicht. Für die Datenanalyse und -verarbeitung ist dieses Format eher ungeeignet, da mit jedem Wert in der Tabelle eigentlich zwei Variablen andressiert werden (konkrete Berufsgruppe in einem konkreten Jahr). Welche beiden Variablen das nun genau sind, lässt sich am Wert alleine nicht ablesen, und wir hätten große Probleme, wenn Zeilen und Spalten nicht benannt wären!

Als Faustregel kann man sich merken, dass eine wide table dann vorliegt, wenn auch (bedeutsame) Zeilennamen im Datensatz vergeben wurden (was bei einer matrix häufig der Fall ist).

Ein Datensatz nach dem Tidy Data-Konzept ist vom Typ long table.

Für die Matrix der Pflegeberufe sähe die long table-Version das Datensatzes so aus:

   Jahr           Berufsgruppe Anzahl
1  1999 Krankenpflegeassistenz  16624
2  2001 Krankenpflegeassistenz  19061
3  2003 Krankenpflegeassistenz  19478
4  2005 Krankenpflegeassistenz  21537
5  2007 Krankenpflegeassistenz  27731
6  2009 Krankenpflegeassistenz  36481
7  2011 Krankenpflegeassistenz  46517
8  2013 Krankenpflegeassistenz  54371
9  2015 Krankenpflegeassistenz  64127
10 1999       Altenpflegehilfe  55770
11 2001       Altenpflegehilfe  52710
12 2003       Altenpflegehilfe  49727
            ( . . . )

Jede Spalte repräsentiert eine Variable, und jede Zeile repräsentiert eine Beobachtung. Auch ohne die Spaltennamen (Zeilennamen gibt es gar keine) könnten wir erkennen, worum es in dem Datensatz geht.

Der Name long table leitet sich davon ab, dass die Tabelle, wenn wir ihr mehr Daten hinzufügen würden, immer länger und länger werden würde.

Die Tatsache, dass die Verarbeitung solcher long tables wesentlich einfacher ist, bildet den Grundgedanken des Tidyverse, und es wurden spezielle R-Erweitrungen implementiert, die speziell an Tidy Data angepasst sind. Die Erweiterungen wurden nach dieser gemeinsame Philosophie entworfen, sie verwenden die selbe “Grammatik” und greifen auf die selbe Datenstruktur (tibbles, dazu später mehr) zurück.

Abbildung 6.2: Tidy Data Konzept

Abbildung 6.2 zeigt den typischen Ablauf einer Datenauswertung in 4 Schritten.

  1. Die Daten müssen importiert und

  2. gegebenenfalls angepasst (ins tidy data bzw. long table Format überführt werden).

  3. Anschließend werden die Daten “statistisch ausgewertet,” d.h. wir versuchen zu verstehen, was wir in den Daten sehen und welche spezifischen Informationen extrahiert werden können. Das heisst die Daten werden transformiert (z.B. indem man Untergruppen bildet) und visualisiert (z.B. in Form von Diagrammen und Tabellen) oder wir rechnen Modelle wie Korrelationen, Regressionen und Signifikanztests.

  4. Unsere Erkenntnisse nutzen wir dann zur Kommunikation (Präsentation) unserer Forschungsergebnisse.

Für all diese Arbeitsschritte stellt das Tidyverse passende Pakete und Funktionen in R zur Verfügung, und wir werden die Schritte nun einzeln durchlaufen.

6.1 Pakete

In R besteht das Tidyverse im Wesentlichen aus dem Zusatzpaket tidyverse, welches alle notwendingen Unterpakete als Abhängigkeit mit-installiert:

  1. Tibble, die Datenklasse im Tidyverse, im Paket

    • tibble, mit den Funktionen
      tibble() as_tibble()
  2. Daten importieren:

    • readr, mit den Funktionen
      read_csv(), read_tsv(), read_delim(), read_table()
  3. Daten tidy machen:

    • tidyr, mit den Funktionen
      pivot_longer(), pivot_wider(), separate(), unite(), drop_na(), replace_na(), fill(), complete(), expand()

    • forcats, mit den Funktionen
      as_factor()

  4. Umgang mit Datensätzen:

    • dplyr, mit den Funktionen
      arrange(), filter(), select(), pull(), mutate(), transmute(), rename(), summarise(), bind_cols(), bind_rows()

    • purrr, mit den Funktionen
      modify(), map(), reduce(), nest()

    • stringr, mit den Funktionen
      str_sub(), bind_locate(), bind_extract(), bind_count(), bind_match()

  5. Daten visualisieren:

    • ggplot, mit den Funktionen
      ggplot(), qplot()

Dazu später mehr, denn um die Funktionen vorzustellen, müssen wir uns zunächst der Pipe zuwenden.

6.2 Pipe

Ein wichtiger Operator für die Arbeit im Tidyverse ist die Pipe aus dem magrittr-Zusatzpaket (die Pipe wird mit tidyverse aktiviert, Sie müssen magrittr nicht extra installieren.). Sie erlaubt es, Datenströme weiterzuleiten.

Hierfür wurde ein eigener Operator implementiert, die Zeichenkette %>%

Sie bedeutet so viel wie “und dann.”

Zur Eklärung sei der “klassische Weg” der Arbeitsschritte in R aufgezeigt:

# wir machen etwas, und speichern es in ein Objekt 
habe.getan <- mache.etwas(Datensatz)

# dann machen wir etwas weiteres, 
# und speichern wieder in ein Objekt
habe.weiteres.getan <- mache.weiteres(habe.getan)

# und kommen schließlich zum Endergebnis 
endergebnis <- mache.noch.letzte.Sache(habe.weiteres.getan)

Mit Einsatz der Pipe wird dieser Prozess quasi umgekehrt in

# Speichere Endergebnis 
endergebnis <- Datensatz %>% 
                gruppiere.nach.geschlecht %>% 
                  sortiere Alter aufsteigend %>% 
                    nimm die letzten 4 Werte

Die liest sich in etwa so:

  • “Speichere etwas ins Objekt endergebnis, und das geht so…

  • nimm den Datensatz und dann

  • gruppiere die Daten nach geschlecht und dann

  • sortiere nach Alter aufsteigend und dann

  • nimm die letzten 4 Werte. ”

Die Pipe reicht das jeweilige Ergebnis (den Datenstrom) an die nächste Code-Zeile weiter. Erst wenn die letzte Zeile durchgelaufen ist, wird das Resultat in endergebnis gespeichert.

Dies liest sich zu Beginn evtl. etwas ungewohnt, aber Sie können erkennen, dass die Befehle so wesentlich übersichtlicher und die einzelnen Manipulationsschritte nachvollziehbarer geworden sind. Auch kann man sich diese Art der “Grammatik” relativ leicht merken.

Benötigt eine Funktion die Angabe eines Datensets, so kann mit einem Punkt . auf den Pipe-Datenstrom verwiesen werden.

# Der Punkt übergibt den Pipe-Strom an die Funktion sum()
endergebnis <- Datensatz %>%
                    wähle Spalte "Alter" %>%
                        # berechne Summe
                        sum(.)

Die Pipe funktioniert bei jedem R-Objekt, egal in welchem Format (long table vs. wide table, Faktor, Vektor, Matrix, usw.) es vorliegt.

6.3 tibbles

Da dieses Konzept der long table so essenziell ist, wurde im Tidyverse eine eigene Datenklasse eingeführt, die tibble heisst (das kommt daher, dass tidy data immer Tabellen sind, was häufig per tbl abgekürzt wird. Liest man im Englischn tbl laut und schnell, klingt das wie - genau - tibble).

Sie entspricht in etwa dem Datenframe, hat aber intern noch weitere wichtige Änderungen eingebaut.

Tibbles werden so wie Datenframes erzeugt, indem man gleichlange Vektoren übergibt. Der Funktionsname ist tibble().

# aktiviere Tidyverse
library(tidyverse)

# erzeuge ein tibble
tibble(a=c(1,2,3), b=c("a", "b", "c"), c=c(T, F, T))
## # A tibble: 3 x 3
##       a b     c    
##   <dbl> <chr> <lgl>
## 1     1 a     TRUE 
## 2     2 b     FALSE
## 3     3 c     TRUE

Die Schwesterfunktion tribble() (mit r) erlaubt diese Schreibweise

# erzeuge ein tibble mit tRibble
tribble(
  ~Text, ~Zahl, ~Logic,
  "a",     1,     T,
  "b",     2,     F,
  "c",     3,     T
  )
## # A tibble: 3 x 3
##   Text   Zahl Logic
##   <chr> <dbl> <lgl>
## 1 a         1 TRUE 
## 2 b         2 FALSE
## 3 c         3 TRUE

Sind die übergebenen Reihen nicht gleich lang, werden sie als list gespeichert.

# Datenreihen NICHT gleich lang
tribble(
  ~Text, ~Zahl, ~Logic,
  "a",     1:3,     T,
  "b",     4:6,     F,
  "c",     7:9,     T
)
## # A tibble: 3 x 3
##   Text  Zahl      Logic
##   <chr> <list>    <lgl>
## 1 a     <int [3]> TRUE 
## 2 b     <int [3]> FALSE
## 3 c     <int [3]> TRUE

Die meisten Funktionen des Tiddyverse funktioneren auch mit Datenframes, eben weil sie sich so ähnlich sind. Dennoch ergibt es (schon ideologisch) Sinn, die Datenframes in tibbles umzuwandeln.

Schauen wir uns hierfür die Daten der Pflegeberufe als long table an:

# Pflegeframe
head(Pflegeframe)
##   Jahr           Berufsgruppe Anzahl
## 1 1999 Krankenpflegeassistenz  16624
## 2 2001 Krankenpflegeassistenz  19061
## 3 2003 Krankenpflegeassistenz  19478
## 4 2005 Krankenpflegeassistenz  21537
## 5 2007 Krankenpflegeassistenz  27731
## 6 2009 Krankenpflegeassistenz  36481
# Übersicht von "Pflegeframe"
str(Pflegeframe)
## 'data.frame':    45 obs. of  3 variables:
##  $ Jahr        : Factor w/ 9 levels "1999","2001",..: 1 2 3 4 5 6 7 8 9 1 ...
##  $ Berufsgruppe: Factor w/ 5 levels "Krankenpflegeassistenz",..: 1 1 1 1 1 1 1 1 1 2 ...
##  $ Anzahl      : num  16624 19061 19478 21537 27731 ...

Wir erhalten eine Zusammenstellung von wichtigen Informationen. Unser Pflegetibble hat 45 Beobachtungen (Reihen) von 3 Variablen (Spalten). Die Variablen Jahr und Berufsgruppe liegen als Faktoren vor, Anzahl ist numerisch.

# Datenklasse von "Pflegeframe"
class(Pflegeframe)
## [1] "data.frame"

Jetzt wandeln wir das Pflegeframe in ein Pflegetibble um.

# erzeuge Pflegetibble aus Pflegeframe
Pflegetibble <- tibble(Pflegeframe)

# Datenklasse von "Pflegeframe"
class(Pflegetibble)
## [1] "tbl_df"     "tbl"        "data.frame"

Wie Sie sehen, ist unser Tibble immernoch ein Datenframe. Es ist aber auch ein “Tibble Datenframe” (tbl_df) und einfach ein Tibble (tbl).

Die Funktion zum Einsehen von Tibbles heisst glimpse() (englisch für Blick).

# werfe einen Blick auf "Pflegetibble"
glimpse(Pflegetibble)
## Rows: 45
## Columns: 3
## $ Jahr         <fct> 1999, 2001, 2003, 2005, 2007, 2009, 2011, 2013, 2015, 199…
## $ Berufsgruppe <fct> Krankenpflegeassistenz, Krankenpflegeassistenz, Krankenpf…
## $ Anzahl       <dbl> 16624, 19061, 19478, 21537, 27731, 36481, 46517, 54371, 6…

Die Ausgabe sieht fast genau so aus wie der str()-Aufruf. Neben den Variablennamen steht der Datentyp, wobei <fct> für Faktor, <dbl> für Dezimalzahlen und <lgl> für logical steht.

Im klassischen R hat man ein data.frame mit str() angeschaut, im Tidyverse schaut man mit glimpse() auf ein tibble.

6.4 Funktionsaufrufe

In R gibt es jede Menge Zusatzpakete, und obschon die Programmierer sich Mühe geben, einen Funktionsnamen nicht doppelt zu vergeben (vielleicht ist Ihnen schon aufgefallen, dass im Tidyverse viele Funktionen mit einem Unterstrich _ geschrieben werden, z.B. read_sav() oder as_factor()), kann dies durchaus vorkommen.

Wenn wir das Tidyverse per library() aktivieren, erhalten wir folgende Informationen:

library(tidyverse)
── Attaching packages ─────────────────── tidyverse 1.3.0 ──
✓ ggplot2 3.3.3     ✓ purrr   0.3.4
✓ tibble  3.1.0     ✓ dplyr   1.0.5
✓ tidyr   1.1.3     ✓ stringr 1.4.0
✓ readr   1.4.0     ✓ forcats 0.5.1
── Conflicts ──────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()

Wie Sie sehen, gibt es nun Konflikte, da die Funktionen filter() und lag() jeweils in den Paketen tidyverse und stats (R-Basispaket) existieren. Das heisst, möchte man die Funktion filter() verwenden, muss man R mitteilen, aus welchem Paket sie stammt. Dies erfolgt in R indem man den Paketnamen getrenn durch zwei Doppelpunkte vor die Funktion schreibt.

# nutze Funktion filter() aus dem Paket "dplyr"
dplyr::filter()

# nutze Funktion filter() aus dem "stats" Paket
stats::filter()

Im Tidyverse ist es daher durchaus üblich, den Paketnamen mit zwei Doppelpunkten getrennt vor den Funktionsnamen zu setzen. So ist immer klar, welche Funktion aus welchem Paket denn nun aufgerufen werden soll.

# Paketname::Funktionsname
haven::read_sav("spss.sav")

Durch die Refernzierung des Paketnamens sparen Sie sich das Einbinden des gesamten Paketes per library().

Dies funktioniert auch bei den zahlreichen Datensätzen, die R mitliefert. Möchten Sie den Datensatz flights aus dem Paket nycflights13 nutzen, können Sie (nachdem das Paket nycflights13 installiert wurde) wie folgt referenzieren:

# Installiere Paket "nycflights13"
install.packages("nycflights13")

# Paketname::Datensatz
head(nycflights13::flights)

6.5 Schritt 1: Daten importieren

Das Importieren von Daten unterscheidet sich nicht von den Methoden aus Abschnitt 4.10. Tidyverse bringt mit readr() ein eigenes Paket zum Importieren mit, dies ist aber nur für Textdateien wirklich geeignet. Mit den Zusatzpaketen haven und readxl können Sie wie in 4.10 beschrieben über die Funktionen read_sav(), read_xlsx() und read_csv() Ihre Daten einlesen.

In RStudio können Sie einfach im Datenfenster auf Import Dataset klicken, siehe Seite .

Hier sei noch einmal erwähnt, dass in SPSS kategoriale Daten häufig mit Labels versehen werden.

# Lade Test-SPSS-Datei mit Labels 
spss <- haven::read_sav(url("https://www.produnis.de/R/alteDaten-lang.sav"))
head(spss)
## # A tibble: 6 x 6
##             v1           v2           v3            v4           v5     thetruth
##      <dbl+lbl>    <dbl+lbl>    <dbl+lbl>     <dbl+lbl>    <dbl+lbl>    <dbl+lbl>
## 1 4 [strongly… 4 [strongly… 4 [strongly… NA            NA           4 [strongly…
## 2 4 [strongly… 4 [strongly… 4 [strongly… NA            NA           4 [strongly…
## 3 4 [strongly… 4 [strongly… 4 [strongly… NA            NA           4 [strongly…
## 4 4 [strongly… 3 [agree]    3 [agree]     4 [strongly…  4 [strongl… 4 [strongly…
## 5 3 [agree]    3 [agree]    2 [disagree]  2 [disagree]  4 [strongl… 4 [strongly…
## 6 2 [disagree] 3 [agree]    3 [agree]     2 [disagree]  4 [strongl… 4 [strongly…

Mit head() sehen wir, dass die Werte der Spalten gelabelt sind (4=strongly agree, 3=agree, usw.). Die Labels stehen in eckigen Klammern neben dem eingentlichen Wert der Variable.

Mit glimpse() werden die Labels ignoriert

# glimpse() zeigt KEINE Labels 
glimpse(spss)
## Rows: 45,278
## Columns: 6
## $ v1       <dbl+lbl> 4, 4, 4, 4, 3, 2, 2, 2, 4, 3, 2, 3, 2, 2, 4, 4, 3, 2, 4, …
## $ v2       <dbl+lbl> 4, 4, 4, 3, 3, 3, 1, 3, 4, 3, 2, 2, 2, 2, 4, 3, 1, 2, 4, …
## $ v3       <dbl+lbl> 4, 4, 4, 3, 2, 3, 3, 3, 4, 3, 2, 2, 2, 3, 4, 2, 3, 3, 4, …
## $ v4       <dbl+lbl> NA, NA, NA,  4,  2,  2,  2,  3, NA,  4,  2,  4,  4,  2, N…
## $ v5       <dbl+lbl> NA, NA, NA,  4,  4,  4,  1,  3, NA,  4,  4,  1,  4,  4, N…
## $ thetruth <dbl+lbl>  4,  4,  4,  4,  4,  4,  4,  3,  1,  4,  4,  4,  3,  4, N…

Die enthaltenen Labels kann man sich mit der Funktion attr() anzeigen lassen.

# Namen der Variablen 
attr(spss, "names")
## [1] "v1"       "v2"       "v3"       "v4"       "v5"       "thetruth"

Das Label einer Variable wird angezeigt mit

# Label der Variablen 
attr(spss$v1, "label")
## [1] "Blue Question"

Die Labels innerhalb einer Variable mit

# Label der Variablenwerte für "v1"
attr(spss$v1, "labels")
## strongly disagree          disagree             agree    strongly agree 
##                 1                 2                 3                 4 
##         no answer 
##                 9

In R ist die Verwendung von Wertelabels eher untypisch. Es empfiehlt sich, die Ausprägungsstufen so wie sie sind als Werte einzutragen, also z.B. direkt “männlich” - “weiblich” - “divers” anstatt 0 - 1 - 2 und anschließender Labelung. So werden die Ausprägungen auch auf den Grafiken entsprechend “aussagekräftig” angezeigt.

Wir wandeln die Variablen in Faktoren um, welche die Labels als Levelnamen nutzen (die Funktion mutate() wird später genauer erläutert).

spss %>% 
  mutate(as_factor(.))
## # A tibble: 45,278 x 6
##              v1           v2          v3           v4            v5     thetruth
##       <dbl+lbl>    <dbl+lbl>   <dbl+lbl>    <dbl+lbl>     <dbl+lbl>    <dbl+lbl>
##  1 4 [strongly… 4 [strongly… 4 [strongl… NA           NA            4 [strongly…
##  2 4 [strongly… 4 [strongly… 4 [strongl… NA           NA            4 [strongly…
##  3 4 [strongly… 4 [strongly… 4 [strongl… NA           NA            4 [strongly…
##  4 4 [strongly… 3 [agree]    3 [agree]    4 [strongl…  4 [strongly… 4 [strongly…
##  5 3 [agree]    3 [agree]    2 [disagre…  2 [disagre…  4 [strongly… 4 [strongly…
##  6 2 [disagree] 3 [agree]    3 [agree]    2 [disagre…  4 [strongly… 4 [strongly…
##  7 2 [disagree] 1 [strongly… 3 [agree]    2 [disagre…  1 [strongly… 4 [strongly…
##  8 2 [disagree] 3 [agree]    3 [agree]    3 [agree]    3 [agree]    3 [agree]   
##  9 4 [strongly… 4 [strongly… 4 [strongl… NA           NA            1 [strongly…
## 10 3 [agree]    3 [agree]    3 [agree]    4 [strongl…  4 [strongly… 4 [strongly…
## # … with 45,268 more rows

6.6 Schritt 2: Daten tidy machen

Der zweite Schritt besteht darin, die Daten tidy zu machen, das heisst, sie ins long table Format zu überführen. Schauen wir uns hierfür die Matrix der Pflegeberufe an, die ja im wide Format vorliegt:

Pflegeberufe
##                          1999   2001   2003   2005   2007   2009   2011   2013
## Krankenpflegeassistenz  16624  19061  19478  21537  27731  36481  46517  54371
## Altenpflegehilfe        55770  52710  49727  45776  48326  47903  47978  48363
## Kinderkrankenpflege     47779  48203  48822  48519  49080  49307  48291  48937
## Krankenpflege          430983 436767 444783 449355 457322 465446 468192 472580
## Altenpflege            109161 124879 141965 158817 178902 194195 208304 227154
##                          2015
## Krankenpflegeassistenz  64127
## Altenpflegehilfe        49507
## Kinderkrankenpflege     48913
## Krankenpflege          476416
## Altenpflege            246412

Die Reihennamen repräsentieren Variablen.

Da im Tidyverse fast alles über tibbles bzw. Datenframes abläuft, muss die Matrix zunächst in ein tibble überführt werden. Hierfür verwenden wir die Funktion as_tibble()

tbl <- as_tibble(Pflegeberufe)
head(tbl)
## # A tibble: 5 x 9
##   `1999` `2001` `2003` `2005` `2007` `2009` `2011` `2013` `2015`
##    <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
## 1  16624  19061  19478  21537  27731  36481  46517  54371  64127
## 2  55770  52710  49727  45776  48326  47903  47978  48363  49507
## 3  47779  48203  48822  48519  49080  49307  48291  48937  48913
## 4 430983 436767 444783 449355 457322 465446 468192 472580 476416
## 5 109161 124879 141965 158817 178902 194195 208304 227154 246412

Wie Sie sehen, wurden die Spalten (Jahre) als Variablen übernommen. Die Informationen aus den Zeilen (Berufsgruppe) ist verloren gegangen. Für fügen sie daher per cbind() unserem tibble hinzu.

tbl <- cbind(tbl, Berufsgruppe = rownames(Pflegeberufe))
head(tbl)
##     1999   2001   2003   2005   2007   2009   2011   2013   2015
## 1  16624  19061  19478  21537  27731  36481  46517  54371  64127
## 2  55770  52710  49727  45776  48326  47903  47978  48363  49507
## 3  47779  48203  48822  48519  49080  49307  48291  48937  48913
## 4 430983 436767 444783 449355 457322 465446 468192 472580 476416
## 5 109161 124879 141965 158817 178902 194195 208304 227154 246412
##             Berufsgruppe
## 1 Krankenpflegeassistenz
## 2       Altenpflegehilfe
## 3    Kinderkrankenpflege
## 4          Krankenpflege
## 5            Altenpflege

Zur Überführung in ein korrektes tibble vom Format long table wird die Funktion pivot_longer() aus dem Tidyverse-Paket tidyr verwendet. Die Logik der Funktion besteht darin, die Variable mit den ehemaligen Reihennamen (die per cbind() hinzugefügt wurde), bestehen zu lassen. Aus den übrigen Spalten werden neue Variablen erzeugt, deren Werte passend zu den Reihenwerten (der cbind()-Spalte) eingetragen werden. In unserem Beispiel ist die (neue) Variable Berufsgruppe in Spalte 10. Wir belassen also Spalte 10, und wenden die Funktion auf die Spalten 1-9 an.

Pflegetibble <- pivot_longer(tbl, 
             # wähle die Spalten 1-9 aus
             cols=1:9, 
             # speichere Spaltennamen als Werte in neuer Variable "Jahr"
             names_to="Jahr", 
             # Die derzeitigen Werte werden in der neuen Variable "Anzahl" gespeichert
             values_to = "Anzahl")

head(Pflegetibble)
## # A tibble: 6 x 3
##   Berufsgruppe           Jahr  Anzahl
##   <chr>                  <chr>  <dbl>
## 1 Krankenpflegeassistenz 1999   16624
## 2 Krankenpflegeassistenz 2001   19061
## 3 Krankenpflegeassistenz 2003   19478
## 4 Krankenpflegeassistenz 2005   21537
## 5 Krankenpflegeassistenz 2007   27731
## 6 Krankenpflegeassistenz 2009   36481

Mit der Funktion pivot_wider() kann im Gegenzug eine wide table erstellt werden. Ihr wird übergeben, aus welcher Variable die neuen Spalten gebildet werden sollen, und aus welcher Variable die anzuzeigenden Werte zu nehmen sind. Für unser Pflegetibble lautet der Befehl:

pivot_wider(Pflegetibble, names_from = Jahr, values_from = Anzahl)
## # A tibble: 5 x 10
##   Berufsgruppe    `1999` `2001` `2003` `2005` `2007` `2009` `2011` `2013` `2015`
##   <chr>            <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
## 1 Krankenpflegea…  16624  19061  19478  21537  27731  36481  46517  54371  64127
## 2 Altenpflegehil…  55770  52710  49727  45776  48326  47903  47978  48363  49507
## 3 Kinderkrankenp…  47779  48203  48822  48519  49080  49307  48291  48937  48913
## 4 Krankenpflege   430983 436767 444783 449355 457322 465446 468192 472580 476416
## 5 Altenpflege     109161 124879 141965 158817 178902 194195 208304 227154 246412

6.6.1 verschachtelte wide table

Schauen wir uns folgende Tabelle an:

untidy_df
##   Altersgruppe Maenner_2018 Frauen_2018 Maenner_2019 Frauen_2019 Maenner_2020
## 1         < 18        22000       20000        22000       20000        23000
## 2        18-30        36000       35000        36000       35000        38000
## 3        31-50        50000       40000        50000       40000        52000
## 4        51-60        62000       60000        62000       60000        65000
## 5         > 60        75000       72000        75000       72000        78000
##   Frauen_2020
## 1       21000
## 2       36000
## 3       47000
## 4       62000
## 5       75000

Diese Tabelle ist mehrfach verschachtelt. Zum einen haben wir “bedeutsame Reihennamen” in Form der Altersgruppe. Zum anderen sind auch in den Spaltennamen jeweils 2 Variablen “versteckt,” nämlich das Geschlecht und das Jahr.

Um diese Tabelle tidy zu machen, müssen wir in 2 Schritten vor gehen.

Mit der Funktion pivot_longer bringen wir die Daten in eine erste long table-Version. Für den Datensatz untidy_df belassen wir die Variable Altersgruppe und wenden die Funktion auf die übrigen Spalten an.

untidy_df %>% 
  pivot_longer(cols = Maenner_2018:Frauen_2020, 
               names_to="Geschlecht_Jahr", 
               values_to = "Einkommen") %>% 
  head(10)
## # A tibble: 10 x 3
##    Altersgruppe Geschlecht_Jahr Einkommen
##    <chr>        <chr>               <dbl>
##  1 < 18         Maenner_2018        22000
##  2 < 18         Frauen_2018         20000
##  3 < 18         Maenner_2019        22000
##  4 < 18         Frauen_2019         20000
##  5 < 18         Maenner_2020        23000
##  6 < 18         Frauen_2020         21000
##  7 18-30        Maenner_2018        36000
##  8 18-30        Frauen_2018         35000
##  9 18-30        Maenner_2019        36000
## 10 18-30        Frauen_2019         35000

Wie Sie sehen, hat pivot_longer() die Altersgruppen ebenfalls richtig zugeordnet.

Im zweiten Schritt teilen wir die Variable Geschlecht_Jahr in zwei eigene Variablen Geschlecht und Jahr auf. Hierfür steht die Funktion separate() zur Verfügung.

untidy_df %>% 
  pivot_longer(cols = Maenner_2018:Frauen_2020, 
               names_to="Geschlecht_Jahr", 
               values_to = "Einkommen") %>% 
  separate(Geschlecht_Jahr, 
           into = c("Geschlecht", "Jahr")) %>% 
  head(10)
## # A tibble: 10 x 4
##    Altersgruppe Geschlecht Jahr  Einkommen
##    <chr>        <chr>      <chr>     <dbl>
##  1 < 18         Maenner    2018      22000
##  2 < 18         Frauen     2018      20000
##  3 < 18         Maenner    2019      22000
##  4 < 18         Frauen     2019      20000
##  5 < 18         Maenner    2020      23000
##  6 < 18         Frauen     2020      21000
##  7 18-30        Maenner    2018      36000
##  8 18-30        Frauen     2018      35000
##  9 18-30        Maenner    2019      36000
## 10 18-30        Frauen     2019      35000

Die Daten liegen nun vollständig als tidy data vor.

6.6.2 Datentypen korrigieren

Gerade bei importierten Daten sollte überprüft werden, ob den Variablen der korrekte Datentyp (numerisch, faktorial, logisch) zugewiesen ist. Dies ist wichtig, wenn wir mit ihnen später die Statistikfunktionen aufrufen.

Schauen wir unser Pflegetibble an

glimpse(Pflegetibble)
## Rows: 45
## Columns: 3
## $ Berufsgruppe <chr> "Krankenpflegeassistenz", "Krankenpflegeassistenz", "Kran…
## $ Jahr         <chr> "1999", "2001", "2003", "2005", "2007", "2009", "2011", "…
## $ Anzahl       <dbl> 16624, 19061, 19478, 21537, 27731, 36481, 46517, 54371, 6…

Die Variablen Berufsgruppe und Jahr sind beide vom Typ chr, was falsch ist. Überführen wir die Berufsgruppen in einen Faktor, und die Jahre in numerische Werte

Pflegetibble$Berufsgruppe <- as.factor(Pflegetibble$Berufsgruppe)
Pflegetibble$Jahr <- as.numeric(Pflegetibble$Jahr)
glimpse(Pflegetibble)
## Rows: 45
## Columns: 3
## $ Berufsgruppe <fct> Krankenpflegeassistenz, Krankenpflegeassistenz, Krankenpf…
## $ Jahr         <dbl> 1999, 2001, 2003, 2005, 2007, 2009, 2011, 2013, 2015, 199…
## $ Anzahl       <dbl> 16624, 19061, 19478, 21537, 27731, 36481, 46517, 54371, 6…

6.6.3 fehlende Werte

Fehlende Werte (NA) können mit der Funktion drop_na() entfernt werden. Die Funktion “dropt” dabei die komplette Datenreihe, wenn ein NA in einer angegebenen Spalte enthalten ist.

# lade Beispieldatensatz
load(url("https://www.produnis.de/R/pf8.RData" ))

# Schaue Variable "Gewicht" an
glimpse(pf8$Gewicht)
##  num [1:731] 69 67 NA 90 68 60 80 60 NA 60 ...

Variable Gewicht enthält 731 Werte, und wir sehen, dass auch NA enthalten sind.

Jetzt “droppen” wir alle Reihen, in denen bei der Variable Gewicht ein NA steht

pf8 %>% 
  drop_na(Gewicht) %>% 
      glimpse(.)
## Rows: 720
## Columns: 16
## $ Standort       <fct> Münster, Münster, Münster, Münster, Münster, Münster, M…
## $ Alter          <int> 18, 67, 61, 24, 21, 59, 56, 52, 79, 22, 19, 18, 17, 21,…
## $ Geschlecht     <fct> weiblich, weiblich, männlich, männlich, weiblich, weibl…
## $ Größe          <int> 172, 165, 182, 173, 177, 168, 156, 166, 161, 206, 163, …
## $ Gewicht        <dbl> 69, 67, 90, 68, 60, 80, 60, 60, 66, 130, 52, 68, 48, 54…
## $ Bildung        <fct> Abitur, mittlere Reife, mittlere Reife, Abitur, Abitur,…
## $ Beruf          <fct> Inspektor*in, Rentner*in, Beamter*in, Student*in, Stude…
## $ Familienstand  <fct> Partnerschaft, geschieden, ledig, ledig, Partnerschaft,…
## $ Kinder         <int> 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ Wohnort        <fct> ländlich, ländlich, ländlich, städtisch, städtisch, län…
## $ Rauchen        <fct> nein, nein, nein, nein, ja, nein, ja, nein, nein, nein,…
## $ SportHäufig    <dbl> NA, 2.0, 4.0, 4.0, 1.0, 2.0, 1.0, 2.0, NA, 4.0, 5.0, 2.…
## $ SportMinuten   <dbl> NA, 60, 120, 60, 60, 45, 90, 45, NA, 90, 20, 120, 120, …
## $ SportWie       <fct> Allein, Gruppe, Allein, Allein, Gruppe, Gruppe, beides,…
## $ SportWarum     <fct> Arbeitsweg, Vorbeugung, Fitness, Gewichtsreduktion, Fit…
## $ LebenZufrieden <dbl> 5, 7, 2, 9, 8, 5, 8, 8, 8, 8, 7, 8, 7, 8, 7, 7, 8, 7, 1…

Der Datensatz pf8 wird mittels Pipe weitergeleitet. In der zweiten Zeile droppen wir alle Reihen mit Gewicht NA und geben das Resultat per Pipe weiter.

Mit glimpse() sehen wir das Resultat. Datensatz pf8 hat jetzt nur noch 720 Reihen, und nicht mehr 731.

Sollen alle NAs in allen Spalten entfernt werden, lautet der Befehl

pf8 %>% 
  drop_na(.) %>% 
      glimpse(.)
## Rows: 398
## Columns: 16
## $ Standort       <fct> Münster, Münster, Münster, Münster, Münster, Münster, M…
## $ Alter          <int> 67, 61, 24, 21, 59, 56, 52, 22, 19, 18, 17, 21, 72, 19,…
## $ Geschlecht     <fct> weiblich, männlich, männlich, weiblich, weiblich, weibl…
## $ Größe          <int> 165, 182, 173, 177, 168, 156, 166, 206, 163, 172, 158, …
## $ Gewicht        <dbl> 67, 90, 68, 60, 80, 60, 60, 130, 52, 68, 48, 54, 86, 65…
## $ Bildung        <fct> mittlere Reife, mittlere Reife, Abitur, Abitur, mittler…
## $ Beruf          <fct> Rentner*in, Beamter*in, Student*in, Student*in, arbeitl…
## $ Familienstand  <fct> geschieden, ledig, ledig, Partnerschaft, verheiratet, g…
## $ Kinder         <int> 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ Wohnort        <fct> ländlich, ländlich, städtisch, städtisch, ländlich, stä…
## $ Rauchen        <fct> nein, nein, nein, ja, nein, ja, nein, nein, nein, nein,…
## $ SportHäufig    <dbl> 2.0, 4.0, 4.0, 1.0, 2.0, 1.0, 2.0, 4.0, 5.0, 2.5, 1.0, …
## $ SportMinuten   <dbl> 60, 120, 60, 60, 45, 90, 45, 90, 20, 120, 120, 80, 160,…
## $ SportWie       <fct> Gruppe, Allein, Allein, Gruppe, Gruppe, beides, Allein,…
## $ SportWarum     <fct> Vorbeugung, Fitness, Gewichtsreduktion, Fitness, Vorbeu…
## $ LebenZufrieden <dbl> 7, 2, 9, 8, 5, 8, 8, 8, 7, 8, 7, 8, 7, 8, 10, 8, 7, 9, …

Mit dieser radikalen Methode schrumpft der Datensatz pf8 auf 398 vollständige Datenreihen zusammen.

Sie können mit den Funktionen fill() und replace_na() fehlende Werte auffüllen oder ersetzen.

Hierbei ersetzt replace_na() alle NA durch einen vorgegebenen Wert, und fill() versucht, die NA durch wahrscheinliche Werte zu ersetzen. Dies ist hilfreich, wenn die Daten z.B. nach einem Kriterium sortiert sind.

test <- tibble(Beruf = factor(c("Bäcker", NA, "Bäcker", "Ärztin", NA, "Ärztin")))

# vorher
test
## # A tibble: 6 x 1
##   Beruf 
##   <fct> 
## 1 Bäcker
## 2 <NA>  
## 3 Bäcker
## 4 Ärztin
## 5 <NA>  
## 6 Ärztin
# ersetze NA
test %>% 
  tidyr::fill(Beruf)
## # A tibble: 6 x 1
##   Beruf 
##   <fct> 
## 1 Bäcker
## 2 Bäcker
## 3 Bäcker
## 4 Ärztin
## 5 Ärztin
## 6 Ärztin

Aufsteigende Werte können nicht erzeugt werden.

test <- tibble(Jahr = c(2014, NA, NA, NA, 2018, 2019, NA , NA , 2022))

# vorher
test
## # A tibble: 9 x 1
##    Jahr
##   <dbl>
## 1  2014
## 2    NA
## 3    NA
## 4    NA
## 5  2018
## 6  2019
## 7    NA
## 8    NA
## 9  2022
test %>% 
  tidyr::fill(Jahr)
## # A tibble: 9 x 1
##    Jahr
##   <dbl>
## 1  2014
## 2  2014
## 3  2014
## 4  2014
## 5  2018
## 6  2019
## 7  2019
## 8  2019
## 9  2022

6.6.4 Variablen umbenennen

Mit der Funktion rename() könne Sie die Variablennamen ändern.

Pflegetibble %>% 
  dplyr::rename(Neu=Berufsgruppe) %>% 
  head()
## # A tibble: 6 x 3
##   Neu                     Jahr Anzahl
##   <fct>                  <dbl>  <dbl>
## 1 Krankenpflegeassistenz  1999  16624
## 2 Krankenpflegeassistenz  2001  19061
## 3 Krankenpflegeassistenz  2003  19478
## 4 Krankenpflegeassistenz  2005  21537
## 5 Krankenpflegeassistenz  2007  27731
## 6 Krankenpflegeassistenz  2009  36481
Pflegetibble %>% 
  dplyr::rename(graduate=Berufsgruppe,
         year=Jahr,
         n=Anzahl) %>% 
            head()
## # A tibble: 6 x 3
##   graduate                year     n
##   <fct>                  <dbl> <dbl>
## 1 Krankenpflegeassistenz  1999 16624
## 2 Krankenpflegeassistenz  2001 19061
## 3 Krankenpflegeassistenz  2003 19478
## 4 Krankenpflegeassistenz  2005 21537
## 5 Krankenpflegeassistenz  2007 27731
## 6 Krankenpflegeassistenz  2009 36481

6.7 Schritt 3: Umgang mit Datensätzen

Das Paket dplyr bietet zahlreiche Funktionen, die den Umgang mit Datensätzen erleichtern.

6.7.1 Daten filtern und sortieren

Mit der Funktion filter() kann der Datensatz nach Kriterien gefiltert werden. Beachten Sie, dass die Funktion mit stats::filter() kollidiert. Rufen Sie sie daher sicherheitshalber mit dplyr::filter() auf.

pf8 %>% 
    # Nur Daten von Personen jünger 40
    dplyr::filter(Alter<40) %>% 
      glimpse()
## Rows: 443
## Columns: 16
## $ Standort       <fct> Münster, Münster, Münster, Münster, Münster, Münster, M…
## $ Alter          <int> 18, 24, 21, 22, 19, 18, 17, 21, 28, 19, 21, 28, 26, 21,…
## $ Geschlecht     <fct> weiblich, männlich, weiblich, männlich, weiblich, weibl…
## $ Größe          <int> 172, 173, 177, 206, 163, 172, 158, 163, 181, 175, 186, …
## $ Gewicht        <dbl> 69, 68, 60, 130, 52, 68, 48, 54, 70, 65, 70, 85, 60, 65…
## $ Bildung        <fct> Abitur, Abitur, Abitur, Fachabitur, Abitur, mittlere Re…
## $ Beruf          <fct> Inspektor*in, Student*in, Student*in, Kaufmann/frau, St…
## $ Familienstand  <fct> Partnerschaft, ledig, Partnerschaft, ledig, ledig, ledi…
## $ Kinder         <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ Wohnort        <fct> ländlich, städtisch, städtisch, ländlich, städtisch, st…
## $ Rauchen        <fct> nein, nein, ja, nein, nein, nein, nein, nein, nein, nei…
## $ SportHäufig    <dbl> NA, 4.0, 1.0, 4.0, 5.0, 2.5, 1.0, 4.0, NA, 0.5, 1.0, 5.…
## $ SportMinuten   <dbl> NA, 60, 60, 90, 20, 120, 120, 80, NA, 120, 60, 50, 30, …
## $ SportWie       <fct> Allein, Allein, Gruppe, Gruppe, Allein, Gruppe, Gruppe,…
## $ SportWarum     <fct> Arbeitsweg, Gewichtsreduktion, Fitness, Fitness, Vorbeu…
## $ LebenZufrieden <dbl> 5, 9, 8, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 9, 8, 8, 6, 7, 8…

Die Kriterien können auch kombiniert werden.

pf8 %>% 
  dplyr::filter(Alter>20 , Geschlecht == "weiblich", Bildung=="Abitur") %>% 
      glimpse()
## Rows: 56
## Columns: 16
## $ Standort       <fct> Münster, Münster, Münster, Bahn, Bahn, Rheine, Rheine, …
## $ Alter          <int> 21, 21, 21, 21, 21, 22, 23, 22, 30, 52, 45, 23, 49, 41,…
## $ Geschlecht     <fct> weiblich, weiblich, weiblich, weiblich, weiblich, weibl…
## $ Größe          <int> 177, 163, 175, 170, 170, 170, 168, 163, 173, 174, 168, …
## $ Gewicht        <dbl> 60, 54, 61, 58, 80, 59, 70, 63, 71, 72, 70, 56, 70, 49,…
## $ Bildung        <fct> Abitur, Abitur, Abitur, Abitur, Abitur, Abitur, Abitur,…
## $ Beruf          <fct> Student*in, Student*in, Student*in, Student*in, Student…
## $ Familienstand  <fct> Partnerschaft, Partnerschaft, Partnerschaft, NA, ledig,…
## $ Kinder         <int> 0, 0, 0, NA, 0, 0, 0, 0, 0, 1, 2, 0, 2, 0, 3, 2, 0, 1, …
## $ Wohnort        <fct> städtisch, städtisch, städtisch, ländlich, ländlich, st…
## $ Rauchen        <fct> ja, nein, nein, nein, nein, nein, nein, nein, nein, nei…
## $ SportHäufig    <dbl> 1.0, 4.0, 3.0, 5.0, 1.0, 1.0, 2.0, 4.0, 3.0, 4.0, 1.0, …
## $ SportMinuten   <dbl> 60, 80, 60, 75, 60, 90, 45, 60, 60, 20, 60, 90, 30, 120…
## $ SportWie       <fct> Gruppe, beides, Gruppe, Allein, Allein, Allein, beides,…
## $ SportWarum     <fct> Fitness, Vorbeugung, Fitness, Fitness, Fitness, Gewicht…
## $ LebenZufrieden <dbl> 8, 8, 8, 9, 8, 8, 10, 8, 7, 6, 7, 8, 7, 7, 7, 7, 8, 8, …

Beachten Sie, dass wir doppelte Gleichheitszeichen (==) verwenden müssen, da mit einem Gleichheitszeichen (=) Variablen zugewiesen werden (so wie mit <-).

Möchte man nach mehreren bestimmten Werte filtern, kann der %in% Operator verwendet werden. Hierdurch übergeben Sie einen Vektor an möglichen Ausprägungen. Angenommen, Sie möchten nur solche Fälle auswählen, in denen das Alter 20 oder 25 oder 40 Jahre beträgt, lautet der Aufruf:

# nach mehreren Werten filtern
# Suche Fälle, die 20 oder 25 oder 40 Jahre alt sind
pf8 %>% 
  dplyr::filter(Alter %in% c(20, 25, 40)) %>% 
  head(10)
##    Standort Alter Geschlecht Größe Gewicht     Bildung
## 1   Münster    25   männlich   182    75.0  Ausbildung
## 2      Bahn    25   männlich   180    72.0  Hochschule
## 3    Rheine    25   weiblich   168    75.0  Hochschule
## 4    Rheine    40   weiblich   163    68.0 Hauptschule
## 5    Rheine    20   weiblich   158    70.0 Hauptschule
## 6    Rheine    20   weiblich   170    85.0  Hochschule
## 7    Rheine    20   weiblich   170    65.0      Abitur
## 8    Rheine    20   weiblich   160    48.5      Abitur
## 9    Rheine    25   männlich   186    70.0  Hochschule
## 10     Bahn    40   weiblich   181    64.0  Hochschule
##                           Beruf Familienstand Kinder   Wohnort Rauchen
## 1                    Finanzwirt         ledig      0 städtisch    nein
## 2  Kaufmann/frau + Betriebswirt         ledig      0  ländlich    nein
## 3                    Student*in         ledig      0 städtisch      ja
## 4                 Angestellte*r         ledig      2 städtisch    nein
## 5                    Schüler*in         ledig      0  ländlich    nein
## 6                         Azubi         ledig      3  ländlich    nein
## 7                         Azubi         ledig      0  ländlich    nein
## 8                    Student*in         ledig      0  ländlich    nein
## 9                    Student*in         ledig      0 städtisch    nein
## 10                Angestellte*r   verheiratet      2 städtisch    nein
##    SportHäufig SportMinuten SportWie        SportWarum LebenZufrieden
## 1          2.0           90   Allein           Fitness              8
## 2          4.0           30   Allein           Fitness              9
## 3          2.0           20   Allein           Fitness              9
## 4           NA           NA     <NA>              <NA>              6
## 5          3.0           60   Allein Gewichtsreduktion              7
## 6          2.0          120   Gruppe        Vorbeugung              8
## 7          5.0          120   beides           Fitness              7
## 8          3.0           60   Allein           Fitness              7
## 9          3.0           30   Allein        Vorbeugung              9
## 10         1.5           60   Gruppe        Vorbeugung              7

Über den Operator != können Fälle ausgeschlossen werden. Wir schließen für dieses Beispiel alle Fälle aus, die verheiratet sind:

# schließe alle verheirateten Fälle aus
pf8 %>% 
  dplyr::filter(Familienstand != "verheiratet") %>% 
  head(10)
##    Standort Alter Geschlecht Größe Gewicht        Bildung            Beruf
## 1   Münster    18   weiblich   172      69         Abitur     Inspektor*in
## 2   Münster    67   weiblich   165      67 mittlere Reife       Rentner*in
## 3   Münster    60   weiblich   175      NA     Hochschule Ergotherapeut*in
## 4   Münster    61   männlich   182      90 mittlere Reife       Beamter*in
## 5   Münster    24   männlich   173      68         Abitur       Student*in
## 6   Münster    21   weiblich   177      60         Abitur       Student*in
## 7   Münster    56   weiblich   156      60     Ausbildung  Pflegehelfer*in
## 8   Münster    22   männlich   206     130     Fachabitur    Kaufmann/frau
## 9   Münster    19   weiblich   163      52         Abitur       Student*in
## 10  Münster    18   weiblich   172      68 mittlere Reife       Schüler*in
##    Familienstand Kinder   Wohnort Rauchen SportHäufig SportMinuten SportWie
## 1  Partnerschaft      0  ländlich    nein          NA           NA   Allein
## 2     geschieden      0  ländlich    nein         2.0           60   Gruppe
## 3  Partnerschaft      0 städtisch    nein         2.0           45   beides
## 4          ledig      0  ländlich    nein         4.0          120   Allein
## 5          ledig      0 städtisch    nein         4.0           60   Allein
## 6  Partnerschaft      0 städtisch      ja         1.0           60   Gruppe
## 7     geschieden      2 städtisch      ja         1.0           90   beides
## 8          ledig      0  ländlich    nein         4.0           90   Gruppe
## 9          ledig      0 städtisch    nein         5.0           20   Allein
## 10         ledig      0 städtisch    nein         2.5          120   Gruppe
##           SportWarum LebenZufrieden
## 1         Arbeitsweg              5
## 2         Vorbeugung              7
## 3         Vorbeugung              7
## 4            Fitness              2
## 5  Gewichtsreduktion              9
## 6            Fitness              8
## 7         Vorbeugung              8
## 8            Fitness              8
## 9         Vorbeugung              7
## 10 Gewichtsreduktion              8

Mit der Funktion arrange() können die Daten sortiert werden. Dabei wird standardmäßig aufsteigend sortiert.

# sortiere Datensatz "pf8"
pf8 %>% 
  arrange(Alter, Größe, Gewicht) %>% 
     head(.)
##   Standort Alter Geschlecht Größe Gewicht        Bildung      Beruf
## 1 Internet    15   weiblich   165    51.6           <NA>           
## 2  Münster    17   weiblich   158    48.0 mittlere Reife Schüler*in
## 3 Internet    17   weiblich   160    75.0           <NA>           
## 4 Internet    17   weiblich   163    57.0           <NA>           
## 5 Internet    17   weiblich   168    59.0           <NA>           
## 6 Internet    17   weiblich   175    80.0           <NA>           
##   Familienstand Kinder   Wohnort Rauchen SportHäufig SportMinuten SportWie
## 1 Partnerschaft      5 städtisch    nein           6           60   Allein
## 2         ledig      0 städtisch    nein           1          120   Gruppe
## 3 Partnerschaft      0  ländlich    nein           2           60   Gruppe
## 4 Partnerschaft      0  ländlich    nein           2           70   Allein
## 5         ledig      0 städtisch    nein           3          120   Allein
## 6         ledig      0 städtisch    nein          NA           30   Allein
##   SportWarum LebenZufrieden
## 1       <NA>              7
## 2  Beruflich              7
## 3       <NA>              8
## 4       <NA>              5
## 5       <NA>              7
## 6       <NA>              8

Die Daten werden zunächst aufsteigend nach Alter sortiert. Gibt es Fälle mit dem selben Alter, wird nach dem zweiten Kriterium (in diesem Falle Größe) sortiert. Gibt es Fälle mit der selben Größe und dem selben Alter, wird in- nerhalb dieser Gruppe nach Gewicht sortiert.

Für eine absteigende Sortierung muss die Funktion desc() verwendet werden.

# sortiere Datensatz "pf8"
# diesmal absteigend
pf8 %>% 
  arrange(desc(Alter), desc(Größe), desc(Gewicht)) %>% 
     head(.)
##    Standort Alter Geschlecht Größe Gewicht     Bildung        Beruf
## 1   Münster    86   weiblich   162      70 Hauptschule   Rentner*in
## 2    Rheine    86   weiblich   160      60      Abitur  Postbote*in
## 3    Rheine    84   weiblich   164      70 Hauptschule Verkäufer*in
## 4    Rheine    84   weiblich   160      60 Hauptschule   Rentner*in
## 5 Ladbergen    83   männlich   182      88 Hauptschule  Rentener*in
## 6   Münster    83       <NA>   165     175        <NA>   Rentner*in
##   Familienstand Kinder   Wohnort Rauchen SportHäufig SportMinuten SportWie
## 1     verwitwet      0  ländlich    nein           2           45   Gruppe
## 2     verwitwet      1 städtisch    nein           2           45   Gruppe
## 3     verwitwet      0 städtisch    nein          NA           NA     <NA>
## 4     verwitwet      0 städtisch    nein           2           60   Allein
## 5   verheiratet      0  ländlich      ja           5           60   Gruppe
## 6         ledig      0 städtisch    nein          NA           25   Allein
##   SportWarum LebenZufrieden
## 1    Fitness              7
## 2   Freizeit              8
## 3       <NA>              5
## 4    Fitness              8
## 5 Vorbeugung              5
## 6 Vorbeugung              4

6.7.2 Fälle auswählen

Mit der Funktion slice() können gewünschte Datenreihen (Fälle) ausgegeben werden.

pf8 %>% 
  # zeige Fälle (Reihen) 98 bis 105
  slice(98:105) %>% 
    glimpse()
## Rows: 8
## Columns: 16
## $ Standort       <fct> Rheine, Rheine, Rheine, Rheine, Rheine, Rheine, Rheine,…
## $ Alter          <int> 23, 30, 26, 35, 22, 50, 35, 22
## $ Geschlecht     <fct> männlich, weiblich, männlich, männlich, männlich, männl…
## $ Größe          <int> 194, 173, 189, 184, 181, 204, 172, 175
## $ Gewicht        <dbl> 110, 71, 89, 79, 92, 102, 86, 75
## $ Bildung        <fct> Abitur, Abitur, Hauptschule, mittlere Reife, mittlere R…
## $ Beruf          <fct> Außendienst, Innendienst, Angestellte*r,  Produktionsle…
## $ Familienstand  <fct> Partnerschaft, verheiratet, Partnerschaft, verheiratet,…
## $ Kinder         <int> 0, 0, 0, 3, 0, 1, 2, 0
## $ Wohnort        <fct> ländlich, ländlich, städtisch, ländlich, ländlich, länd…
## $ Rauchen        <fct> ja, nein, ja, ja, nein, nein, ja, nein
## $ SportHäufig    <dbl> 1, 3, 1, 3, 2, 4, 1, 0
## $ SportMinuten   <dbl> 30, 60, 60, 90, 30, 30, 60, 0
## $ SportWie       <fct> Allein, Allein, Gruppe, Gruppe, Gruppe, beides, Gruppe,…
## $ SportWarum     <fct> Fitness, Fitness, Freizeit, Fitness, Fitness, Vorbeugun…
## $ LebenZufrieden <dbl> 9, 7, 6, 6, 7, 8, 7, 7

Mit slice_min() und slice_max() können die kleinsten und größten Werte eingesehen werden.

pf8 %>% 
  # zeige die leichtesten Gewichte
  slice_min(Gewicht)%>% 
      glimpse()
## Rows: 5
## Columns: 16
## $ Standort       <fct> Münster, Münster, Münster, Internet, Internet
## $ Alter          <int> 26, 24, 24, 24, 19
## $ Geschlecht     <fct> männlich, weiblich, weiblich, weiblich, weiblich
## $ Größe          <int> 180, 164, 160, 159, 155
## $ Gewicht        <dbl> 45, 45, 45, 45, 45
## $ Bildung        <fct> Hauptschule, Abitur, Abitur, NA, NA
## $ Beruf          <fct> Kaufmann/frau, Student*in, Student*in, , 
## $ Familienstand  <fct> ledig, Partnerschaft, Partnerschaft, Partnerschaft, led…
## $ Kinder         <int> 0, 0, 0, 0, 0
## $ Wohnort        <fct> ländlich, städtisch, städtisch, ländlich, städtisch
## $ Rauchen        <fct> ja, nein, nein, nein, nein
## $ SportHäufig    <dbl> NA, 2.0, 3.0, 4.0, 2.5
## $ SportMinuten   <dbl> NA, 60, 60, 60, 90
## $ SportWie       <fct> NA, Gruppe, Allein, Allein, Allein
## $ SportWarum     <fct> NA, Vorbeugung, Vorbeugung, NA, NA
## $ LebenZufrieden <dbl> 10, 8, 9, 10, 9

Die Tabelle wird nach Gewicht sortiert ausgegeben. Im Datensatz pf8 haben insgesamt 5 Fälle das kleinste Gewicht.

Der Parameter n gibt an, wieviele “Stufen” gezählt werden sollen, also z.B. der kleinste (n=1) oder auch der zweit-kleinste Wert (n=2) usw..

Intern zählt n allerdings mit, wieviele Fälle (Reihen) bereits ausgegeben wurde. Das ist am Anfang etwas un-intuitiv.

pf8 %>% 
  # zeigen die leichtesten Gewichte
  slice_min(Gewicht, n=3)%>% 
      glimpse()
## Rows: 5
## Columns: 16
## $ Standort       <fct> Münster, Münster, Münster, Internet, Internet
## $ Alter          <int> 26, 24, 24, 24, 19
## $ Geschlecht     <fct> männlich, weiblich, weiblich, weiblich, weiblich
## $ Größe          <int> 180, 164, 160, 159, 155
## $ Gewicht        <dbl> 45, 45, 45, 45, 45
## $ Bildung        <fct> Hauptschule, Abitur, Abitur, NA, NA
## $ Beruf          <fct> Kaufmann/frau, Student*in, Student*in, , 
## $ Familienstand  <fct> ledig, Partnerschaft, Partnerschaft, Partnerschaft, led…
## $ Kinder         <int> 0, 0, 0, 0, 0
## $ Wohnort        <fct> ländlich, städtisch, städtisch, ländlich, städtisch
## $ Rauchen        <fct> ja, nein, nein, nein, nein
## $ SportHäufig    <dbl> NA, 2.0, 3.0, 4.0, 2.5
## $ SportMinuten   <dbl> NA, 60, 60, 60, 90
## $ SportWie       <fct> NA, Gruppe, Allein, Allein, Allein
## $ SportWarum     <fct> NA, Vorbeugung, Vorbeugung, NA, NA
## $ LebenZufrieden <dbl> 10, 8, 9, 10, 9

Das Ergebnis ist evtl. anders, als Sie es erwarten. Es werden weiterhin 5 Fälle angezeigt, obwohl n auf 3 gesetzt wurde. Das liegt daran, dass 5 Fälle das kleinste Gewicht haben, und diese werden vollständig angezeigt. Intern ist n dabei auf 5 angewachsen, weshalb keine zweit-kleinsten Gewichte mehr ausgegeben werden.

Lassen wir uns die Älteste Probanden auswählen.

pf8 %>% 
  # zeige die ältesten 
  slice_max(Alter, n=2) %>% 
      glimpse()
## Rows: 2
## Columns: 16
## $ Standort       <fct> Münster, Rheine
## $ Alter          <int> 86, 86
## $ Geschlecht     <fct> weiblich, weiblich
## $ Größe          <int> 162, 160
## $ Gewicht        <dbl> 70, 60
## $ Bildung        <fct> Hauptschule, Abitur
## $ Beruf          <fct> Rentner*in, Postbote*in
## $ Familienstand  <fct> verwitwet, verwitwet
## $ Kinder         <int> 0, 1
## $ Wohnort        <fct> ländlich, städtisch
## $ Rauchen        <fct> nein, nein
## $ SportHäufig    <dbl> 2, 2
## $ SportMinuten   <dbl> 45, 45
## $ SportWie       <fct> Gruppe, Gruppe
## $ SportWarum     <fct> Fitness, Freizeit
## $ LebenZufrieden <dbl> 7, 8

Die Tabelle besteht zwar aus 2 Fällen, aber beide Fälle haben das selbe Alter. Die zweit-ältesten werden nicht mit angezeigt, da n intern bereits auf 2 angewachsen ist.

Wir eröhen n auf 3:

pf8 %>% 
  # zeige die ältesten 
  slice_max(Alter, n=3)%>% 
      glimpse()
## Rows: 4
## Columns: 16
## $ Standort       <fct> Münster, Rheine, Rheine, Rheine
## $ Alter          <int> 86, 86, 84, 84
## $ Geschlecht     <fct> weiblich, weiblich, weiblich, weiblich
## $ Größe          <int> 162, 160, 160, 164
## $ Gewicht        <dbl> 70, 60, 60, 70
## $ Bildung        <fct> Hauptschule, Abitur, Hauptschule, Hauptschule
## $ Beruf          <fct> Rentner*in, Postbote*in, Rentner*in, Verkäufer*in
## $ Familienstand  <fct> verwitwet, verwitwet, verwitwet, verwitwet
## $ Kinder         <int> 0, 1, 0, 0
## $ Wohnort        <fct> ländlich, städtisch, städtisch, städtisch
## $ Rauchen        <fct> nein, nein, nein, nein
## $ SportHäufig    <dbl> 2, 2, 2, NA
## $ SportMinuten   <dbl> 45, 45, 60, NA
## $ SportWie       <fct> Gruppe, Gruppe, Allein, NA
## $ SportWarum     <fct> Fitness, Freizeit, Fitness, NA
## $ LebenZufrieden <dbl> 7, 8, 8, 5

Jetzt haben wir insgesamt 4 Fälle. Es werden zuerst die ältesten angezeigt. Da es 2 Fälle sind, steigt n intern auf 2 an. Da wir n mit 3 aufgerufen haben, ist noch “Platz” für die zweit-ältesten. Da dies ebenfalls 2 Fälle sind, werden beide ausgegeben. Insgesamt sehen wir also 4 Fälle, obwohl wir n mit 3 aufgerufen haben.

Ähnlich wie head() und tail() zeigen slice_head() und slice_tail() die ersten bzw. letzten Fälle an.

# zeige die ersten 5 Fälle
pf8 %>% slice_head(n=5)
##   Standort Alter Geschlecht Größe Gewicht        Bildung            Beruf
## 1  Münster    18   weiblich   172      69         Abitur     Inspektor*in
## 2  Münster    67   weiblich   165      67 mittlere Reife       Rentner*in
## 3  Münster    60   weiblich   175      NA     Hochschule Ergotherapeut*in
## 4  Münster    61   männlich   182      90 mittlere Reife       Beamter*in
## 5  Münster    24   männlich   173      68         Abitur       Student*in
##   Familienstand Kinder   Wohnort Rauchen SportHäufig SportMinuten SportWie
## 1 Partnerschaft      0  ländlich    nein          NA           NA   Allein
## 2    geschieden      0  ländlich    nein           2           60   Gruppe
## 3 Partnerschaft      0 städtisch    nein           2           45   beides
## 4         ledig      0  ländlich    nein           4          120   Allein
## 5         ledig      0 städtisch    nein           4           60   Allein
##          SportWarum LebenZufrieden
## 1        Arbeitsweg              5
## 2        Vorbeugung              7
## 3        Vorbeugung              7
## 4           Fitness              2
## 5 Gewichtsreduktion              9
# zeige die letzten 2 Fälle
pf8 %>% slice_tail(n=2)
##   Standort Alter Geschlecht Größe Gewicht Bildung Beruf Familienstand Kinder
## 1 Internet    20   weiblich   168      58    <NA>               ledig      0
## 2 Internet    40   männlich   183      78    <NA>         verheiratet      2
##     Wohnort Rauchen SportHäufig SportMinuten SportWie SportWarum LebenZufrieden
## 1 städtisch    nein         1.0           60   Allein       <NA>              8
## 2 städtisch      ja         2.5          120   Gruppe       <NA>             10

Mit slice_sample() können zufällig Fälle aus dem Datensatz gezogen werden.

# ziehe zufällig 7 Fälle
pf8 %>% slice_sample(n=7)
##   Standort Alter Geschlecht Größe Gewicht     Bildung             Beruf
## 1 Internet    23   weiblich   165      50        <NA>                  
## 2 Internet    56   männlich   191      86        <NA>                  
## 3 Internet    60   weiblich   164      73        <NA>                  
## 4  Münster    24   männlich   178      72  Hochschule Sozialarbeiter*in
## 5 Internet    48   weiblich   174      98        <NA>                  
## 6  Münster    86   weiblich   162      70 Hauptschule        Rentner*in
## 7 Internet    27   männlich   185      97        <NA>                  
##   Familienstand Kinder   Wohnort Rauchen SportHäufig SportMinuten SportWie
## 1         ledig      0  ländlich    nein         3.5           NA   Allein
## 2   verheiratet      0 städtisch    nein         5.0          180   Allein
## 3    geschieden      0  ländlich      ja         7.0           45   Allein
## 4         ledig      0 städtisch    nein         4.0           90   beides
## 5   verheiratet      2  ländlich      ja         1.0           30   Allein
## 6     verwitwet      0  ländlich    nein         2.0           45   Gruppe
## 7         ledig      0  ländlich    nein         7.0          120   Allein
##   SportWarum LebenZufrieden
## 1       <NA>              5
## 2       <NA>             10
## 3       <NA>              6
## 4    Fitness             10
## 5       <NA>              6
## 6    Fitness              7
## 7       <NA>              8

Mit der Funktion group_by() können Gruppierungen vorgenommen werden.

In Kombination mit group_by() zeigen die slice()-Funktionen die jeweilige Auswahl an Fällen pro Gruppe.

pf8 %>%
  drop_na() %>% 
  # Gruppiere nach Geschlecht
  group_by(Geschlecht) %>% 
  #  zeige
  slice(1)
## # A tibble: 3 x 16
## # Groups:   Geschlecht [3]
##   Standort Alter Geschlecht Größe Gewicht Bildung   Beruf   Familienstand Kinder
##   <fct>    <int> <fct>      <int>   <dbl> <fct>     <fct>   <fct>          <int>
## 1 Münster     61 männlich     182      90 mittlere… Beamte… ledig              0
## 2 Münster     67 weiblich     165      67 mittlere… Rentne… geschieden         0
## 3 Rheine      32 divers       186      92 Hochschu… Sozial… verheiratet        0
## # … with 7 more variables: Wohnort <fct>, Rauchen <fct>, SportHäufig <dbl>,
## #   SportMinuten <dbl>, SportWie <fct>, SportWarum <fct>, LebenZufrieden <dbl>
pf8 %>%
  drop_na() %>% 
  # Gruppiere nach Geschlecht
  group_by(Geschlecht) %>% 
  # sortiere nach Alter
  arrange(desc(Alter)) %>% 
  #  zeige die ersten 3 Fälle pro Gruppe
  slice(1:3)
## # A tibble: 7 x 16
## # Groups:   Geschlecht [3]
##   Standort  Alter Geschlecht Größe Gewicht Bildung  Beruf   Familienstand Kinder
##   <fct>     <int> <fct>      <int>   <dbl> <fct>    <fct>   <fct>          <int>
## 1 Ladbergen    83 männlich     182    88   Hauptsc… Renten… verheiratet        0
## 2 Münster      78 männlich     178    71.5 Hochsch… Lehrer… verheiratet        0
## 3 Bahn         76 männlich     180    90   Hochsch… Arzt*in verheiratet        0
## 4 Münster      86 weiblich     162    70   Hauptsc… Rentne… verwitwet          0
## 5 Rheine       86 weiblich     160    60   Abitur   Postbo… verwitwet          1
## 6 Rheine       84 weiblich     160    60   Hauptsc… Rentne… verwitwet          0
## 7 Rheine       32 divers       186    92   Hochsch… Sozial… verheiratet        0
## # … with 7 more variables: Wohnort <fct>, Rauchen <fct>, SportHäufig <dbl>,
## #   SportMinuten <dbl>, SportWie <fct>, SportWarum <fct>, LebenZufrieden <dbl>

Innerhalb der Gruppierungen kann auch gefiltert werden.

pf8 %>% 
  # gruppiere nach Standort
  group_by(Geschlecht) %>% 
  # filtere "divers"
  dplyr::filter(Geschlecht != "divers") %>% 
  # filtere "Internet"
  dplyr::filter(Standort != "Internet") %>% 
  # sortiere nach "Gewicht"
  arrange(desc(Gewicht)) %>% 
  #  zeige die ersten 2 Fälle pro Gruppe
  slice(1,2)
## # A tibble: 4 x 16
## # Groups:   Geschlecht [2]
##   Standort Alter Geschlecht Größe Gewicht Bildung   Beruf   Familienstand Kinder
##   <fct>    <int> <fct>      <int>   <dbl> <fct>     <fct>   <fct>          <int>
## 1 Münster     22 männlich     206     130 Fachabit… Kaufma… ledig              0
## 2 Bahn        31 männlich     184     130 Fachabit… Schade… Partnerschaft      0
## 3 Münster     40 weiblich     171     122 Hochschu… Presse… Partnerschaft      0
## 4 Rheine      45 weiblich     168     120 mittlere… kaufma… geschieden         1
## # … with 7 more variables: Wohnort <fct>, Rauchen <fct>, SportHäufig <dbl>,
## #   SportMinuten <dbl>, SportWie <fct>, SportWarum <fct>, LebenZufrieden <dbl>
pf8 %>% 
  group_by(Standort) %>% 
  dplyr::filter(Familienstand == "ledig" & Geschlecht == "männlich") %>% 
  arrange(desc(Alter)) %>% 
  head()
## # A tibble: 6 x 16
## # Groups:   Standort [2]
##   Standort Alter Geschlecht Größe Gewicht Bildung   Beruf   Familienstand Kinder
##   <fct>    <int> <fct>      <int>   <dbl> <fct>     <fct>   <fct>          <int>
## 1 Rheine      81 männlich     179      79 Hauptsch… "Handw… ledig              0
## 2 Rheine      74 männlich     175      84 mittlere… "Koch*… ledig              0
## 3 Münster     72 männlich     175      86 mittlere… "Siche… ledig              0
## 4 Münster     69 männlich     179      89 mittlere… "Rentn… ledig              0
## 5 Münster     61 männlich     182      90 mittlere… "Beamt… ledig              0
## 6 Rheine      59 männlich     175      70 Abitur    ""      ledig              1
## # … with 7 more variables: Wohnort <fct>, Rauchen <fct>, SportHäufig <dbl>,
## #   SportMinuten <dbl>, SportWie <fct>, SportWarum <fct>, LebenZufrieden <dbl>

6.7.3 Variablen hinzufügen

Variablen können mit der Funktion bind_cols() hinzugefügt werden. Dabei muss die Länge der enthaltenen Werte mit der Länge des tibble übereinstimmen, ansonsten wiederholt R die Wertereihe so lange, bis sie mit der Länge des tibble übereinstimmt.

pf8 %>% 
  # Fügt eine Variable "test" hinzu, in der alle Werte TRUE sind.
  bind_cols(test = TRUE) %>% 
    glimpse()
## Rows: 731
## Columns: 17
## $ Standort       <fct> Münster, Münster, Münster, Münster, Münster, Münster, M…
## $ Alter          <int> 18, 67, 60, 61, 24, 21, 59, 56, 82, 52, 79, 22, 19, 18,…
## $ Geschlecht     <fct> weiblich, weiblich, weiblich, männlich, männlich, weibl…
## $ Größe          <int> 172, 165, 175, 182, 173, 177, 168, 156, 184, 166, 161, …
## $ Gewicht        <dbl> 69, 67, NA, 90, 68, 60, 80, 60, NA, 60, 66, 130, 52, 68…
## $ Bildung        <fct> Abitur, mittlere Reife, Hochschule, mittlere Reife, Abi…
## $ Beruf          <fct> Inspektor*in, Rentner*in, Ergotherapeut*in, Beamter*in,…
## $ Familienstand  <fct> Partnerschaft, geschieden, Partnerschaft, ledig, ledig,…
## $ Kinder         <int> 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ Wohnort        <fct> ländlich, ländlich, städtisch, ländlich, städtisch, stä…
## $ Rauchen        <fct> nein, nein, nein, nein, nein, ja, nein, ja, nein, nein,…
## $ SportHäufig    <dbl> NA, 2.0, 2.0, 4.0, 4.0, 1.0, 2.0, 1.0, 1.0, 2.0, NA, 4.…
## $ SportMinuten   <dbl> NA, 60, 45, 120, 60, 60, 45, 90, NA, 45, NA, 90, 20, 12…
## $ SportWie       <fct> Allein, Gruppe, beides, Allein, Allein, Gruppe, Gruppe,…
## $ SportWarum     <fct> Arbeitsweg, Vorbeugung, Vorbeugung, Fitness, Gewichtsre…
## $ LebenZufrieden <dbl> 5, 7, 7, 2, 9, 8, 5, 8, 10, 8, 8, 8, 7, 8, 7, 8, 7, 7, …
## $ test           <lgl> TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, T…

Unsere neue Variable test sehen wir ganz unten. Alle Werte stehen auf TRUE.

6.7.4 Fälle hinzufügen

Neue Fälle können mit der Funktion bind_rows() hinzugefügt werden. Dies klappt nur, wenn die neuen Fälle als tibble vorliegen, das über die selben Variablen verfügt wie der Originaldatensatz. Die Reihenfolge der Spalten ist egal, da über die Spaltennamen gematcht wird.

Wichtig ist jedoch, dass innerhalb der Variablen auch der selbe Datentyp (numerisch, faktor, logisch) vorliegt, da ansonten die Datentypen auf den kleinsten gemeinsamen Nenner (character) zurückfallen. Wir machen es hier einmal falsch:

# erzeuge neuen Fall
# ohne Angabe des Datentyps
neu <- tibble("Internet", 44, "weiblich", 166, 70, NA, "Pilot", "verheiratet", 0, "ländlich","ja")
# kopiere die Spaltennamen
colnames(neu) <- colnames(pf8)

# füge zum Datensazu hinzu
# Achtung, zerschießt die Datentypen des tibble!
pf8 %>% 
   bind_rows( neu ) %>% 
    tail()
##     Standort Alter Geschlecht Größe Gewicht Bildung Beruf Familienstand Kinder
## 727 Internet    19   weiblich   158      58    <NA>               ledig      0
## 728 Internet    37   weiblich   160      59    <NA>         verheiratet      1
## 729 Internet    56   männlich   185      79    <NA>       Partnerschaft      0
## 730 Internet    20   weiblich   168      58    <NA>               ledig      0
## 731 Internet    40   männlich   183      78    <NA>         verheiratet      2
## 732 Internet    44   weiblich   166      70    <NA> Pilot   verheiratet      0
##       Wohnort Rauchen SportHäufig SportMinuten SportWie SportWarum
## 727 städtisch    nein         7.0           10   Allein       <NA>
## 728  ländlich    nein         3.0           60   Allein       <NA>
## 729  ländlich    nein         2.0           90   Gruppe       <NA>
## 730 städtisch    nein         1.0           60   Allein       <NA>
## 731 städtisch      ja         2.5          120   Gruppe       <NA>
## 732  ländlich      ja          NA           NA     <NA>       <NA>
##     LebenZufrieden
## 727              7
## 728              9
## 729              9
## 730              8
## 731             10
## 732             NA

Unsere Zeile ist ganz unten zu sehen. Die fehlenden Werte wurden mit NA aufgefüllt. Alles scheint gut gelaufen zu sein. Wie ein Blick mit glimpse() jedoch zeigt, haben wir die Datentypen unseres tibbles zerschossen, da unsere hinzugefügte Zeile nicht die korrekten Datentypen beinhaltete.

pf8 %>% 
   bind_rows( neu ) %>% 
    glimpse()
## Rows: 732
## Columns: 16
## $ Standort       <chr> "Münster", "Münster", "Münster", "Münster", "Münster", …
## $ Alter          <dbl> 18, 67, 60, 61, 24, 21, 59, 56, 82, 52, 79, 22, 19, 18,…
## $ Geschlecht     <chr> "weiblich", "weiblich", "weiblich", "männlich", "männli…
## $ Größe          <dbl> 172, 165, 175, 182, 173, 177, 168, 156, 184, 166, 161, …
## $ Gewicht        <dbl> 69, 67, NA, 90, 68, 60, 80, 60, NA, 60, 66, 130, 52, 68…
## $ Bildung        <fct> Abitur, mittlere Reife, Hochschule, mittlere Reife, Abi…
## $ Beruf          <chr> "Inspektor*in", "Rentner*in", "Ergotherapeut*in", "Beam…
## $ Familienstand  <chr> "Partnerschaft", "geschieden", "Partnerschaft", "ledig"…
## $ Kinder         <dbl> 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ Wohnort        <chr> "ländlich", "ländlich", "städtisch", "ländlich", "städt…
## $ Rauchen        <chr> "nein", "nein", "nein", "nein", "nein", "ja", "nein", "…
## $ SportHäufig    <dbl> NA, 2.0, 2.0, 4.0, 4.0, 1.0, 2.0, 1.0, 1.0, 2.0, NA, 4.…
## $ SportMinuten   <dbl> NA, 60, 45, 120, 60, 60, 45, 90, NA, 45, NA, 90, 20, 12…
## $ SportWie       <fct> Allein, Gruppe, beides, Allein, Allein, Gruppe, Gruppe,…
## $ SportWarum     <fct> Arbeitsweg, Vorbeugung, Vorbeugung, Fitness, Gewichtsre…
## $ LebenZufrieden <dbl> 5, 7, 7, 2, 9, 8, 5, 8, 10, 8, 8, 8, 7, 8, 7, 8, 7, 7, …

Wie Sie sehen, sind unsere ehemaligen Faktoren Standort und Geschlecht auf <chr> zurückgefallen.

Ein falscher bind_rows()-Befehl kann Ihnen also das gesamte tibble “zerschießen!”

Fügen wir nun eine korrekte neue Zeile hinzu

# erzeuge korrekte neue Zeile
neu <- tibble(factor("Internet"), 44, factor("weiblich"), 166, 70, NA, factor("Pilot"), factor("verheiratet"), 0, factor("ländlich"), factor("ja"))
# Spaltennamen übernehmen
colnames(neu) <- colnames(pf8)

pf8 %>% 
   bind_rows( neu ) %>% 
    glimpse()
## Rows: 732
## Columns: 16
## $ Standort       <fct> Münster, Münster, Münster, Münster, Münster, Münster, M…
## $ Alter          <dbl> 18, 67, 60, 61, 24, 21, 59, 56, 82, 52, 79, 22, 19, 18,…
## $ Geschlecht     <fct> weiblich, weiblich, weiblich, männlich, männlich, weibl…
## $ Größe          <dbl> 172, 165, 175, 182, 173, 177, 168, 156, 184, 166, 161, …
## $ Gewicht        <dbl> 69, 67, NA, 90, 68, 60, 80, 60, NA, 60, 66, 130, 52, 68…
## $ Bildung        <fct> Abitur, mittlere Reife, Hochschule, mittlere Reife, Abi…
## $ Beruf          <fct> Inspektor*in, Rentner*in, Ergotherapeut*in, Beamter*in,…
## $ Familienstand  <fct> Partnerschaft, geschieden, Partnerschaft, ledig, ledig,…
## $ Kinder         <dbl> 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0…
## $ Wohnort        <fct> ländlich, ländlich, städtisch, ländlich, städtisch, stä…
## $ Rauchen        <fct> nein, nein, nein, nein, nein, ja, nein, ja, nein, nein,…
## $ SportHäufig    <dbl> NA, 2.0, 2.0, 4.0, 4.0, 1.0, 2.0, 1.0, 1.0, 2.0, NA, 4.…
## $ SportMinuten   <dbl> NA, 60, 45, 120, 60, 60, 45, 90, NA, 45, NA, 90, 20, 12…
## $ SportWie       <fct> Allein, Gruppe, beides, Allein, Allein, Gruppe, Gruppe,…
## $ SportWarum     <fct> Arbeitsweg, Vorbeugung, Vorbeugung, Fitness, Gewichtsre…
## $ LebenZufrieden <dbl> 5, 7, 7, 2, 9, 8, 5, 8, 10, 8, 8, 8, 7, 8, 7, 8, 7, 7, …

Die Datentypen sind erhalten geblieben.

6.7.5 Variablen auswählen

Mit der Funktion select() können Variablen (Spalten) des tibble ausgewählt werden.

# wähle Variablen "Alter", "Größe" und "Gewicht"
# aus Datensatz pf8
 pf8 %>% 
   select(Alter,Größe,Gewicht) %>% 
   head(.)
##    Alter Größe Gewicht
## 11    18   172      69
## 12    67   165      67
## 13    60   175      NA
## 14    61   182      90
## 15    24   173      68
## 16    21   177      60

In Kombination mit der Funktion everything() kann die Reihenfolge der Variablen im Datensatz geändert werden. Die Funktion everything() hängt alle weiteren Variablen an unsere Auswahl an.

Angenommen, wir möchten Größe und Gewicht “als erstes” sehen, und alle anderen Variablen danach, so lautet der Befehl:

# zeige erst "Größe" und "Gewicht"
# und danach alles andere.
pf8 %>% 
  select(Größe, Gewicht, everything()) %>% 
  as_tibble()
## # A tibble: 731 x 16
##    Größe Gewicht Standort Alter Geschlecht Bildung   Beruf  Familienstand Kinder
##    <int>   <dbl> <fct>    <int> <fct>      <fct>     <fct>  <fct>          <int>
##  1   172      69 Münster     18 weiblich   Abitur    Inspe… Partnerschaft      0
##  2   165      67 Münster     67 weiblich   mittlere… Rentn… geschieden         0
##  3   175      NA Münster     60 weiblich   Hochschu… Ergot… Partnerschaft      0
##  4   182      90 Münster     61 männlich   mittlere… Beamt… ledig              0
##  5   173      68 Münster     24 männlich   Abitur    Stude… ledig              0
##  6   177      60 Münster     21 weiblich   Abitur    Stude… Partnerschaft      0
##  7   168      80 Münster     59 weiblich   mittlere… arbei… verheiratet        0
##  8   156      60 Münster     56 weiblich   Ausbildu… Pfleg… geschieden         2
##  9   184      NA Münster     82 männlich   mittlere… Kaufm… verheiratet        0
## 10   166      60 Münster     52 weiblich   Fachabit… Kaufm… verheiratet        1
## # … with 721 more rows, and 7 more variables: Wohnort <fct>, Rauchen <fct>,
## #   SportHäufig <dbl>, SportMinuten <dbl>, SportWie <fct>, SportWarum <fct>,
## #   LebenZufrieden <dbl>

Mit der Funktion pull() werden die Spaltenwerte als Vektor wiedergegeben

# gib Werte von "Alter" als Vektor
pf8 %>% 
  pull(Alter) %>% 
   head(10)
##  [1] 18 67 60 61 24 21 59 56 82 52

6.7.6 Variablen erzeugen

Die Funktion mutate() erlaubt es, neue Variablen (Spalten) zu erzeugen, die durch Interaktion mit den anderen Variablen enstanden sind. So können wir im Datensatz pf8 aus den Variablen Größe und Gewicht den Body-Maß-Index errechnen, und diese Werte als neue Variable (Spalte) speichern.

# erzeuge BMI
pf8 %>% 
  mutate(BMI = Gewicht/Größe*100) %>% 
    head(.)
##    Standort Alter Geschlecht Größe Gewicht        Bildung            Beruf
## 11  Münster    18   weiblich   172      69         Abitur     Inspektor*in
## 12  Münster    67   weiblich   165      67 mittlere Reife       Rentner*in
## 13  Münster    60   weiblich   175      NA     Hochschule Ergotherapeut*in
## 14  Münster    61   männlich   182      90 mittlere Reife       Beamter*in
## 15  Münster    24   männlich   173      68         Abitur       Student*in
## 16  Münster    21   weiblich   177      60         Abitur       Student*in
##    Familienstand Kinder   Wohnort Rauchen SportHäufig SportMinuten SportWie
## 11 Partnerschaft      0  ländlich    nein          NA           NA   Allein
## 12    geschieden      0  ländlich    nein           2           60   Gruppe
## 13 Partnerschaft      0 städtisch    nein           2           45   beides
## 14         ledig      0  ländlich    nein           4          120   Allein
## 15         ledig      0 städtisch    nein           4           60   Allein
## 16 Partnerschaft      0 städtisch      ja           1           60   Gruppe
##           SportWarum LebenZufrieden      BMI
## 11        Arbeitsweg              5 40.11628
## 12        Vorbeugung              7 40.60606
## 13        Vorbeugung              7       NA
## 14           Fitness              2 49.45055
## 15 Gewichtsreduktion              9 39.30636
## 16           Fitness              8 33.89831

Mit der Schwesterfunktion transmute() wird nur die neue Variable in einem eigenen tibble zurückgegeben

# erzeuge BMI und gib nur BMI zurück
pf8 %>% 
  transmute(BMI = Gewicht/Größe*100) %>% 
    head(.)
##         BMI
## 11 40.11628
## 12 40.60606
## 13       NA
## 14 49.45055
## 15 39.30636
## 16 33.89831

6.7.7 statistische Berechnungen

Mit der Funktion summarise() können “zusammenfassenden Statistiken” berechnet werden. Sie fungiert als eine Art “Vermittlungsfunktion,” um Statistikfunktionen (siehe Kapitel 8 in den Tidyverse-Workflow zu integrieren.

Klassische zusammenfassende Kennzahlen sind Mittelwert (über Funktion mean()), Median (über Funktion median()) und Standardabweichung (über Funktion sd()). Es funktioniert aber auch mit allen anderen Statistikfunktionen. Wir beschränken uns im Weiteren auf diese drei, alle anderen werden in Kapitel 8 vorgestellt.

Berechnen wir mit mean() den Mittelwert für Alter.

# Mittelwert von "Alter"
pf8 %>% 
  summarise(Mittelwert = mean(Alter))
##   Mittelwert
## 1         NA

Wir erhalten ein NA zurück, weil in der Variable Alter fehlende Werte enthalten sind. Fast alle statistischen Funktionen erwarten von uns, dass NAs weggefilter wurden. Nutzen wir die Macht der Pipe und ändern den Befehl in

# Mittelwert von "Alter"
pf8 %>% 
  drop_na() %>% 
    summarise(Mittelwert = mean(Alter))
##   Mittelwert
## 1   38.25126

Mit der Funktion group_by() können Gruppierungen vorgenommen werden.

# Gruppiere nach Geschlecht
pf8 %>% 
  dplyr::group_by(Geschlecht) %>% 
    drop_na() %>% 
      summarise(Mittelwert = mean(Alter))
### A tibble: 3 x 2
##  Geschlecht Mittelwert
##   <fct>           <dbl>
## 1 männlich         37.3
## 2 weiblich         39.1
## 3 divers           32 

Die Liste der “zusammenfassenden Statistiken” lässt sich beliebig erweitern.

pf8 %>% 
  group_by(Geschlecht) %>% 
     drop_na() %>% 
       summarise(Mittelwert = mean(Alter),
                 Median = median(Alter),
                 Stdabw = sd(Alter))
### A tibble: 3 x 4
##  Geschlecht Mittelwert Median Stdabw
##   <fct>           <dbl>  <dbl>  <dbl>
## 1 männlich         37.3     29   17.5
## 2 weiblich         39.1     33   18.9
## 3 divers           32       32   NA  

Auch, indem Gruppierungen komplexer definiert werden.

# mit mehr Gruppierungen
pf8 %>% 
  group_by(Geschlecht, Standort) %>% 
     drop_na() %>% 
        summarise(Mittelwert = mean(Alter),
                  Median = median(Alter),
                  Stdabw = sd(Alter))
### A tibble: 9 x 5
### Groups:   Geschlecht [3]
##  Geschlecht Standort  Mittelwert Median Stdabw
##   <fct>      <fct>          <dbl>  <dbl>  <dbl>
## 1 männlich   Rheine          34.3   26     15.4
## 2 männlich   Münster         37.9   28     18.5
## 3 männlich   Bahn            39.9   36     19.8
## 4 männlich   Ladbergen       41.4   40     17.6
## 5 weiblich   Rheine          37.6   33     17.8
## 6 weiblich   Münster         38.8   27     20.0
## 7 weiblich   Bahn            41.3   37.5   19.4
## 8 weiblich   Ladbergen       43     40.5   18.5
## 9 divers     Rheine          32     32     NA   


Die Funktion count() zählt die Häufigkeit der Variablenwerte.

Dies ist nicht nur bei Faktoren hilfreich.

pf8 %>% 
  dplyr::count(Geschlecht)
##   Geschlecht   n
## 1   männlich 287
## 2   weiblich 437
## 3     divers   1
## 4       <NA>   6

In Kombination mit group_by() lassen sich Ausgaben ähnlich der Kreuztabelle erstellen.

pf8 %>% 
  drop_na() %>% 
  group_by(Familienstand, Geschlecht) %>% 
  count() %>% 
  slice_head()
##   Standort Alter Geschlecht Größe Gewicht        Bildung      Beruf
## 1  Münster    67   weiblich   165      67 mittlere Reife Rentner*in
##   Familienstand Kinder  Wohnort Rauchen SportHäufig SportMinuten SportWie
## 1    geschieden      0 ländlich    nein           2           60   Gruppe
##   SportWarum LebenZufrieden freq
## 1 Vorbeugung              7    1

Mit der Funktion add_acount() werden die Häufigkeitswerte als eigene Variable im Datensatz gespeichert.

pf8 %>% 
  # Speichere die Levelhäufigkeit als eigene Variable
  add_count(Geschlecht, name = "AnzahlGeschlecht") %>% 
  # Zeige diese Variablen als erstes, dann den Rest
  select(Geschlecht, AnzahlGeschlecht, everything()) %>% 
  # Ausgabe als tibble ist "schöner"
  as_tibble()
## # A tibble: 731 x 17
##    Geschlecht AnzahlGeschlecht Standort Alter Größe Gewicht Bildung    Beruf    
##    <fct>                 <int> <fct>    <int> <int>   <dbl> <fct>      <fct>    
##  1 weiblich                437 Münster     18   172      69 Abitur     Inspekto…
##  2 weiblich                437 Münster     67   165      67 mittlere … Rentner*…
##  3 weiblich                437 Münster     60   175      NA Hochschule Ergother…
##  4 männlich                287 Münster     61   182      90 mittlere … Beamter*…
##  5 männlich                287 Münster     24   173      68 Abitur     Student*…
##  6 weiblich                437 Münster     21   177      60 Abitur     Student*…
##  7 weiblich                437 Münster     59   168      80 mittlere … arbeitlos
##  8 weiblich                437 Münster     56   156      60 Ausbildung Pflegehe…
##  9 männlich                287 Münster     82   184      NA mittlere … Kaufmann…
## 10 weiblich                437 Münster     52   166      60 Fachabitur Kaufmann…
## # … with 721 more rows, and 9 more variables: Familienstand <fct>,
## #   Kinder <int>, Wohnort <fct>, Rauchen <fct>, SportHäufig <dbl>,
## #   SportMinuten <dbl>, SportWie <fct>, SportWarum <fct>, LebenZufrieden <dbl>

Die Funktion n() fliefert die Anzahl der Fälle.

pf8 %>% 
  group_by(Standort, Geschlecht) %>% 
  drop_na() %>% 
  summarise(xquer = mean(Alter),
            sd = sd(Alter),
            median = median(Alter),
            n = n())
# A tibble: 9 x 6
# Groups:   Standort [4]
  Standort  Geschlecht xquer    sd median     n
  <fct>     <fct>      <dbl> <dbl>  <dbl> <int>
1 Rheine    männlich    34.3  15.4   26      67
2 Rheine    weiblich    37.6  17.8   33      83
3 Rheine    divers      32    NA     32       1
4 Münster   männlich    37.9  18.5   28      62
5 Münster   weiblich    38.8  20.0   27      83
6 Bahn      männlich    39.9  19.8   36      29
7 Bahn      weiblich    41.3  19.4   37.5    38
8 Ladbergen männlich    41.4  17.6   40      21
9 Ladbergen weiblich    43    18.5   40.5    14


6.7.8 Umgang mit Faktoren

Mit dem Paket forcats stehen im Tidyverse viele hilfreiche Funktionen für den Umgang mit Faktoren zur Verfügung.

6.7.8.1 Levels umbenennen

Mit der Funktion fct_recode() können Faktorenlevels umbenannt werden.

pf8 %>% 
  mutate(Geschlecht = fct_recode(Geschlecht, 
                      m ="männlich",
                      w = "weiblich",
                      d = "divers")) %>% 
  as_tibble()
## # A tibble: 731 x 16
##    Standort Alter Geschlecht Größe Gewicht Bildung   Beruf  Familienstand Kinder
##    <fct>    <int> <fct>      <int>   <dbl> <fct>     <fct>  <fct>          <int>
##  1 Münster     18 w            172      69 Abitur    Inspe… Partnerschaft      0
##  2 Münster     67 w            165      67 mittlere… Rentn… geschieden         0
##  3 Münster     60 w            175      NA Hochschu… Ergot… Partnerschaft      0
##  4 Münster     61 m            182      90 mittlere… Beamt… ledig              0
##  5 Münster     24 m            173      68 Abitur    Stude… ledig              0
##  6 Münster     21 w            177      60 Abitur    Stude… Partnerschaft      0
##  7 Münster     59 w            168      80 mittlere… arbei… verheiratet        0
##  8 Münster     56 w            156      60 Ausbildu… Pfleg… geschieden         2
##  9 Münster     82 m            184      NA mittlere… Kaufm… verheiratet        0
## 10 Münster     52 w            166      60 Fachabit… Kaufm… verheiratet        1
## # … with 721 more rows, and 7 more variables: Wohnort <fct>, Rauchen <fct>,
## #   SportHäufig <dbl>, SportMinuten <dbl>, SportWie <fct>, SportWarum <fct>,
## #   LebenZufrieden <dbl>

Enthalten die neuen Levelnamen Sonderzeichen (wie das Leerzeichen), müssen sie in Anführungsstrichen gesetzt werden.

pf8 %>% 
  mutate(Geschlecht = fct_recode(Geschlecht, 
                      "ein Mann" ="männlich",
                      "eine Frau" = "weiblich",
                      "ein(e) Divers" = "divers")) %>% 
  as_tibble()
## # A tibble: 731 x 16
##    Standort Alter Geschlecht Größe Gewicht Bildung   Beruf  Familienstand Kinder
##    <fct>    <int> <fct>      <int>   <dbl> <fct>     <fct>  <fct>          <int>
##  1 Münster     18 eine Frau    172      69 Abitur    Inspe… Partnerschaft      0
##  2 Münster     67 eine Frau    165      67 mittlere… Rentn… geschieden         0
##  3 Münster     60 eine Frau    175      NA Hochschu… Ergot… Partnerschaft      0
##  4 Münster     61 ein Mann     182      90 mittlere… Beamt… ledig              0
##  5 Münster     24 ein Mann     173      68 Abitur    Stude… ledig              0
##  6 Münster     21 eine Frau    177      60 Abitur    Stude… Partnerschaft      0
##  7 Münster     59 eine Frau    168      80 mittlere… arbei… verheiratet        0
##  8 Münster     56 eine Frau    156      60 Ausbildu… Pfleg… geschieden         2
##  9 Münster     82 ein Mann     184      NA mittlere… Kaufm… verheiratet        0
## 10 Münster     52 eine Frau    166      60 Fachabit… Kaufm… verheiratet        1
## # … with 721 more rows, and 7 more variables: Wohnort <fct>, Rauchen <fct>,
## #   SportHäufig <dbl>, SportMinuten <dbl>, SportWie <fct>, SportWarum <fct>,
## #   LebenZufrieden <dbl>

6.7.8.2 Levelreihenfolge ändern

Bei kategorialen Daten existiert keine geordnete Reihe der Werte. Dennoch kann es hilfreich sein, kategoriale Levels in eine bestimmte Reihenfolge zu bringen. Über die Hausfunktion factor() können über den Parameter levels die Levelreihenfolgen von Hand geändert werden.

x <- factor(c("vielleicht", "ja", "nein"))
x
## [1] vielleicht ja         nein      
## Levels: ja nein vielleicht
# ändere Levelreihenfolge
factor(x, levels=c("nein", "vielleicht", "ja"))
## [1] vielleicht ja         nein      
## Levels: nein vielleicht ja

Für häufige Anwendungsfälle bietet forcats Funktionen, die uns diese Arbeit abnehmen.

Schauen wir uns im Datensatz pf8 die Anlässe für Sport an. Das Skalenniveau ist nominal. Wenn wir die Daten plotten (zu ggplot siehe Kapitel 8.4), werden die Daten (die Diagrammsäulen) in der Reihenfolge der Levels angezeigt, und nicht in der Reihenfolge der Häufigkeiten.

pf8 %>% 
  select(SportWarum) %>% 
  drop_na() %>% 
  # dies ist der Plotbefehl, den Sie jetzt noch nicht verstehen.
  # Lesen Sie das Kapitel zu "ggplot".
  ggplot(aes(x=SportWarum)) + geom_bar()

Soll die Reihenfolgde der Levels so verändert werden, dass die mit der höchsten Ausprägung zuerst angezeigt werden, kann die Funktion fct_infreq() verwendet werden.

pf8 %>% 
  drop_na() %>% 
  # Sortiere nach Häufigkeiten
  mutate(SportWarum = fct_infreq(SportWarum)) %>% 
  # plotten
  ggplot(aes(x=SportWarum)) + geom_bar()

Mit der Funktion fct_rev() wird die Levelreihenfolge umgekehrt.

pf8 %>% 
  drop_na() %>% 
  # Sortiere nach Häufigkeiten
  mutate(SportWarum = fct_infreq(SportWarum)) %>% 
  # kehre Levelreihenfolge um
  mutate(SportWarum = fct_rev(SportWarum)) %>% 
  # plotten
  ggplot(aes(x=SportWarum)) + geom_bar()

Die Levelreihenfolge kann auch auf Grundlage einer anderen Variable erfolgen.

Erstellen wir uns hierfür ein Subset des pf8-Datensatzes, indem wir für jede Sport-Kategorie die Mittelwerte von Alter und Gewicht ermitteln.

pf8sub <- pf8 %>% 
            group_by(SportWarum) %>% 
            summarise(
              Alter = mean(Alter, na.rm=T),
              Gewicht = mean(Gewicht, na.rm=T),
              n = n()
            )
pf8sub
## # A tibble: 9 x 4
##   SportWarum        Alter Gewicht     n
##   <fct>             <dbl>   <dbl> <int>
## 1 0                  19      65       1
## 2 Vorbeugung         42.9    78.1   131
## 3 Gewichtsreduktion  31.9    81.7    56
## 4 Fitness            37.4    73.2   191
## 5 Therapie           52.4    80.8    14
## 6 Arbeitsweg         34.6    82.1    19
## 7 Beruflich          43.9    80.6    14
## 8 Freizeit           36.7    74.0    28
## 9 <NA>               34.1    73.9   277

Wenn wir die Daten plotten, folgen die Datenpunkte auch hier der Levelreihenfolge.

pf8sub %>% 
  # plotten
  ggplot(aes(x=Alter, y=SportWarum)) + geom_point()

Soll auch hier die Reihenfolge nach Mittelwerten erfolgen, kann die Funktion fct_reorder() verwendet werden.

pf8sub %>% 
  # überschreibe Variable "SportWarum"
  # ordne die Levels von "SportWarum" nach "Alter"
  mutate(SportWarum = fct_reorder(SportWarum, Alter)) %>% 
  # plotten  
  ggplot(aes(x=Alter, y=SportWarum)) + geom_point()

Beachten Sie, dass NA weiterhin ganz oben angezeigt werden.

Mit der Funktion fct_relevel() können einzelne Levels “nach vorne” geholt werden. In diesem Beispiel möchten wir, dass der Grund Freizeit als erstes angezeigt wird

pf8sub %>% 
  # überschreibe Variable "SportWarum"
  # ordne die Levels von "SportWarum" nach "Alter"
  mutate(SportWarum = fct_reorder(SportWarum, Alter)) %>% 
  # hole Level "Freizeit" nach vorne
  mutate(SportWarum = fct_relevel(SportWarum, "Freizeit")) %>% 
  # plotten  
  ggplot(aes(x=Alter, y=SportWarum)) + geom_point()

6.7.8.3 Levels zusammenfassen

Schauen wir uns die Berufe im Datenatz pf8 an.

pf8 %>% 
  dplyr::select(Beruf) %>% 
  dplyr::count(Beruf) %>% 
  arrange(n) %>% 
  as_tibble()
## # A tibble: 104 x 2
##    Beruf                    n
##    <fct>                <int>
##  1 " Produktionsleiter"     1
##  2 "Angestellte"            1
##  3 "Bäcker*in"              1
##  4 "Bauzeichner*in"         1
##  5 "Berater*in"             1
##  6 "Betriebsprüfer*in"      1
##  7 "Bibliothekar*in"        1
##  8 "Büchereileiter*in"      1
##  9 "Controller"             1
## 10 "Ergotherapeut*in"       1
## # … with 94 more rows

Wie Sie sehen, haben wir sehr viele Levels, die nur einmal oder zweimal vorkommen.


Mit der Funktion fct_lump_min() können wir niedrigausgeprägte Levels zusammenfassen.

pf8 %>% 
  drop_na() %>% 
  # fasse alle Levels mit Ausprägung kleiner 4 zusammen
  mutate(Beruf = fct_lump_min(Beruf, 4)) %>% 
  dplyr::select(Beruf) %>% 
  dplyr::count(Beruf) %>% 
  arrange(desc(n)) %>% 
  as_tibble()
## # A tibble: 22 x 2
##    Beruf             n
##    <fct>         <int>
##  1 Other           101
##  2 Student*in       82
##  3 kaufmann/frau    29
##  4 Handwerker*in    19
##  5 Angestellte*r    18
##  6 Azubi            17
##  7 Pflege           16
##  8 Rentner*in       14
##  9 Schüler*in       14
## 10 Lehrer*in        12
## # … with 12 more rows

Alle Levels mit Ausprägungen kleiner 4 wurden in der neuen Level Other zusammengefasst.

Mit der Funktion fct_lump_n() bleiben die höchsten n Levels erhalten, während der Rest unter Other zusammengefasst wird.

pf8 %>% 
  drop_na() %>% 
  # behalte die 3 höchstausgeprägtesten Levels
  # und fasse den Rest zusammen
  mutate(Beruf = fct_lump_n(Beruf, 3)) %>% 
  dplyr::select(Beruf) %>% 
  dplyr::count(Beruf) %>% 
  arrange(desc(n)) %>% 
  as_tibble()
## # A tibble: 4 x 2
##   Beruf             n
##   <fct>         <int>
## 1 Other           268
## 2 Student*in       82
## 3 kaufmann/frau    29
## 4 Handwerker*in    19


Mit der Funktion fct_collapse() können die Levels “von Hand” zusammengefasst werden. Schauen wir uns den Familienstand im Datensatz pf8 an.

  levels(pf8$Familienstand)
## [1] "ledig"         "Partnerschaft" "verheiratet"   "geschieden"   
## [5] "verwitwet"     "getrennt"

Fassen wir nun alle “verpartnerten” und alle “Singles” zu zwei Levels zusammen.

pf8 %>% 
  # fasse Singles und Partner in eigenen Levels zusammen
  mutate(Partnerschaft = fct_collapse(Familienstand,
                                      "Partnerschaft" = c("Partnerschaft", "verheiratet"),
                                      "Single" = c("ledig", "geschieden", "verwitwet", "getrennt"))) %>% 
  dplyr::select(Partnerschaft, Familienstand, Alter) %>% 
  as_tibble()
## # A tibble: 731 x 3
##    Partnerschaft Familienstand Alter
##    <fct>         <fct>         <int>
##  1 Partnerschaft Partnerschaft    18
##  2 Single        geschieden       67
##  3 Partnerschaft Partnerschaft    60
##  4 Single        ledig            61
##  5 Single        ledig            24
##  6 Partnerschaft Partnerschaft    21
##  7 Partnerschaft verheiratet      59
##  8 Single        geschieden       56
##  9 Partnerschaft verheiratet      82
## 10 Partnerschaft verheiratet      52
## # … with 721 more rows

6.7.9 Daten visualisieren

Zum Visualisieren von Daten sind neben Tabellen vor allem Diagramme geeignet. Wie Sie im Tidyverse Diagramme erstellen behandeln wir im Kapitel ggplot, siehe 8.4.

6.8 Schritt 4: Ergebisse kommunizieren

Ihre Ergebnisse können Sie Ihrem Publikum am besten mit RMarkdown kommunizieren. Lesen Sie hierzu Kapitel 5.

6.9 Die Macht der Pipe

Die volle Macht entfaltet das Tidyverse durch die Aneinanderreihung von Funktionen und Befehlen mittels der Pipe. Im Vergleich zum klassischen R kommen Sie so viel leichter zum Ziel, und Ihr Code ist gut les- und nachvollziehbar.

Versuchen Sie den folgenden Code nachzuvollziehen.

# lade Datensatz "mma"
load(url("https://www.produnis.de/R/mma.RData"))

mma %>% 
  drop_na() %>% 
  dplyr::filter(ward == "Chirurgie") %>% 
  group_by(day) %>% 
  ggplot(aes(x=category, fill=category)) + geom_bar(aes(fill=qual))

pf8 %>% 
  group_by(Geschlecht, Standort) %>% 
  drop_na() %>% 
  dplyr::filter(Rauchen == "ja") %>% 
  summarise(Mittelwert = mean(Alter),
            Median = median(Alter),
            Stdabw = sd(Alter))
##   Mittelwert Median  Stdabw
## 1    36.5493     30 16.5519

  1. Wickham, H; Grolemund, G (2017): R for Data Science: Import, Tidy, Transform, Visualize, and Model Data, O’Reilly Media, ISBN 978-1491910399, https://r4ds.had.co.nz/↩︎

  2. Wickham, H (2014): Tidy Data, Journal of Statistical Software, 59(10), doi: 10.18637/jss.v059.i10, https://www.jstatsoft.org/article/view/v059i10↩︎