dplyr: Eine Grammatik zur Datenaufbereitung von Hadley Wickham Rmd

‘pliers’: Zange

Datenaufbereitung in R heißt normalerweise, sich intensiv mit dem Thema ‘slicing’ auseinanderzusetzen ../transformation/transformation_base.html.

Dies ist sehr stark orientiert an Programmierkonzepten und einem “Gefühl für Syntax”, besonders dann, wenn es Probleme gibt. Als Alternative zu diesem Vorgehen ist das Paket dplyr entstanden, das vieles bei der Datenaufbereitung in R intuitiver und einfacher macht.

Das Package dplyr stellt eine Sammlung von Befehlen zur Datenmanipulation zur Verfügung. Dem Paket liegt eine Grammatik zur Datenaufbereitung zugrunde (A Grammar of Data Manipulation). Es wurde entwickelt von Hadley Wickham

Zentral ist hierbei das Konzept “gutstrukturierter Daten” (“tidy data”). Siehe hierzu Hadley Wickhams Artikel zu tidy data, auch lokal.

Alle dplyr Befehle erwarten als ersten Parameter einen Dataframe/Tibble und geben einen Dataframe/Tibble als Ergebnis zurück. Das Verständnis, was in R ein Dataframe bzw. Tibble ist, wird in diesem Tutorial vorausgesetzt.

Wir stellen hier einige der Befehle (verbs) vor, die dplyr() zur Verfügung stellt, sowie jeweils einige Beispiele hierzu.

Alle Erläuterungen benutzen einen kleinen Beispiel-Datensatz, die in einem dataframe namens df geladen sind.

# get some data to play with
require(tidyverse)
## Loading required package: 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()
df <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
# take a look at the data: 12 observations, 7 variables
df
## # A tibble: 12 x 7
##     subj gender   age   grp    v1    v2    v3
##    <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl>
##  1     1 f         17     1     9    16     8
##  2     2 f         33     2    67    73    66
##  3     3 f         47     3    86    87    91
##  4     4 f         10     1    64    68    67
##  5     5 f         21     2    40    46    44
##  6     6 f         30     3    26    34    28
##  7     7 m         51     1    64    66    64
##  8     8 m         13     2    61    66    64
##  9     9 m         17     3    67    67    67
## 10    10 m         25     1    38    36    35
## 11    11 m         33     2    22    25    21
## 12    12 m         27     3    81    86    81

Datentransformation in R “klassisch”

“klassisch” mein hier, Verwenden von Slicing-Techniken (Subsetting) in Kombination mit Assigning-Techniken

… verschachtelte Befehle sind unübersichtlich, fehlerträchtig und führen schnell zu sehr kryptischen Ausdrücken

require(tidyverse)
df <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
# find v-values of all women aged 25 or more
df[df$gender == "f" & df$age >= 25, c('v1', 'v2', 'v3')]
## # A tibble: 3 x 3
##      v1    v2    v3
##   <dbl> <dbl> <dbl>
## 1    67    73    66
## 2    86    87    91
## 3    26    34    28
# mean of the above values per subject
apply(df[df$gender == "f" & df$age >= 25, c('v1', 'v2', 'v3')], 2, mean)
##       v1       v2       v3 
## 59.66667 64.66667 61.66667
# make all the above to a small table, means attached at the right
cbind(df[df$gender == "f" & df$age >= 25, c('v1', 'v2', 'v3')], apply(df[df$gender == "f" & df$age >= 25, c('v1', 'v2', 'v3')], 2, mean))
##    v1 v2 v3 apply(df[df$gender == "f" & df$age >= 25, c("v1", "v2", "v3")], 
## v1 67 73 66                                                         59.66667
## v2 86 87 91                                                         64.66667
## v3 26 34 28                                                         61.66667

dplyr: Basic verbs

  • filter() ähnlich subset() für Teilstichproben
  • arrange() zum geordneten Ausgeben
  • select() Variablenauswahl
  • mutate() zum Erzeugen neuer Variablen, z. B. durch Verrechnung anderer
  • distinct() für Ausprägungen und Ausprägungskombinationen
  • summarise() aggregieren
  • uvm

Verb filter() für Teilstichproben

Wir können Teilstichproben erhalten, indem wir eine oder mehrere Bedingungen angeben, die die Beobachtungen erfüllen müssen, um ausgegeben zu werden.

require(tidyverse)
df <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
#require(dplyr)

# verb filter: get observertions that comply certain conditions

# get all women
dplyr::filter(df, gender=='f')
## # A tibble: 6 x 7
##    subj gender   age   grp    v1    v2    v3
##   <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl>
## 1     1 f         17     1     9    16     8
## 2     2 f         33     2    67    73    66
## 3     3 f         47     3    86    87    91
## 4     4 f         10     1    64    68    67
## 5     5 f         21     2    40    46    44
## 6     6 f         30     3    26    34    28
# we can use a combination of several conditions: get all men of group 2
dplyr::filter(df, gender=='m', grp==2)
## # A tibble: 2 x 7
##    subj gender   age   grp    v1    v2    v3
##   <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl>
## 1     8 m         13     2    61    66    64
## 2    11 m         33     2    22    25    21

Verb arrange() zum geordneten Ausgeben

Wir können einen Dataframe vielfältig umordnen lassen.

require(tidyverse)
df <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
# require(dplyr)

# verb arrange: reorder data frames
# sort by one variable: group membership
dplyr::arrange(df, grp)
## # A tibble: 12 x 7
##     subj gender   age   grp    v1    v2    v3
##    <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl>
##  1     1 f         17     1     9    16     8
##  2     4 f         10     1    64    68    67
##  3     7 m         51     1    64    66    64
##  4    10 m         25     1    38    36    35
##  5     2 f         33     2    67    73    66
##  6     5 f         21     2    40    46    44
##  7     8 m         13     2    61    66    64
##  8    11 m         33     2    22    25    21
##  9     3 f         47     3    86    87    91
## 10     6 f         30     3    26    34    28
## 11     9 m         17     3    67    67    67
## 12    12 m         27     3    81    86    81
# we may sort by various variables simultaneously: get highest to lowest v1 scores per group
dplyr::arrange(df, grp, desc(v1))
## # A tibble: 12 x 7
##     subj gender   age   grp    v1    v2    v3
##    <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl>
##  1     4 f         10     1    64    68    67
##  2     7 m         51     1    64    66    64
##  3    10 m         25     1    38    36    35
##  4     1 f         17     1     9    16     8
##  5     2 f         33     2    67    73    66
##  6     8 m         13     2    61    66    64
##  7     5 f         21     2    40    46    44
##  8    11 m         33     2    22    25    21
##  9     3 f         47     3    86    87    91
## 10    12 m         27     3    81    86    81
## 11     9 m         17     3    67    67    67
## 12     6 f         30     3    26    34    28

