library(tidyverse)
6 Data Wrangling II
Wir gehen nochmal zurück zum Uni-Datensatz vom Anfang:
<- data.frame(studs = c(19173,5333,15643),
dat1 profs = c(322,67,210),
gegr = c(1971,1830,1973),
prom_recht = rep(TRUE,3),
uni = c("Uni Bremen","Uni Vechta", "Uni Oldenburg"))
<- data.frame(studs = c(14954,47269 ,23659,9415 ,38079),
dat2 profs = c(250,553,438 ,150,636),
prom_recht = c(FALSE,TRUE,TRUE,TRUE,FALSE),
gegr = c(1971,1870,1457,1818,1995),
uni = c("FH Aachen","RWTH Aachen","Uni Freiburg","Uni Bonn","FH Bonn-Rhein-Sieg"))
dat1
studs profs gegr prom_recht uni
1 19173 322 1971 TRUE Uni Bremen
2 5333 67 1830 TRUE Uni Vechta
3 15643 210 1973 TRUE Uni Oldenburg
dat2
studs profs prom_recht gegr uni
1 14954 250 FALSE 1971 FH Aachen
2 47269 553 TRUE 1870 RWTH Aachen
3 23659 438 TRUE 1457 Uni Freiburg
4 9415 150 TRUE 1818 Uni Bonn
5 38079 636 FALSE 1995 FH Bonn-Rhein-Sieg
Mit bind_rows()
aus {dplyr}
können wir die beiden data.frame
s zusammensetzen:
<- bind_rows(dat1,dat2)
dat3 dat3
studs profs gegr prom_recht uni
1 19173 322 1971 TRUE Uni Bremen
2 5333 67 1830 TRUE Uni Vechta
3 15643 210 1973 TRUE Uni Oldenburg
4 14954 250 1971 FALSE FH Aachen
5 47269 553 1870 TRUE RWTH Aachen
6 23659 438 1457 TRUE Uni Freiburg
7 9415 150 1818 TRUE Uni Bonn
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg
Es gibt auch bind_cols()
um Datensätze spaltenweise zusammenzufügen. Möglichkeiten, Datensätzen auf Basis einer oder mehrer Identifikationsvariablen zu “mergen” lernen wir auch noch später kennen.
6.1 Variablen erstellen
Nun sehen wir uns die Möglichkeiten, Variablen zu erstellen, nochmal etwas genauer an. Grundsätzlich gibt es zwei Arten, Variablen in einen data.frame
hinzuzufügen:
6.1.1 base R: ...$newvar <-
$studs_to_mean <- dat3$studs - mean(dat3$studs)
dat3 dat3
studs profs gegr prom_recht uni studs_to_mean
1 19173 322 1971 TRUE Uni Bremen -2517.625
2 5333 67 1830 TRUE Uni Vechta -16357.625
3 15643 210 1973 TRUE Uni Oldenburg -6047.625
4 14954 250 1971 FALSE FH Aachen -6736.625
5 47269 553 1870 TRUE RWTH Aachen 25578.375
6 23659 438 1457 TRUE Uni Freiburg 1968.375
7 9415 150 1818 TRUE Uni Bonn -12275.625
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg 16388.375
Mit <- NULL
können Variablen auch gelöscht werden:
$studs_to_mean <- NULL
dat3 dat3
studs profs gegr prom_recht uni
1 19173 322 1971 TRUE Uni Bremen
2 5333 67 1830 TRUE Uni Vechta
3 15643 210 1973 TRUE Uni Oldenburg
4 14954 250 1971 FALSE FH Aachen
5 47269 553 1870 TRUE RWTH Aachen
6 23659 438 1457 TRUE Uni Freiburg
7 9415 150 1818 TRUE Uni Bonn
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg
6.1.2 {dplyr}: mutate(neue_var= )
Wir hatten die Variante aus {dplyr}
({tidyverse}
) bereits in Kapitel 3 kurz kennen gelernt. Die grundsätzliche Struktur ist immer datensatz %>% mutate(neue_var = ....)
:
%>% mutate(studs_to_mean = studs-mean(studs)) dat3
studs profs gegr prom_recht uni studs_to_mean
1 19173 322 1971 TRUE Uni Bremen -2517.625
2 5333 67 1830 TRUE Uni Vechta -16357.625
3 15643 210 1973 TRUE Uni Oldenburg -6047.625
4 14954 250 1971 FALSE FH Aachen -6736.625
5 47269 553 1870 TRUE RWTH Aachen 25578.375
6 23659 438 1457 TRUE Uni Freiburg 1968.375
7 9415 150 1818 TRUE Uni Bonn -12275.625
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg 16388.375
Wir können auch mehrere Variablen innerhalb eines mutate()
-Befehls erstellen:
%>% mutate(studs_to_mean = studs-mean(studs),
dat3 profs_to_mean = profs-mean(profs))
studs profs gegr prom_recht uni studs_to_mean profs_to_mean
1 19173 322 1971 TRUE Uni Bremen -2517.625 -6.25
2 5333 67 1830 TRUE Uni Vechta -16357.625 -261.25
3 15643 210 1973 TRUE Uni Oldenburg -6047.625 -118.25
4 14954 250 1971 FALSE FH Aachen -6736.625 -78.25
5 47269 553 1870 TRUE RWTH Aachen 25578.375 224.75
6 23659 438 1457 TRUE Uni Freiburg 1968.375 109.75
7 9415 150 1818 TRUE Uni Bonn -12275.625 -178.25
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg 16388.375 307.75
Oder Variablen können innerhalb von mutate()
weiterverwendet werden:
%>% mutate(rel_to_mean = studs-mean(studs),
dat3 above_mean = rel_to_mean > 0)
studs profs gegr prom_recht uni rel_to_mean above_mean
1 19173 322 1971 TRUE Uni Bremen -2517.625 FALSE
2 5333 67 1830 TRUE Uni Vechta -16357.625 FALSE
3 15643 210 1973 TRUE Uni Oldenburg -6047.625 FALSE
4 14954 250 1971 FALSE FH Aachen -6736.625 FALSE
5 47269 553 1870 TRUE RWTH Aachen 25578.375 TRUE
6 23659 438 1457 TRUE Uni Freiburg 1968.375 TRUE
7 9415 150 1818 TRUE Uni Bonn -12275.625 FALSE
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg 16388.375 TRUE
Der Ausgangsdatensatz bleibt aber unverändert:
dat3
studs profs gegr prom_recht uni
1 19173 322 1971 TRUE Uni Bremen
2 5333 67 1830 TRUE Uni Vechta
3 15643 210 1973 TRUE Uni Oldenburg
4 14954 250 1971 FALSE FH Aachen
5 47269 553 1870 TRUE RWTH Aachen
6 23659 438 1457 TRUE Uni Freiburg
7 9415 150 1818 TRUE Uni Bonn
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg
Wenn wir die Ergebnisse behalten wollen, müssen wir das Ergebnis in einem Objekt ablegen:
<-
dat4 %>%
dat3 mutate(rel_to_mean = studs-mean(studs),
above_mean = rel_to_mean > 0)
dat4
studs profs gegr prom_recht uni rel_to_mean above_mean
1 19173 322 1971 TRUE Uni Bremen -2517.625 FALSE
2 5333 67 1830 TRUE Uni Vechta -16357.625 FALSE
3 15643 210 1973 TRUE Uni Oldenburg -6047.625 FALSE
4 14954 250 1971 FALSE FH Aachen -6736.625 FALSE
5 47269 553 1870 TRUE RWTH Aachen 25578.375 TRUE
6 23659 438 1457 TRUE Uni Freiburg 1968.375 TRUE
7 9415 150 1818 TRUE Uni Bonn -12275.625 FALSE
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg 16388.375 TRUE
6.1.3 Übung
6.2 Gruppierung mit group_by()
& .by=
Die wirkliche Stärke von mutate()
kommt aber erst zum Tragen, wenn wir es mit weiteren {dplyr}
-Funktionen kombinieren. Eine häufige Aufgabe in der Datenaufbereitung sind gruppierte Werte.
Wir machen unseren Beispieldatensatz noch etwas kleiner:
<- dat3 %>%
dat5 select(-uni,-gegr) # nur dass alles zu sehen ist
Wenn wir einen Datensatz mit group_by()
entlang den Werten einer Variablen gruppieren, dann werden alle weiteren mutate()
Berechnungen nur innerhalb dieser Gruppen ausgeführt:
%>%
dat5 mutate(m_studs = mean(studs),
m_profs = mean(profs)) %>%
group_by(prom_recht) %>%
mutate(m_studs2 = mean(studs),
m_profs2 = mean(profs))
# A tibble: 8 × 7
# Groups: prom_recht [2]
studs profs prom_recht m_studs m_profs m_studs2 m_profs2
<dbl> <dbl> <lgl> <dbl> <dbl> <dbl> <dbl>
1 19173 322 TRUE 21691. 328. 20082 290
2 5333 67 TRUE 21691. 328. 20082 290
3 15643 210 TRUE 21691. 328. 20082 290
4 14954 250 FALSE 21691. 328. 26516. 443
5 47269 553 TRUE 21691. 328. 20082 290
6 23659 438 TRUE 21691. 328. 20082 290
7 9415 150 TRUE 21691. 328. 20082 290
8 38079 636 FALSE 21691. 328. 26516. 443
Verwenden wir group_by()
, können (sollten!) wir mit ungroup()
die Gruppierung wieder aufheben, sobald wir sie nicht mehr benötigen:
%>%
dat5 mutate(m_studs = mean(studs),
m_profs = mean(profs)) %>%
group_by(prom_recht) %>%
mutate(m_studs2 = mean(studs)) %>%
ungroup() %>%
mutate(m_profs2 = mean(profs))
studs profs prom_recht m_studs m_profs m_studs2 m_profs2
1 19173 322 TRUE 21690.62 328.25 20082.0 328.25
2 5333 67 TRUE 21690.62 328.25 20082.0 328.25
3 15643 210 TRUE 21690.62 328.25 20082.0 328.25
4 14954 250 FALSE 21690.62 328.25 26516.5 328.25
5 47269 553 TRUE 21690.62 328.25 20082.0 328.25
6 23659 438 TRUE 21690.62 328.25 20082.0 328.25
7 9415 150 TRUE 21690.62 328.25 20082.0 328.25
8 38079 636 FALSE 21690.62 328.25 26516.5 328.25
Seit {dplyr}
-Version 1.1.1 können wir direkt in mutate()
mit dem Argument .by=
eine Gruppierung angeben. Diese Gruppierung .by=
gilt dabei nur für die unmittelbaren Berechnungen innerhalb mutate()
- wir sparen uns das ungroup()
.
%>%
dat5 mutate(m_studs = mean(studs),
m_profs = mean(profs)) %>%
mutate(m_studs2 = mean(studs),
.by = prom_recht) %>%
mutate(m_profs2 = mean(profs))
studs profs prom_recht m_studs m_profs m_studs2 m_profs2
1 19173 322 TRUE 21690.62 328.25 20082.0 328.25
2 5333 67 TRUE 21690.62 328.25 20082.0 328.25
3 15643 210 TRUE 21690.62 328.25 20082.0 328.25
4 14954 250 FALSE 21690.62 328.25 26516.5 328.25
5 47269 553 TRUE 21690.62 328.25 20082.0 328.25
6 23659 438 TRUE 21690.62 328.25 20082.0 328.25
7 9415 150 TRUE 21690.62 328.25 20082.0 328.25
8 38079 636 FALSE 21690.62 328.25 26516.5 328.25
Mit summarise()
statt mutate()
erhalten wir eine Übersicht:
%>%
dat5 summarise(m_studs = mean(studs),.by = prom_recht)
prom_recht m_studs
1 TRUE 20082.0
2 FALSE 26516.5
6.2.1 Übung
6.3 across()
: Mehrere Variablen bearbeiten
Eine sehr vielseitige Erweiterung für mutate()
und summarise()
ist across()
. Hier mit können wir eine Funktion auf mehrere Spalten gleichzeitig anwenden, ohne uns zu wiederholen:
%>%
dat3 summarise(studs = mean(studs),
profs = mean(profs))
studs profs
1 21690.62 328.25
Hier ist across()
deutlich kürzer - für die Variablenauswahl können wir die ?select_helpers
verwenden - z.B. matches()
:
%>%
dat3 summarise(across(.cols = matches("studs|profs"),.fns = ~mean(.x)))
studs profs
1 21690.62 328.25
Natürlich ist das auch kombinierbar mit group_by()
:
%>%
dat3 group_by(prom_recht) %>%
summarise(across(matches("studs|profs"), ~mean(.x)))
# A tibble: 2 × 3
prom_recht studs profs
<lgl> <dbl> <dbl>
1 FALSE 26516. 443
2 TRUE 20082 290
Wir können auch mehrere Funktionen durchführen, dafür müssen wir sie in einer list()
angeben:
%>%
dat3 group_by(prom_recht) %>%
summarise(across(matches("studs|profs"), list(mean = ~mean(.x), sd = ~sd(.x))))
# A tibble: 2 × 5
prom_recht studs_mean studs_sd profs_mean profs_sd
<lgl> <dbl> <dbl> <dbl> <dbl>
1 FALSE 26516. 16352. 443 273.
2 TRUE 20082 14858. 290 183.
Diese list()
auch vorab ablegen und dann verwenden:
<- list(mean = ~mean(.x), sd = ~sd(.x), max = ~max(.x,na.rm = T))
wert_liste
%>%
dat3 group_by(prom_recht) %>%
summarise(across(matches("studs|profs"), wert_liste))
# A tibble: 2 × 7
prom_recht studs_mean studs_sd studs_max profs_mean profs_sd profs_max
<lgl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 FALSE 26516. 16352. 38079 443 273. 636
2 TRUE 20082 14858. 47269 290 183. 553
Mit dem .names()
-Argument können wir auch die Benennung der Spalten steuern. {.fn}
steht dabei als Platzhalter für die angewendete Funktion, {.col}
für den Namen der bearbeiteten Variable.
%>%
dat3 group_by(prom_recht) %>%
summarise(across(matches("studs|profs"),
list(mean = ~mean(.x), sd = ~sd(.x)),
.names = "{.fn}_{.col}"))
# A tibble: 2 × 5
prom_recht mean_studs sd_studs mean_profs sd_profs
<lgl> <dbl> <dbl> <dbl> <dbl>
1 FALSE 26516. 16352. 443 273.
2 TRUE 20082 14858. 290 183.
Alle gezeigten Funktionen funktionieren natürlich auch mit mutate()
:
%>%
dat3 mutate(across(matches("studs|profs"), ~mean(.x), .names = "m_{.col}"))
studs profs gegr prom_recht uni m_studs m_profs
1 19173 322 1971 TRUE Uni Bremen 21690.62 328.25
2 5333 67 1830 TRUE Uni Vechta 21690.62 328.25
3 15643 210 1973 TRUE Uni Oldenburg 21690.62 328.25
4 14954 250 1971 FALSE FH Aachen 21690.62 328.25
5 47269 553 1870 TRUE RWTH Aachen 21690.62 328.25
6 23659 438 1457 TRUE Uni Freiburg 21690.62 328.25
7 9415 150 1818 TRUE Uni Bonn 21690.62 328.25
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg 21690.62 328.25
Mehr Beispiele in der Hilfe zu across
6.3.1 Übung
6.4 Eigene Funktionen
Woher kommt aber die ~
1 in across()
? Dazu sehen wir uns einmal die Grundlagen von Funktionen in R an.
Dazu sehen wir uns drei Zufriedensheitsvariablen für die Befragten aus den Zeilen 12-16 an:
var | . | 1 | 2 | 3 | 4 | 7/8/9 |
---|---|---|---|---|---|---|
F1450_04 | Wie zufrieden sind Sie mit dem Betriebsklima? | sehr zufrieden | zufrieden | weniger zufrieden | nicht zufrieden | t.n.z./k.A. |
F1450_05 | Wie zufrieden sind Sie mit Ihrem direkten Vorgesetzen? | sehr zufrieden | zufrieden | weniger zufrieden | nicht zufrieden | t.n.z./k.A. |
F1450_06 | Wie zufrieden sind Sie mit Art und Inhalt der Tätigkeit? | sehr zufrieden | zufrieden | weniger zufrieden | nicht zufrieden | t.n.z./k.A. |
<- haven::read_dta("./data/BIBBBAuA_2018_suf1.0.dta")
etb18
<-
sat_small %>%
etb18 select(F1450_04,F1450_05,F1450_06) %>%
slice(12:16) %>%
::zap_labels() %>% haven::zap_label() # labels entfernen
haven sat_small
# A tibble: 5 × 3
F1450_04 F1450_05 F1450_06
<dbl> <dbl> <dbl>
1 3 3 2
2 2 2 1
3 2 2 1
4 2 2 2
5 1 2 2
Häufig wollen wir mehrere Variablen mit der gleichen Operation bearbeiten. Oben haben wir gesehen wie sich das mit across()
für existierende Funktionen erledigen lässt. Was aber, wenn wir eine Berechnung durchführen wollen, die nicht einfach die Anwendung von mean()
, sd()
o.ä. ist?
%>%
sat_small mutate(dmean_F1450_04 = F1450_04 - mean(F1450_04,na.rm = T),
dmean_F1450_05 = F1450_05 - mean(F1450_05,na.rm = T))
# A tibble: 5 × 5
F1450_04 F1450_05 F1450_06 dmean_F1450_04 dmean_F1450_05
<dbl> <dbl> <dbl> <dbl> <dbl>
1 3 3 2 1 0.8
2 2 2 1 0 -0.200
3 2 2 1 0 -0.200
4 2 2 2 0 -0.200
5 1 2 2 -1 -0.200
…und jetzt noch F1450_06
? Dann hätten wir drei Mal das mehr oder weniger gleiche getippt und damit gegen das “DRY”-Prinzip2 verstoßen. Außerdem gibt es in der ETB 2018 insgesamt 10 Spalten mit ähnlichen Zufriedenheitsvariablen. Wenn wir die alle bearbeiten möchten, ist copy & paste keine echte Option.
Eigene Funktionen helfen uns, das DRY-Prinzip in R umzusetzen. Wir machen die Berechnungsschritte Teil einer function()
und wenden diese dann auf die gewünschten Variablen an. Eine Funktion hat einen Input, für welchen ein Platzhalter in der ()
definiert wird. Dieser Platzhalter kann dann innerhalb der Funktion - zwischen den {}
- aufgerufen und bearbeitet werden. Als Ergebnis erhalten wir das Objekt, das wir in return()
angeben. return()
muss immer als letztes angeben werden und wir können immer nur ein Objekt als Output definieren:
<- function(x){
dtomean <- x - mean(x,na.rm = T)
d_x return(d_x)
}
<- c(1,6,3,7,8,1,5)
var1 mean(var1)
[1] 4.428571
dtomean(var1)
[1] -3.4285714 1.5714286 -1.4285714 2.5714286 3.5714286 -3.4285714 0.5714286
Wie können wir unsere Funktion dtomean()
jetzt auf die Variablen aus unserem sat_small
anwenden? Grundsätzlich haben wir ganz zu Beginn gesehen, dass ein data.frame
lediglich zusammengefügte Sammlung von Vektoren (den Variablen) ist. Dementsprechend können wir jetzt unsere dtomean()
auf eine Variable (einen Vektor) anwenden, indem wir ihn mit data.frame$variablename
aufrufen:
dtomean(sat_small$F1450_04)
[1] 1 0 0 0 -1
Um unsere Funktion jetzt auf jede Variable eines data.frame
anzuwenden, können wir map()
aus {purrr}
(ebenfalls Teil des {tidyverse}
) verwenden - der Output ist dann eine Liste, deren Elemente nach den Variablennamen benannt werden:
%>% map(.f = ~dtomean(.x)) sat_small
$F1450_04
[1] 1 0 0 0 -1
$F1450_05
[1] 0.8 -0.2 -0.2 -0.2 -0.2
$F1450_06
[1] 0.4 -0.6 -0.6 0.4 0.4
Mit bind_cols()
können wir die Liste spaltenweise zusammenfügen:
%>% map(~dtomean(.x)) %>% bind_cols() # formula syntax-Schreibweise sat_small
# A tibble: 5 × 3
F1450_04 F1450_05 F1450_06
<dbl> <dbl> <dbl>
1 1 0.8 0.4
2 0 -0.200 -0.6
3 0 -0.200 -0.6
4 0 -0.200 0.4
5 -1 -0.200 0.4
Diese formula syntax Schreibweise findet sich dann auch in across()
wieder - zusätzlich haben wir hier direkt über .names =
die Möglichkeit, die Variablennamen für die Ergebnisse zu bearbeiten:
%>%
sat_small mutate(across(matches("F1450"),~dtomean(.x),.names = "dmean_{.col}"))
# A tibble: 5 × 6
F1450_04 F1450_05 F1450_06 dmean_F1450_04 dmean_F1450_05 dmean_F1450_06
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 3 3 2 1 0.8 0.4
2 2 2 1 0 -0.200 -0.6
3 2 2 1 0 -0.200 -0.6
4 2 2 2 0 -0.200 0.4
5 1 2 2 -1 -0.200 0.4
6.4.1 Übung
6.5 Hilfsfunktionen ifelse()
und case_when()
ifelse()
ist eine große Hilfe für alle Umcodierungen: wir formulieren darin eine Bedingung und wenn diese zutrifft wird der erste Wert eingesetzt, wenn nicht wird der zweite Wert eingesetzt. Hier fragen wir also ab, ob studs-mean(studs)
größer 0
ist - dann wird darüber
eingesetzt, ansonsten eine darunter
:
%>% mutate(rel_to_mean = studs-mean(studs),
dat3 ab_mean_lab = ifelse(rel_to_mean > 0,"darüber","darunter"))
studs profs gegr prom_recht uni rel_to_mean ab_mean_lab
1 19173 322 1971 TRUE Uni Bremen -2517.625 darunter
2 5333 67 1830 TRUE Uni Vechta -16357.625 darunter
3 15643 210 1973 TRUE Uni Oldenburg -6047.625 darunter
4 14954 250 1971 FALSE FH Aachen -6736.625 darunter
5 47269 553 1870 TRUE RWTH Aachen 25578.375 darüber
6 23659 438 1457 TRUE Uni Freiburg 1968.375 darüber
7 9415 150 1818 TRUE Uni Bonn -12275.625 darunter
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg 16388.375 darüber
case_when()
({dplyr}
) erweitert dieses Prinzip, sodass wir mehr als zwei Optionen angeben können. Die Syntax ist aber etwas anders: hier geben wir erst die Bedingung an, dann nach einer ~
3 die einzusetzenden Werte:
%>% mutate(alter = case_when(gegr < 1500 ~ "sehr alt",
dat3 < 1900 ~ "alt")) gegr
studs profs gegr prom_recht uni alter
1 19173 322 1971 TRUE Uni Bremen <NA>
2 5333 67 1830 TRUE Uni Vechta alt
3 15643 210 1973 TRUE Uni Oldenburg <NA>
4 14954 250 1971 FALSE FH Aachen <NA>
5 47269 553 1870 TRUE RWTH Aachen alt
6 23659 438 1457 TRUE Uni Freiburg sehr alt
7 9415 150 1818 TRUE Uni Bonn alt
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg <NA>
Mit TRUE
können alle Fälle angesprochen werden, die bis dahin keiner Bedingung entsprochen haben:
%>% mutate(alter = case_when(gegr < 1500 ~ "sehr alt",
dat3 < 1900 ~ "alt",
gegr TRUE ~ "relativ neu"))
studs profs gegr prom_recht uni alter
1 19173 322 1971 TRUE Uni Bremen relativ neu
2 5333 67 1830 TRUE Uni Vechta alt
3 15643 210 1973 TRUE Uni Oldenburg relativ neu
4 14954 250 1971 FALSE FH Aachen relativ neu
5 47269 553 1870 TRUE RWTH Aachen alt
6 23659 438 1457 TRUE Uni Freiburg sehr alt
7 9415 150 1818 TRUE Uni Bonn alt
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg relativ neu
Das muss sich nicht auf eine Variable beschränken:
%>% mutate(alter = case_when(gegr < 1500 & prom_recht == T ~ "sehr alte Uni",
dat3 < 1900 & prom_recht == T ~ "alte Uni",
gegr > 1900 & prom_recht == T ~ "junge Uni",
gegr < 1900 & prom_recht == F ~ "alte Hochschule",
gegr > 1900 & prom_recht == F ~ "junge Hochschule")) gegr
studs profs gegr prom_recht uni alter
1 19173 322 1971 TRUE Uni Bremen junge Uni
2 5333 67 1830 TRUE Uni Vechta alte Uni
3 15643 210 1973 TRUE Uni Oldenburg junge Uni
4 14954 250 1971 FALSE FH Aachen junge Hochschule
5 47269 553 1870 TRUE RWTH Aachen alte Uni
6 23659 438 1457 TRUE Uni Freiburg sehr alte Uni
7 9415 150 1818 TRUE Uni Bonn alte Uni
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg junge Hochschule
6.5.1 Übung
6.6 Variablen umbenennen
Um Variablen umzubenennen gibt es rename(neuer_name = alter_name)
%>% rename(neu=F1450_04) sat_small
# A tibble: 5 × 3
neu F1450_05 F1450_06
<dbl> <dbl> <dbl>
1 3 3 2
2 2 2 1
3 2 2 1
4 2 2 2
5 1 2 2
Für fortgeschrittene Veränderungen empfiehlt sich ein Blick in rename_with()
. Damit können wir Regular Expressions, bspw. aus {stringr} verwenden. Hier nur ein Beispiel:
%>% rename_with(~tolower(.)) sat_small
# A tibble: 5 × 3
f1450_04 f1450_05 f1450_06
<dbl> <dbl> <dbl>
1 3 3 2
2 2 2 1
3 2 2 1
4 2 2 2
5 1 2 2
%>% rename_with(~str_remove(.x,"1450_")) sat_small
# A tibble: 5 × 3
F04 F05 F06
<dbl> <dbl> <dbl>
1 3 3 2
2 2 2 1
3 2 2 1
4 2 2 2
5 1 2 2
6.7 Übungen
6.7.1 Übung
- Erstellen Sie
dat3
wie oben gezeigt ausdat1
unddat2
- Berechnen Sie das Betreuungsverhältnis (Studierende pro Professur
studs/profs
) an den Hochschulen relativ zum Mittelwert des Betreuungsverhältnisses (rel_studprofs
). - Liegt das Betreuungsverhältnis über oder unter dem Mittelwert? Wie können Sie den Befehl anpassen, sodass die Variable
rel_studprofs
lediglichTRUE
oderFALSE
enthält anstelle der Zahlenwerte. - Wandeln Sie
rel_studprofs
in eine Dummy-Variable mit 0/1 als Werten stattTRUE
/FALSE
6.7.2 Übung
- Verwenden Sie weiterhin den Uni-Datensatz.
- Berechnen Sie das Betreuungsverhältnis (
studprofs
) relativ zum Mittelwert getrennt für Hochschulen/Unis mit und ohne Promotionsrecht und fügen Sie dieses als neue Spalte ein. - Testen Sie sowohl die Variante mit
group_by()
als auch.by =
.
6.7.3 Übung
- Verwenden Sie den
etb18_small
-Datensatz:
<- haven::read_dta("./data/BIBBBAuA_2018_suf1.0.dta",
etb18_small n_max = 10, # nur 10 Zeilen
col_select = c("zpalter","S1","F1450_01","F1450_02","F1450_03")
)
- Berechnen Sie den Mittelwert für die Variablen F1450_01, F1450_02, und F1450_03:
var | . |
---|---|
F1450_01 | Wie zufrieden sind Sie mit dem Einkommen aus dieser Tätigkeit? |
F1450_02 | Wie zufrieden sind Sie mit den derzeitigen Aufstiegsmöglichkeiten? |
F1450_03 | Wie zufrieden sind Sie mit Ihrer derzeitigen Arbeitszeit? |
zpalter S1 F1450_01 F1450_02 F1450_03
1 41 1 2 NA 3
2 51 2 4 4 2
3 49 1 2 4 2
4 63 2 2 2 2
5 41 2 2 2 2
6 57 1 1 2 4
7 62 1 2 NA 2
8 59 2 3 7 2
9 32 2 3 3 3
10 62 2 2 2 1
- Verwenden Sie
across()
und denken Sie ggf. daran, dass SieNA
s diena.rm = T
inmean()
setzen müssen:mean(....,na.rm = T)
- Berechnen Sie die Mittelwerte getrennt nach Geschlecht, indem Sie
group_by()
oder.by =
verwenden. - Fügen Sie auch die Varianz (
var()
) hinzu und nutzen sie.names=
, um die Spaltennamen nach dem Schemakennzahl.variable
zu benennen.
6.7.4 Übung
Verwenden Sie etb18_small3
:
<- haven::read_dta("./data/BIBBBAuA_2018_suf1.0.dta",
etb18_small3 col_select = c("zpalter","S1","F1450_01","F1450_02","F1450_03"))
<- etb18_small3 %>% slice(5654:5666)
etb18_small3 etb18_small3
# A tibble: 13 × 5
zpalter S1 F1450_01 F1450_02 F1450_03
<dbl+lbl> <dbl+lbl> <dbl+lbl> <dbl+lbl> <dbl+lbl>
1 54 2 [weiblich] 9 [keine Angabe] 4 [nicht zufrieden] 4 [nicht…
2 60 2 [weiblich] 2 [zufrieden] 2 [zufrieden] 2 [zufri…
3 63 1 [männlich] 2 [zufrieden] 2 [zufrieden] 2 [zufri…
4 49 2 [weiblich] 2 [zufrieden] 2 [zufrieden] 2 [zufri…
5 62 2 [weiblich] 1 [sehr zufrieden] 7 [Es gibt keine] 2 [zufri…
6 52 1 [männlich] 1 [sehr zufrieden] NA 1 [sehr …
7 59 1 [männlich] 2 [zufrieden] 2 [zufrieden] 2 [zufri…
8 59 1 [männlich] 1 [sehr zufrieden] NA 1 [sehr …
9 33 1 [männlich] 2 [zufrieden] NA 2 [zufri…
10 41 2 [weiblich] 2 [zufrieden] 7 [Es gibt keine] 9 [keine…
11 50 2 [weiblich] 2 [zufrieden] 7 [Es gibt keine] 1 [sehr …
12 42 2 [weiblich] 3 [weniger zufrieden] 3 [weniger zufrieden] 3 [wenig…
13 28 2 [weiblich] 9 [keine Angabe] 2 [zufrieden] 2 [zufri…
zpalter S1 F1450_01 F1450_02 F1450_03
1 54 2 9 4 4
2 60 2 2 2 2
3 63 1 2 2 2
4 49 2 2 2 2
5 62 2 1 7 2
6 52 1 1 NA 1
7 59 1 2 2 2
8 59 1 1 NA 1
9 33 1 2 NA 2
10 41 2 2 7 9
11 50 2 2 7 1
12 42 2 3 3 3
13 28 2 9 2 2
var | . | 1 | 2 | 3 | 4 | 7/8/9 |
---|---|---|---|---|---|---|
F1450_01 | Wie zufrieden sind Sie mit dem Einkommen aus dieser Tätigkeit? | sehr zufrieden | zufrieden | weniger zufrieden | nicht zufrieden | t.n.z./k.A. |
F1450_02 | Wie zufrieden sind Sie mit den derzeitigen Aufstiegsmöglichkeiten? | sehr zufrieden | zufrieden | weniger zufrieden | nicht zufrieden | t.n.z./k.A. |
F1450_03 | Wie zufrieden sind Sie mit Ihrer derzeitigen Arbeitszeit? | sehr zufrieden | zufrieden | weniger zufrieden | nicht zufrieden | t.n.z./k.A. |
- Standardisieren Sie die Variablen F1450_01 - F1450_03 aus
etb_small2
nach folgendem Muster:
%>%
etb_small2 mutate(std_F1450_01 = (F1450_01 - mean(F1450_01,na.rm = T))/sd(F1450_01,na.rm = T))
- Nutzen Sie eine Funktion, um nicht wiederholt die gleichen Schritte einzugeben.
- Verwenden Sie zusätzlich
across()
, um die Funktion auf die gewünschten Variablen anzuwenden.
6.7.5 Übung
- Bearbeiten Sie
etb18_small
:
<- haven::read_dta("./data/BIBBBAuA_2018_suf1.0.dta",
etb18_small2 col_select = c("zpalter","S1","F1450_01","F1450_02","F1450_03"))
<- etb18_small2 %>% slice(5654:5666)
etb18_small2 etb18_small2
# A tibble: 13 × 5
zpalter S1 F1450_01 F1450_02 F1450_03
<dbl+lbl> <dbl+lbl> <dbl+lbl> <dbl+lbl> <dbl+lbl>
1 54 2 [weiblich] 9 [keine Angabe] 4 [nicht zufrieden] 4 [nicht…
2 60 2 [weiblich] 2 [zufrieden] 2 [zufrieden] 2 [zufri…
3 63 1 [männlich] 2 [zufrieden] 2 [zufrieden] 2 [zufri…
4 49 2 [weiblich] 2 [zufrieden] 2 [zufrieden] 2 [zufri…
5 62 2 [weiblich] 1 [sehr zufrieden] 7 [Es gibt keine] 2 [zufri…
6 52 1 [männlich] 1 [sehr zufrieden] NA 1 [sehr …
7 59 1 [männlich] 2 [zufrieden] 2 [zufrieden] 2 [zufri…
8 59 1 [männlich] 1 [sehr zufrieden] NA 1 [sehr …
9 33 1 [männlich] 2 [zufrieden] NA 2 [zufri…
10 41 2 [weiblich] 2 [zufrieden] 7 [Es gibt keine] 9 [keine…
11 50 2 [weiblich] 2 [zufrieden] 7 [Es gibt keine] 1 [sehr …
12 42 2 [weiblich] 3 [weniger zufrieden] 3 [weniger zufrieden] 3 [wenig…
13 28 2 [weiblich] 9 [keine Angabe] 2 [zufrieden] 2 [zufri…
- Nutzen Sie
ifelse()
, um Personen ab 50 Jahren mit “ü50” zu kennzeichnen - lassen Sie für Personen bis unter 50 Jahren “u50” eintragen. - Führen Sie eine Dreiteilung durch: Personen bis 40 bekommen “u40”, Personen bis einschließlich 50 “u50” und Personen über 50 Jahren “ü50”. Wie würden Sie mit
case_when()
vorgehen? - Nutzen Sie
ifelse()
, um Werte > 4 in den VariablenF1450_01
,F1450_02
, undF1450_03
inetb18_small2
mitNA
zu überschreiben. - Schreiben Sie zunächst eine
ifelse()
-Funktion, die fürF1450_01
alle Werte > 4 mitNA
überschreibt und ansonsten den AusgangswertF1450_01
einsetzt. - Wie würde die Funktion aussehen, wenn Sie sie mit
across()
aufF1450_01
,F1450_02
undF1450_03
gleichzeitig anwenden?
6.8 Anhang
6.8.1 Klassen bilden mit cut()
dat3
studs profs gegr prom_recht uni
1 19173 322 1971 TRUE Uni Bremen
2 5333 67 1830 TRUE Uni Vechta
3 15643 210 1973 TRUE Uni Oldenburg
4 14954 250 1971 FALSE FH Aachen
5 47269 553 1870 TRUE RWTH Aachen
6 23659 438 1457 TRUE Uni Freiburg
7 9415 150 1818 TRUE Uni Bonn
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg
Eine häufig Aufgabe in der Datenaufbereitung die Klassierung eines metrisches Merkmals, wie zum Beispiel die Professorenzahlen. Wir möchten also profs
in 150er-Schritten zusammenfassen. Um die Klassen zu bilden, nutzen wir cut()
und geben neben der zu unterteilenden Variable mit breaks
die Klassengrenzen an. Für die Grenzen können wir seq()
verwenden. Darin geben wir zunächst die obere und untere Grenze an und dann die Schrittbreiten.
cut(dat3$profs,breaks = c(50, 200, 350, 500, 650))
[1] (200,350] (50,200] (200,350] (200,350] (500,650] (350,500] (50,200]
[8] (500,650]
Levels: (50,200] (200,350] (350,500] (500,650]
cut(dat3$profs,breaks = seq(50,650,150))
[1] (200,350] (50,200] (200,350] (200,350] (500,650] (350,500] (50,200]
[8] (500,650]
Levels: (50,200] (200,350] (350,500] (500,650]
Diese Werte legen wir in einer neuen Variable im Datensatz dat3
ab:
$prof_class <- cut(dat3$profs,breaks = seq(50,650,150))
dat3 dat3
studs profs gegr prom_recht uni prof_class
1 19173 322 1971 TRUE Uni Bremen (200,350]
2 5333 67 1830 TRUE Uni Vechta (50,200]
3 15643 210 1973 TRUE Uni Oldenburg (200,350]
4 14954 250 1971 FALSE FH Aachen (200,350]
5 47269 553 1870 TRUE RWTH Aachen (500,650]
6 23659 438 1457 TRUE Uni Freiburg (350,500]
7 9415 150 1818 TRUE Uni Bonn (50,200]
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg (500,650]
Für diese neue Variable können wir mit count()
eine Häufigkeitstabelle anfordern:
%>% count(prof_class) dat3
prof_class n
1 (50,200] 2
2 (200,350] 3
3 (350,500] 1
4 (500,650] 2
(
bedeutet dabei ausgeschlossen, ]
inklusive. Es gibt also 3 Unis im Datensatz, die über 200 bis inklusive 350 Professuren unterhalten.
Für die weiteren Beispiele löschen wir die prof_class
wieder:
$prof_class <- NULL dat3
Einige hilfreiche Optionen für cut()
im Anhang
<- c(1990,1998,2001,2009)
bsp bsp
[1] 1990 1998 2001 2009
cut(bsp,breaks = c(1990,2000,2010))
[1] <NA> (1.99e+03,2e+03] (2e+03,2.01e+03] (2e+03,2.01e+03]
Levels: (1.99e+03,2e+03] (2e+03,2.01e+03]
# Anzahl der stellen in den labels
cut(bsp,breaks = c(1990,2000,2010),dig.lab = 4)
[1] <NA> (1990,2000] (2000,2010] (2000,2010]
Levels: (1990,2000] (2000,2010]
# untere Grenze mit einbeziehen
cut(bsp,breaks = c(1990,2000,2010),dig.lab = 4,include.lowest = T)
[1] [1990,2000] [1990,2000] (2000,2010] (2000,2010]
Levels: [1990,2000] (2000,2010]
# durchnummerieren statt labels:
cut(bsp,breaks = c(1990,2000,2010),labels = FALSE)
[1] NA 1 2 2
# eigene labels angeben:
cut(bsp,breaks = c(1990,2000,2010),labels = c("90er","00er"))
[1] <NA> 90er 00er 00er
Levels: 90er 00er
6.8.2 String-Funktionen für regex
{stringr} stellt eine ganze Reihe an sehr hilfreichen String-Funktionen mit Regular Expressions zur Verfügung, einen Überblick bietet das Cheatsheet
%>% mutate(uni_fh = str_detect(uni,"Uni")) dat3
studs profs gegr prom_recht uni uni_fh
1 19173 322 1971 TRUE Uni Bremen TRUE
2 5333 67 1830 TRUE Uni Vechta TRUE
3 15643 210 1973 TRUE Uni Oldenburg TRUE
4 14954 250 1971 FALSE FH Aachen FALSE
5 47269 553 1870 TRUE RWTH Aachen FALSE
6 23659 438 1457 TRUE Uni Freiburg TRUE
7 9415 150 1818 TRUE Uni Bonn TRUE
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg FALSE
%>% mutate(bula = case_when(str_detect(uni,"Bremen")~ "HB",
dat3 str_detect(uni,"Oldenb|Vechta")~ "NDS",
str_detect(uni,"Bonn|Aachen")~ "NRW",
str_detect(uni,"Freiburg")~ "BW"
))
studs profs gegr prom_recht uni bula
1 19173 322 1971 TRUE Uni Bremen HB
2 5333 67 1830 TRUE Uni Vechta NDS
3 15643 210 1973 TRUE Uni Oldenburg NDS
4 14954 250 1971 FALSE FH Aachen NRW
5 47269 553 1870 TRUE RWTH Aachen NRW
6 23659 438 1457 TRUE Uni Freiburg BW
7 9415 150 1818 TRUE Uni Bonn NRW
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg NRW
%>% mutate(ort = str_remove(uni,"Uni |FH |RWTH ")) dat3
studs profs gegr prom_recht uni ort
1 19173 322 1971 TRUE Uni Bremen Bremen
2 5333 67 1830 TRUE Uni Vechta Vechta
3 15643 210 1973 TRUE Uni Oldenburg Oldenburg
4 14954 250 1971 FALSE FH Aachen Aachen
5 47269 553 1870 TRUE RWTH Aachen Aachen
6 23659 438 1457 TRUE Uni Freiburg Freiburg
7 9415 150 1818 TRUE Uni Bonn Bonn
8 38079 636 1995 FALSE FH Bonn-Rhein-Sieg Bonn-Rhein-Sieg
“Tilde” - Tastaturbefehle:
Alt Gr
+*
auf Windows. Auf macOSAlt
+N
und anschließend ein Leerzeichen, damit die Tilde erscheint.↩︎Do not repeat yourself, siehe Wickham et al: “You should consider writing a function whenever you’ve copied and pasted a block of code more than twice (i.e. you now have three copies of the same code).”↩︎
“Tilde” - Tastaturbefehle:
Alt Gr
+*
auf Windows. Auf macOSAlt
+N
und anschließend ein Leerzeichen, damit die Tilde erscheint.↩︎