Verb select() Variablenauswahl (Spalten)

Wir können nur eine Untermenge der zur Verfügung stehenden Variablen auswählen.

require(tidyverse)
df <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
# require(dplyr)

# verb select: get certain columns
# get subject, gender and grp; we provide a simple list of the variables
dplyr::select(df, subj, gender, age, grp)
## # A tibble: 12 x 4
##     subj gender   age   grp
##    <dbl> <chr>  <dbl> <dbl>
##  1     1 f         17     1
##  2     2 f         33     2
##  3     3 f         47     3
##  4     4 f         10     1
##  5     5 f         21     2
##  6     6 f         30     3
##  7     7 m         51     1
##  8     8 m         13     2
##  9     9 m         17     3
## 10    10 m         25     1
## 11    11 m         33     2
## 12    12 m         27     3
# we may benefit from the sequence of variables in the dataframe using the ':' operator to get the above
dplyr::select(df, subj:grp)
## # A tibble: 12 x 4
##     subj gender   age   grp
##    <dbl> <chr>  <dbl> <dbl>
##  1     1 f         17     1
##  2     2 f         33     2
##  3     3 f         47     3
##  4     4 f         10     1
##  5     5 f         21     2
##  6     6 f         30     3
##  7     7 m         51     1
##  8     8 m         13     2
##  9     9 m         17     3
## 10    10 m         25     1
## 11    11 m         33     2
## 12    12 m         27     3
# we may even get all variables that share some naming convention: get all variables whichs name starts with letter "v"
dplyr::select(df, starts_with('v'))
## # A tibble: 12 x 3
##       v1    v2    v3
##    <dbl> <dbl> <dbl>
##  1     9    16     8
##  2    67    73    66
##  3    86    87    91
##  4    64    68    67
##  5    40    46    44
##  6    26    34    28
##  7    64    66    64
##  8    61    66    64
##  9    67    67    67
## 10    38    36    35
## 11    22    25    21
## 12    81    86    81
# we can get the same, using regular expressions: variable names first letter is v and it continues with at least one more character
dplyr::select(df, matches("[v]+"))
## # A tibble: 12 x 3
##       v1    v2    v3
##    <dbl> <dbl> <dbl>
##  1     9    16     8
##  2    67    73    66
##  3    86    87    91
##  4    64    68    67
##  5    40    46    44
##  6    26    34    28
##  7    64    66    64
##  8    61    66    64
##  9    67    67    67
## 10    38    36    35
## 11    22    25    21
## 12    81    86    81
# search variable that contains certain substring: all names with "e"
dplyr::select(df, contains('e'))
## # A tibble: 12 x 2
##    gender   age
##    <chr>  <dbl>
##  1 f         17
##  2 f         33
##  3 f         47
##  4 f         10
##  5 f         21
##  6 f         30
##  7 m         51
##  8 m         13
##  9 m         17
## 10 m         25
## 11 m         33
## 12 m         27

cheatsheet regular expressions

Verb mutate() zum Erzeugen neuer Variablen, z. B. durch Verrechnung anderer

Wir können Variablen verändern und neue Variablen auf Basis von bestehenden generieren. Definierte Variablen können sofort verwendet werden, auch im selben Ausdruck schon.

require(tidyverse)
# require(dplyr)
# df <- read_tsv("http://134.76.136.204/data/div/df_dplyr.txt")
df <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
df$gender <- factor(df$gender)

# verb mutate: create new variables
# rescale v1 to vary between 0 and 1
dplyr::mutate(df, v1q = v1 / 100)
## # A tibble: 12 x 8
##     subj gender   age   grp    v1    v2    v3   v1q
##    <dbl> <fct>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1     1 f         17     1     9    16     8  0.09
##  2     2 f         33     2    67    73    66  0.67
##  3     3 f         47     3    86    87    91  0.86
##  4     4 f         10     1    64    68    67  0.64
##  5     5 f         21     2    40    46    44  0.4 
##  6     6 f         30     3    26    34    28  0.26
##  7     7 m         51     1    64    66    64  0.64
##  8     8 m         13     2    61    66    64  0.61
##  9     9 m         17     3    67    67    67  0.67
## 10    10 m         25     1    38    36    35  0.38
## 11    11 m         33     2    22    25    21  0.22
## 12    12 m         27     3    81    86    81  0.81
# inversion of variable v2 that varies between 0 and 100
dplyr::mutate(df, v2_inv = 100 - v2)
## # A tibble: 12 x 8
##     subj gender   age   grp    v1    v2    v3 v2_inv
##    <dbl> <fct>  <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>
##  1     1 f         17     1     9    16     8     84
##  2     2 f         33     2    67    73    66     27
##  3     3 f         47     3    86    87    91     13
##  4     4 f         10     1    64    68    67     32
##  5     5 f         21     2    40    46    44     54
##  6     6 f         30     3    26    34    28     66
##  7     7 m         51     1    64    66    64     34
##  8     8 m         13     2    61    66    64     34
##  9     9 m         17     3    67    67    67     33
## 10    10 m         25     1    38    36    35     64
## 11    11 m         33     2    22    25    21     75
## 12    12 m         27     3    81    86    81     14
# age in days
dplyr::mutate(df, age_days = age * 365)
## # A tibble: 12 x 8
##     subj gender   age   grp    v1    v2    v3 age_days
##    <dbl> <fct>  <dbl> <dbl> <dbl> <dbl> <dbl>    <dbl>
##  1     1 f         17     1     9    16     8     6205
##  2     2 f         33     2    67    73    66    12045
##  3     3 f         47     3    86    87    91    17155
##  4     4 f         10     1    64    68    67     3650
##  5     5 f         21     2    40    46    44     7665
##  6     6 f         30     3    26    34    28    10950
##  7     7 m         51     1    64    66    64    18615
##  8     8 m         13     2    61    66    64     4745
##  9     9 m         17     3    67    67    67     6205
## 10    10 m         25     1    38    36    35     9125
## 11    11 m         33     2    22    25    21    12045
## 12    12 m         27     3    81    86    81     9855
# newly generated variables can be used within the same operation
dplyr::mutate(df, age_days = age * 365, age_months = age_days / 30)
## # A tibble: 12 x 9
##     subj gender   age   grp    v1    v2    v3 age_days age_months
##    <dbl> <fct>  <dbl> <dbl> <dbl> <dbl> <dbl>    <dbl>      <dbl>
##  1     1 f         17     1     9    16     8     6205       207.
##  2     2 f         33     2    67    73    66    12045       402.
##  3     3 f         47     3    86    87    91    17155       572.
##  4     4 f         10     1    64    68    67     3650       122.
##  5     5 f         21     2    40    46    44     7665       256.
##  6     6 f         30     3    26    34    28    10950       365 
##  7     7 m         51     1    64    66    64    18615       620.
##  8     8 m         13     2    61    66    64     4745       158.
##  9     9 m         17     3    67    67    67     6205       207.
## 10    10 m         25     1    38    36    35     9125       304.
## 11    11 m         33     2    22    25    21    12045       402.
## 12    12 m         27     3    81    86    81     9855       328.

Achtung: Funktionen wie mean() oder sum() etc. funktionieren hier nicht, wie vielleicht erwartet zeilenweise, sondern setzen den Grand Mean bei mean() ein. Den zeilenweisen Effekt bekommt man über rowwise() (s. u.).

Verb distinct() für Ausprägungen und Ausprägungskombinationen

Wir können Ausprägungen von Variablen auflisten, auch Kombinationen von Ausprägungen, die im Datensatz vorkommen.

require(tidyverse)
df <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
# require(dplyr)

# verb distinct: the first occurance of any distinct observation is shown
# do we have men and women in the sample?
dplyr::distinct(df, gender)
## # A tibble: 2 x 1
##   gender
##   <chr> 
## 1 f     
## 2 m
# which group levels are available?
dplyr::distinct(df, grp)
## # A tibble: 3 x 1
##     grp
##   <dbl>
## 1     1
## 2     2
## 3     3
# we can also look for combinations or variables: which combinations of gender and grp can be found in the data?
dplyr::distinct(df, gender, grp)
## # A tibble: 6 x 2
##   gender   grp
##   <chr>  <dbl>
## 1 f          1
## 2 f          2
## 3 f          3
## 4 m          1
## 5 m          2
## 6 m          3

Verb summarise() aggregieren

Wir können Variablen zusammenfassen und vielfältige Operationen auf sie ausführen.

require(tidyverse)
df <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
# require(dplyr)

# verb summarise: aggregate data by column
# mean of v1
dplyr::summarise(df, mean(c(v1)))
## # A tibble: 1 x 1
##   `mean(c(v1))`
##           <dbl>
## 1          52.1
# grand mean of variables v1, v2, and v3
dplyr::summarise(df, mean(c(v1, v2, v3)))
## # A tibble: 1 x 1
##   `mean(c(v1, v2, v3))`
##                   <dbl>
## 1                  53.6
# mean of special columns
dplyr::summarise(df, mean(v1), mean(v3))
## # A tibble: 1 x 2
##   `mean(v1)` `mean(v3)`
##        <dbl>      <dbl>
## 1       52.1         53
# get mean, standard deviation and n of v2, result only
dplyr::summarise(df, mean(v2), sd(v2), n())
## # A tibble: 1 x 3
##   `mean(v2)` `sd(v2)` `n()`
##        <dbl>    <dbl> <int>
## 1       55.8     23.7    12
# get the same named
dplyr::summarise(df, v2_m = mean(v2), v2_sd = sd(v2), v2_n = n())
## # A tibble: 1 x 3
##    v2_m v2_sd  v2_n
##   <dbl> <dbl> <int>
## 1  55.8  23.7    12

Verb summarise_all() für wiederholtes summarise() über mehrere Variablen

Ein typischer Anwendungsfall mehrfacher Aktionen ist, dass dieselbe Operation auf viele Variablen ausgeführt werden soll. Hierzu dient der Befehl summarise_all().

require(tidyverse)
df <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
# require(dplyr)

# create a temporary dataframe
df.t <- dplyr::select(df, age, v1, v2, v3)

# we might be interested in the means of all variables
dplyr::summarise_all(df.t, funs(mean))
## Warning: `funs()` was deprecated in dplyr 0.8.0.
## Please use a list of either functions or lambdas: 
## 
##   # Simple named list: 
##   list(mean = mean, median = median)
## 
##   # Auto named with `tibble::lst()`: 
##   tibble::lst(mean, median)
## 
##   # Using lambdas
##   list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))
## # A tibble: 1 x 4
##     age    v1    v2    v3
##   <dbl> <dbl> <dbl> <dbl>
## 1    27  52.1  55.8    53
# we can apply for several functions at a time
# f. e. we might want to check the plausibility of data by controlling the range of answers
dplyr::summarise_all(df.t, funs(min, max, sd, mean))
## # A tibble: 1 x 16
##   age_min v1_min v2_min v3_min age_max v1_max v2_max v3_max age_sd v1_sd v2_sd
##     <dbl>  <dbl>  <dbl>  <dbl>   <dbl>  <dbl>  <dbl>  <dbl>  <dbl> <dbl> <dbl>
## 1      10      9     16      8      51     86     87     91   12.7  24.5  23.7
## # … with 5 more variables: v3_sd <dbl>, age_mean <dbl>, v1_mean <dbl>,
## #   v2_mean <dbl>, v3_mean <dbl>
# we delete the temporary dataframe, we have better options ...
rm(df.t)

Teilgruppen behandeln mit group_by()

Möchten wir über Teilgruppen hinweg immer wieder dasselbe tun, beispielsweise einen Mittelwert über Variablen haben, müssen wir den summarise() Befehl nicht immer wieder auf vorher ausgewählte, einzelne Teilgruppen ausführen. Mit dem Befehl group_by können wir die relevanten Teilgruppen einmal festlegen und dann über diese Teilgruppen Aktionen ausführen.

require(tidyverse)
df <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
# require(dplyr)

# group by: get the same for several subgroups
df_grouped <- dplyr::group_by(df, grp)
# get means of v1, v2 and v3 for each group
dplyr::summarise(df_grouped, mean(v1), mean(v2), mean(v3) )
## # A tibble: 3 x 4
##     grp `mean(v1)` `mean(v2)` `mean(v3)`
##   <dbl>      <dbl>      <dbl>      <dbl>
## 1     1       43.8       46.5       43.5
## 2     2       47.5       52.5       48.8
## 3     3       65         68.5       66.8
# get means of v1, v2 and v3 for each group
dplyr::summarise(df_grouped, mean(v1), sd(v1), mean(v2), sd(v2), mean(v3), sd(v3) )
## # A tibble: 3 x 7
##     grp `mean(v1)` `sd(v1)` `mean(v2)` `sd(v2)` `mean(v3)` `sd(v3)`
##   <dbl>      <dbl>    <dbl>      <dbl>    <dbl>      <dbl>    <dbl>
## 1     1       43.8     26.2       46.5     25.1       43.5     27.7
## 2     2       47.5     20.6       52.5     21.6       48.8     21.0
## 3     3       65       27.2       68.5     24.8       66.8     27.6

Verketten von Aktionen mit %>%

Häufig braucht man für eine Datenmodifikation mehrere Teilschritte. Beispielsweise könnte man für eine Teilgruppe eine Aktion über eine Teilmenge der Variablen wollen. Hier bräuchte man also eine Kombination aus filter() und select(). Nun könnte man das erreichen, in dem man die Ergebnisse der Zwischenschritte immer in einem Dataframe speichert und im nachfolgenden Schritt wieder als Parameter übergibt. Da dies aber ein häufiges Anliegen ist, sieht dplyr hierfür eine verkürzte Schreibweise vor: %>%. Wegen des Prinzips von dplyr, immer einen Dataframe als ersten Parameter zu erwarten, auf das die geforderten Aktionen ausgeübt werden und einen Dataframe als Ergebnis zurückzugeben, wird diese verkürzte Anweisungsart möglich.

Das Ergebnis einer Kette von Teilschritten kann, wie gewohnt, mit dem Zuweisugsoperator ->, <-, oder = als Ergebnis-Dataframe gespeichert werden.

require(tidyverse)
df <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
# require(dplyr)

# chained actions using %>%
# we might want to do something with the three variables v1, v2, and v2 for women only
# we could do this step by step by saving the resulting dataframes
df.f <- dplyr::filter(df, gender=="f") 
dplyr::select(df.f, v1:v3)
## # A tibble: 6 x 3
##      v1    v2    v3
##   <dbl> <dbl> <dbl>
## 1     9    16     8
## 2    67    73    66
## 3    86    87    91
## 4    64    68    67
## 5    40    46    44
## 6    26    34    28
# but we have as shortcut for that: the resulting dataframe of the filter() is passed automatically as first parameter to select()
# the select() does not get a dataframe as first parameter, this is done implicitly
dplyr::filter(df, gender=="f") %>% dplyr::select(v1:v3)
## # A tibble: 6 x 3
##      v1    v2    v3
##   <dbl> <dbl> <dbl>
## 1     9    16     8
## 2    67    73    66
## 3    86    87    91
## 4    64    68    67
## 5    40    46    44
## 6    26    34    28
# alternative
df %>% dplyr::filter(gender=="f") %>% dplyr::select(v1:v3)
## # A tibble: 6 x 3
##      v1    v2    v3
##   <dbl> <dbl> <dbl>
## 1     9    16     8
## 2    67    73    66
## 3    86    87    91
## 4    64    68    67
## 5    40    46    44
## 6    26    34    28
# the chain migth be longer ...
dplyr::filter(df, gender=="f") %>% dplyr::group_by(grp) %>% dplyr::select(v1:v3)  %>% dplyr::summarise_each(funs(mean))
## Warning: `summarise_each_()` was deprecated in dplyr 0.7.0.
## Please use `across()` instead.
## Adding missing grouping variables: `grp`
## # A tibble: 3 x 4
##     grp    v1    v2    v3
##   <dbl> <dbl> <dbl> <dbl>
## 1     1  36.5  42    37.5
## 2     2  53.5  59.5  55  
## 3     3  56    60.5  59.5

Aktionen innerhalb einer Beobachtung - zeilenweise Datenmodifikationen und Transformationen - rowwise(), die Probleme damit und die Ansätze zu Lösungen

Häufig ist es notwendig, bei jeder einzelnen Beobachtung aus einer oder auch mehreren Variablen eine neue Variable zu berechnen. Typische Beispiele hierfür sind: Aus Einzelitems eines Fragebogens Summen- oder Mittelwerte zu berechnen, die dann als Ausprägung auf einer Eigenschaftsdimension interpretiert werden. Ein inhaltliches Beispiel wäre im NEO-FFI das Mitteln über die 12 Neurotizismus-Items als Neurotizismus-Skala.

Zentral für zeilenweise Modifikationen ist hierbei der Befehl rowwise().

Mit mutate() können wir beliebige, auch selbst definierte Funktionen zeilenweise auf die Daten anwenden.

require(tidyverse)
dd <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
# require(dplyr)


# verb: rowwise()
# we might want to have the individual means of the three variables v1 to v3
dplyr::rowwise(dd) %>% dplyr::mutate(v_mean = mean(c(v1, v2, v3))) 
## # A tibble: 12 x 8
## # Rowwise: 
##     subj gender   age   grp    v1    v2    v3 v_mean
##    <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>
##  1     1 f         17     1     9    16     8   11  
##  2     2 f         33     2    67    73    66   68.7
##  3     3 f         47     3    86    87    91   88  
##  4     4 f         10     1    64    68    67   66.3
##  5     5 f         21     2    40    46    44   43.3
##  6     6 f         30     3    26    34    28   29.3
##  7     7 m         51     1    64    66    64   64.7
##  8     8 m         13     2    61    66    64   63.7
##  9     9 m         17     3    67    67    67   67  
## 10    10 m         25     1    38    36    35   36.3
## 11    11 m         33     2    22    25    21   22.7
## 12    12 m         27     3    81    86    81   82.7
# just to note: without rowwise() this would not work correctly
dplyr::mutate(dd, v_mean = mean(c(v1, v2, v3)))  # caution: THIS IS WRONG
## # A tibble: 12 x 8
##     subj gender   age   grp    v1    v2    v3 v_mean
##    <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>
##  1     1 f         17     1     9    16     8   53.6
##  2     2 f         33     2    67    73    66   53.6
##  3     3 f         47     3    86    87    91   53.6
##  4     4 f         10     1    64    68    67   53.6
##  5     5 f         21     2    40    46    44   53.6
##  6     6 f         30     3    26    34    28   53.6
##  7     7 m         51     1    64    66    64   53.6
##  8     8 m         13     2    61    66    64   53.6
##  9     9 m         17     3    67    67    67   53.6
## 10    10 m         25     1    38    36    35   53.6
## 11    11 m         33     2    22    25    21   53.6
## 12    12 m         27     3    81    86    81   53.6
# building questionnaire scales often requires to invert items before aggregating them
dplyr::rowwise(dd) %>% dplyr::mutate(v2_i = 100 - v2) %>% dplyr::mutate(v_mean = mean(c(v1, v2_i, v3))) 
## # A tibble: 12 x 9
## # Rowwise: 
##     subj gender   age   grp    v1    v2    v3  v2_i v_mean
##    <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>
##  1     1 f         17     1     9    16     8    84   33.7
##  2     2 f         33     2    67    73    66    27   53.3
##  3     3 f         47     3    86    87    91    13   63.3
##  4     4 f         10     1    64    68    67    32   54.3
##  5     5 f         21     2    40    46    44    54   46  
##  6     6 f         30     3    26    34    28    66   40  
##  7     7 m         51     1    64    66    64    34   54  
##  8     8 m         13     2    61    66    64    34   53  
##  9     9 m         17     3    67    67    67    33   55.7
## 10    10 m         25     1    38    36    35    64   45.7
## 11    11 m         33     2    22    25    21    75   39.3
## 12    12 m         27     3    81    86    81    14   58.7
  # rowwise means seems to work only using unquoted column names
  # unquoted column names need to be combined c()
# without inversion we could even use the : operator when variables are one aside the other
dplyr::rowwise(dd) %>% dplyr::mutate(v_mean = mean(c(v1:v3))) 
## # A tibble: 12 x 8
## # Rowwise: 
##     subj gender   age   grp    v1    v2    v3 v_mean
##    <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>
##  1     1 f         17     1     9    16     8    8.5
##  2     2 f         33     2    67    73    66   66.5
##  3     3 f         47     3    86    87    91   88.5
##  4     4 f         10     1    64    68    67   65.5
##  5     5 f         21     2    40    46    44   42  
##  6     6 f         30     3    26    34    28   27  
##  7     7 m         51     1    64    66    64   64  
##  8     8 m         13     2    61    66    64   62.5
##  9     9 m         17     3    67    67    67   67  
## 10    10 m         25     1    38    36    35   36.5
## 11    11 m         33     2    22    25    21   21.5
## 12    12 m         27     3    81    86    81   81
# we might even use some function outside of dplyr commands with piping: here rowMeans
dd %>% dplyr::mutate(v2_i = 100 - v2) %>% dplyr::select(v1, v2_i, v3) %>% dplyr::rowwise() %>% rowMeans()
##  [1] 33.66667 53.33333 63.33333 54.33333 46.00000 40.00000 54.00000 53.00000
##  [9] 55.66667 45.66667 39.33333 58.66667
# as rowMeans already works rowwise, we don't need rowwise when using with rowMeans()
# so we get the same doing
dd %>% dplyr::mutate(v2_i = 100 - v2) %>% dplyr::select(v1, v2_i, v3) %>% rowMeans()
##  [1] 33.66667 53.33333 63.33333 54.33333 46.00000 40.00000 54.00000 53.00000
##  [9] 55.66667 45.66667 39.33333 58.66667
# we might even define our own function and apply it to each row
# we define a function that returns the mean of a vector of values excluding the lowest one
mean_c <- function(x){return (mean(x[order(x)[2:length(x)]]))}
# just to see what mean_c does: this should return 6, the mean of 8 and 4, 2 is excluded
mean_c(c(8,4,2))
## [1] 6
# we want to have the mean of v1, v2, and v3, excluding the minimum value of the three. this should be done for each observation.
dplyr::rowwise(dd) %>%  dplyr::mutate(v_mean_c = mean_c(c(v1, v2, v3)))
## # A tibble: 12 x 8
## # Rowwise: 
##     subj gender   age   grp    v1    v2    v3 v_mean_c
##    <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl>    <dbl>
##  1     1 f         17     1     9    16     8     12.5
##  2     2 f         33     2    67    73    66     70  
##  3     3 f         47     3    86    87    91     89  
##  4     4 f         10     1    64    68    67     67.5
##  5     5 f         21     2    40    46    44     45  
##  6     6 f         30     3    26    34    28     31  
##  7     7 m         51     1    64    66    64     65  
##  8     8 m         13     2    61    66    64     65  
##  9     9 m         17     3    67    67    67     67  
## 10    10 m         25     1    38    36    35     37  
## 11    11 m         33     2    22    25    21     23.5
## 12    12 m         27     3    81    86    81     83.5

Die Erweiterung der verbs auf *_by

Die dplyr-Kommandos haben inzwischen eine Variante bekommen, die die jeweilige Manipulation nur auf Teile der Daten beschränkt. Dies hat den Vorteil, dass der Rest der Daten unverändert “mitgenommen” wird und am Ende gespeichert werden können.

Ein paar Beispiele

require(tidyverse)
dd <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
# todo ...

additional stuff

Aggregate with and without collapsing

We can summarize over observations, defined by group_by(). Then we have one summarized value per subgroup. This can be saved in a collapsed manner. Alternatively the summarized value can be stored in a new column for all observations. All members of a subgroup as defined by group_by() then share the same summarized value.

require(tidyverse)
dd <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
dd %>% dplyr::group_by(grp) %>% dplyr::mutate(av.v1 = mean(v1, na.rm = TRUE))
## # A tibble: 12 x 8
## # Groups:   grp [3]
##     subj gender   age   grp    v1    v2    v3 av.v1
##    <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1     1 f         17     1     9    16     8  43.8
##  2     2 f         33     2    67    73    66  47.5
##  3     3 f         47     3    86    87    91  65  
##  4     4 f         10     1    64    68    67  43.8
##  5     5 f         21     2    40    46    44  47.5
##  6     6 f         30     3    26    34    28  65  
##  7     7 m         51     1    64    66    64  43.8
##  8     8 m         13     2    61    66    64  47.5
##  9     9 m         17     3    67    67    67  65  
## 10    10 m         25     1    38    36    35  43.8
## 11    11 m         33     2    22    25    21  47.5
## 12    12 m         27     3    81    86    81  65
dd %>% dplyr::group_by(gender) %>% dplyr::mutate(av.v1 = mean(v1, na.rm = TRUE))
## # A tibble: 12 x 8
## # Groups:   gender [2]
##     subj gender   age   grp    v1    v2    v3 av.v1
##    <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1     1 f         17     1     9    16     8  48.7
##  2     2 f         33     2    67    73    66  48.7
##  3     3 f         47     3    86    87    91  48.7
##  4     4 f         10     1    64    68    67  48.7
##  5     5 f         21     2    40    46    44  48.7
##  6     6 f         30     3    26    34    28  48.7
##  7     7 m         51     1    64    66    64  55.5
##  8     8 m         13     2    61    66    64  55.5
##  9     9 m         17     3    67    67    67  55.5
## 10    10 m         25     1    38    36    35  55.5
## 11    11 m         33     2    22    25    21  55.5
## 12    12 m         27     3    81    86    81  55.5
# dealing with serveral modifications
dd %>% dplyr::group_by(gender) %>% dplyr::summarise(av.v1 = mean(v1, na.rm = TRUE), av.v2 = mean(v2, na.rm = TRUE))  # summarise collapses
## # A tibble: 2 x 3
##   gender av.v1 av.v2
##   <chr>  <dbl> <dbl>
## 1 f       48.7  54  
## 2 m       55.5  57.7
dd %>% dplyr::group_by(gender) %>% dplyr::mutate(av.v1 = mean(v1, na.rm = TRUE), av.v2 = mean(v2, na.rm = TRUE))     # mutate aggregates only and keeps the observations
## # A tibble: 12 x 9
## # Groups:   gender [2]
##     subj gender   age   grp    v1    v2    v3 av.v1 av.v2
##    <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1     1 f         17     1     9    16     8  48.7  54  
##  2     2 f         33     2    67    73    66  48.7  54  
##  3     3 f         47     3    86    87    91  48.7  54  
##  4     4 f         10     1    64    68    67  48.7  54  
##  5     5 f         21     2    40    46    44  48.7  54  
##  6     6 f         30     3    26    34    28  48.7  54  
##  7     7 m         51     1    64    66    64  55.5  57.7
##  8     8 m         13     2    61    66    64  55.5  57.7
##  9     9 m         17     3    67    67    67  55.5  57.7
## 10    10 m         25     1    38    36    35  55.5  57.7
## 11    11 m         33     2    22    25    21  55.5  57.7
## 12    12 m         27     3    81    86    81  55.5  57.7
# multiple grouping is possible
dd %>% dplyr::group_by(gender, grp) %>% dplyr::summarize(av.v1 = mean(v1, na.rm = TRUE))
## `summarise()` has grouped output by 'gender'. You can override using the `.groups` argument.
## # A tibble: 6 x 3
## # Groups:   gender [2]
##   gender   grp av.v1
##   <chr>  <dbl> <dbl>
## 1 f          1  36.5
## 2 f          2  53.5
## 3 f          3  56  
## 4 m          1  51  
## 5 m          2  41.5
## 6 m          3  74
dd %>% dplyr::group_by(gender, grp) %>% dplyr::mutate(av.v1 = mean(v1, na.rm = TRUE))
## # A tibble: 12 x 8
## # Groups:   gender, grp [6]
##     subj gender   age   grp    v1    v2    v3 av.v1
##    <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1     1 f         17     1     9    16     8  36.5
##  2     2 f         33     2    67    73    66  53.5
##  3     3 f         47     3    86    87    91  56  
##  4     4 f         10     1    64    68    67  36.5
##  5     5 f         21     2    40    46    44  53.5
##  6     6 f         30     3    26    34    28  56  
##  7     7 m         51     1    64    66    64  51  
##  8     8 m         13     2    61    66    64  41.5
##  9     9 m         17     3    67    67    67  74  
## 10    10 m         25     1    38    36    35  51  
## 11    11 m         33     2    22    25    21  41.5
## 12    12 m         27     3    81    86    81  74
dd %>% group_by(gender, grp) %>% dplyr::mutate(av.v1 = mean(v1, na.rm = TRUE, av.v2 = mean(v2, na.rm = TRUE)))
## # A tibble: 12 x 8
## # Groups:   gender, grp [6]
##     subj gender   age   grp    v1    v2    v3 av.v1
##    <dbl> <chr>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1     1 f         17     1     9    16     8  36.5
##  2     2 f         33     2    67    73    66  53.5
##  3     3 f         47     3    86    87    91  56  
##  4     4 f         10     1    64    68    67  36.5
##  5     5 f         21     2    40    46    44  53.5
##  6     6 f         30     3    26    34    28  56  
##  7     7 m         51     1    64    66    64  51  
##  8     8 m         13     2    61    66    64  41.5
##  9     9 m         17     3    67    67    67  74  
## 10    10 m         25     1    38    36    35  51  
## 11    11 m         33     2    22    25    21  41.5
## 12    12 m         27     3    81    86    81  74

ifelse() and case_when()

Um einen Teil der Zeilen einer Spalte zu überschreiben, z. B. subgruppenspezifisch, können wir ifelse() verwenden und den veränderten DataFrame zurückspeichern.

require(tidyverse)
df <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
# require(dplyr)
# is there a gender difference in 
df %>% dplyr::group_by(gender) %>% dplyr::summarise(mean(v1), mean(v2), mean(v3))
## # A tibble: 2 x 4
##   gender `mean(v1)` `mean(v2)` `mean(v3)`
##   <chr>       <dbl>      <dbl>      <dbl>
## 1 f            48.7       54         50.7
## 2 m            55.5       57.7       55.3
t.test(v1 ~ gender, data=df)
## 
##  Welch Two Sample t-test
## 
## data:  v1 by gender
## t = -0.46636, df = 9.2652, p-value = 0.6517
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -39.83543  26.16876
## sample estimates:
## mean in group f mean in group m 
##        48.66667        55.50000
# lower v1 values of men in place
df %>% mutate(v1 = ifelse(gender == "m", v1 - 7, v1)) -> df
t.test(v1 ~ gender, data=df)
## 
##  Welch Two Sample t-test
## 
## data:  v1 by gender
## t = 0.011375, df = 9.2652, p-value = 0.9912
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -32.83543  33.16876
## sample estimates:
## mean in group f mean in group m 
##        48.66667        48.50000

mit case_when()

c.f.

require(tidyverse)
df <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
# require(dplyr)
# is there a gender difference in 
df %>% dplyr::group_by(gender) %>% dplyr::summarise(mean(v1), mean(v2), mean(v3))
## # A tibble: 2 x 4
##   gender `mean(v1)` `mean(v2)` `mean(v3)`
##   <chr>       <dbl>      <dbl>      <dbl>
## 1 f            48.7       54         50.7
## 2 m            55.5       57.7       55.3
t.test(v1 ~ gender, data=df)
## 
##  Welch Two Sample t-test
## 
## data:  v1 by gender
## t = -0.46636, df = 9.2652, p-value = 0.6517
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -39.83543  26.16876
## sample estimates:
## mean in group f mean in group m 
##        48.66667        55.50000
# lower v1 values of men in place
df %>% dplyr::mutate(v1 = as.double(v1)) %>%
  dplyr::mutate(vn = dplyr::case_when(gender == 'm' ~ v1 - 7, 
                            gender == 'f' ~ v1, 
                            TRUE ~ NA_real_)) -> df
t.test(vn ~ gender, data=df)
## 
##  Welch Two Sample t-test
## 
## data:  vn by gender
## t = 0.011375, df = 9.2652, p-value = 0.9912
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -32.83543  33.16876
## sample estimates:
## mean in group f mean in group m 
##        48.66667        48.50000

Example of correcting for differences

We can use dplyr to control statistical models and use model properties to do some data modification. Here we take out a gender level difference.

# is there a gender difference
dd <- readr::read_tsv("https://md.psych.bio.uni-goettingen.de/mv/data/div/df_dplyr.txt")
## 
## ── Column specification ────────────────────────────────────────────────────────
## cols(
##   subj = col_double(),
##   gender = col_character(),
##   age = col_double(),
##   grp = col_double(),
##   v1 = col_double(),
##   v2 = col_double(),
##   v3 = col_double()
## )
dd %>% dplyr::group_by(gender) %>% dplyr::summarise(mean(v1), mean(v2), mean(v3))
## # A tibble: 2 x 4
##   gender `mean(v1)` `mean(v2)` `mean(v3)`
##   <chr>       <dbl>      <dbl>      <dbl>
## 1 f            48.7       54         50.7
## 2 m            55.5       57.7       55.3
(tt <- t.test(v1 ~ gender, data=dd))
## 
##  Welch Two Sample t-test
## 
## data:  v1 by gender
## t = -0.46636, df = 9.2652, p-value = 0.6517
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -39.83543  26.16876
## sample estimates:
## mean in group f mean in group m 
##        48.66667        55.50000
gender_diff <- tt[['estimate']][2] - tt[['estimate']][1]
# let's take out the gender difference by lowerin mens v1 values in place and store it back to the data object
dd %>% dplyr::mutate(v1 = as.double(v1)) %>%
  dplyr::mutate(vn = dplyr::case_when(gender == 'm' ~ v1 - gender_diff, 
                                      gender == 'f' ~ v1, 
                                      TRUE ~ NA_real_)) -> dd
# the difference should have disappeared
t.test(vn ~ gender, data=dd)
## 
##  Welch Two Sample t-test
## 
## data:  vn by gender
## t = 0, df = 9.2652, p-value = 1
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  -33.00209  33.00209
## sample estimates:
## mean in group f mean in group m 
##        48.66667        48.66667

Aufgaben zu dplyr

Im Datensatz Big5_GEMI_R_recoded.csv finden sich die Daten von 160 Vpn. Von allen haben wir das Alter, das Geschlecht (0=Frau, 1=Mann) sowie 60 NEO-FFI Items. Die zu invertierenden Items sind bereits umkodiert. Die entsprechenden Variablennamen enden auf "_rec" (z. B. neo_ffi_8_rec, neo_ffi_9_rec).

Die Skala Extraversion setzt sich zusammen aus den Variablen:

neo_ffi_2, neo_ffi_7, neo_ffi_12_rec, neo_ffi_17, neo_ffi_22, neo_ffi_27_rec, neo_ffi_32, neo_ffi_37, neo_ffi_42_rec, neo_ffi_47, neo_ffi_52, neo_ffi_57_rec

  1. Wir brauchen einen temporären Dataframe “data_e_t”, der nur die Extraversionsitems enthält

  2. Erstelle einen Dataframe “data_e”, der das Geschlecht, das Alter sowie die Extraversionsitems enthält.

  3. Bilde eine Variable mit Namen “neo_e”, in der der Mittelwert aus den Extraversions-Items gebildet wird und an den Dataframe data_e angehängt wird.

  4. Gebe aus “data_e” Alter, Geschlecht und die Skalenwerte “neo_e” aller Frauen (vpsex hat Wert 0) aus, die über 24 Jahre alt sind.

  5. Gebe aus “data_e” den Mittelwert von “neo_e” aus, getrennt nach Geschlecht. Normalerweise haben Frauen etwas höhere Extraversions-Werte wie Männer.

Lösungen

require(tidyverse)
data <- read.csv2('http://e-scientifics.de/content/datasets/Big5_GEMI_R_recoded.csv') # read data, items already recoded
# require(dplyr)


# solution 1.
data_e_t <- dplyr::select(data, neo_ffi_2, neo_ffi_7, neo_ffi_12_rec, neo_ffi_17, neo_ffi_22, neo_ffi_27_rec, neo_ffi_32, neo_ffi_37, neo_ffi_42_rec, neo_ffi_47, neo_ffi_52, neo_ffi_57_rec)
# take a look at it
head(dplyr::select(data_e_t, neo_ffi_2:neo_ffi_22))
##   neo_ffi_2 neo_ffi_7 neo_ffi_12_rec neo_ffi_17 neo_ffi_22
## 1         1         1              2          1          1
## 2         1         0              1          2          1
## 3        -1         1              1          2         -1
## 4         2         1              2          1          0
## 5         1         2              2          2          0
## 6         1         2              2          2          0
# and delete this temporary dataframe
rm(data_e_t)


# solution 2.
data_e <- dplyr::select(data, vpsex, vpage, neo_ffi_2, neo_ffi_7, neo_ffi_12_rec, neo_ffi_17, neo_ffi_22, neo_ffi_27_rec, neo_ffi_32, neo_ffi_37, neo_ffi_42_rec, neo_ffi_47, neo_ffi_52, neo_ffi_57_rec)

# solution 3.
data_e <- dplyr::rowwise(data_e) %>% dplyr::mutate(neo_e = mean(c(neo_ffi_2, neo_ffi_7, neo_ffi_12_rec, neo_ffi_17, neo_ffi_22, neo_ffi_27_rec, neo_ffi_32, neo_ffi_37, neo_ffi_42_rec, neo_ffi_47, neo_ffi_52, neo_ffi_57_rec)))

# solution 4.
dplyr::filter(data_e, vpage > 24, vpsex == 0) %>% dplyr::select(vpsex, vpage, neo_e)
## # A tibble: 17 x 3
## # Rowwise: 
##    vpsex vpage   neo_e
##    <int> <int>   <dbl>
##  1     0    32  0.417 
##  2     0    28  0.583 
##  3     0    26  1     
##  4     0    27  1     
##  5     0    46  0.833 
##  6     0    26  1.08  
##  7     0    25  0.417 
##  8     0    25  0.583 
##  9     0    45 -0.167 
## 10     0    27  1.25  
## 11     0    26  0.333 
## 12     0    25  0.417 
## 13     0    28  0.0833
## 14     0    27 -0.5   
## 15     0    25  0.667 
## 16     0    29  0.667 
## 17     0    25  0.0833
# solution 5.
dplyr::group_by(data_e, vpsex) %>% dplyr::summarise(mean(c(neo_e)))
## # A tibble: 2 x 2
##   vpsex `mean(c(neo_e))`
##   <int>            <dbl>
## 1     0            0.521
## 2     1            0.456

Ausblick

dplyr hat einen weit über diese Einführung hinausgehenden Befehlsumfang. Beispielsweise gibt es eine ganze Familie von Befehlen, die Ideen aus dem Umfeld von relationalen Datenbanken auf die statistische Datenaufbereitung überträgt. Dies spielt eine Rolle beim Zusammenbauen von verschiedenen Datentabellen zu einer neuen (data merging).

Ein paar Beispiele finden sich in dplyr_advanced

Beispiele und Aufgaben

Zum Vergleich Datenmodifikation mit dem Base-System vs. Datenmodifikation mit dplyr gibt es ein vergleichendes Beispiel panas_base vs. panas_dplyr

Body Comparison (PACS) als html

References

full documentation

Befehlsreferenz mit Beispielen

Data wrangling cheatsheet

Vignetten

http://rpubs.com/justmarkham/dplyr-tutorial

http://www.r-bloggers.com/hands-on-dplyr-tutorial-for-faster-data-manipulation-in-r/

two table verbs

Hadley Wickhams Artikel zu tidy data, auch lokal.

todo

.var und .fun example

Datenmodifikation von Einzelspalten und Zurückschreiben in Tibble (Johannes’ Übungen) Erreichbar durch die Anwendung der neueren …_at() Befehle.

from

mydata2 %>% mutate(species_new = case_when(is.na(Species) ~ "missing",
                                           Species=="setosa" ~ "setosa_new",
                                           Species=="versicolor" ~ "versicolor_new",
                                           Species=="virginica" ~ "virginica_new",
                                           TRUE ~ "others"))

df1 = mydata2 %>%
  rowwise() %>% mutate(row_max= max(Sepal.Length:Petal.Width))

 
head(df1)

percentile rank http://www.datasciencemadesimple.com/calculate-percentile-quantile-n-tile-of-dataframe-in-r-using-dplyr-create-column-with-percentile-rank/

conceptual stuff on dplyr

glimpse()

todo: # using case_when

x=read.table(text="V1 V2 V3 V4
 1  1  2  3  5
 2  2  4  4  1
 3  1  4  1  1
 4  4  5  1  3
 5  5  5  5  4",
 col.names=c("V1", "V2", "V3", "V4"))
x$V5 = case_when(m$V1==1 & x$V2!=4 ~ 1,
                 x$V2==4 & x$V3!=1 ~ 2,
                 TRUE ~ 0)

dd$pho_sem2 = case_when(dd$condition == "Pho_Con" | dd$condition == "Pho_Exp" ~ "pho",
                              dd$condition == "PhoSem_Con" | dd$condition == "PhoSem_Exp" ~ "sem")
dd$exp_con2 = case_when(dd$condition == "Pho_Con" | dd$condition == "PhoSem_Con" ~ "con",
                              dd$condition == "Pho_Exp" | dd$condition == "PhoSem_Exp" ~ "exp")                

Version: 11 April, 2021 13:54