3  Daten Aufbereiten

Nachdem der Datensatz eingelesen ist, müssen wir diesen für eine quantitative Auswertung bereinigen bzw. aufarbeiten.

WarnungWas sind bereinigte Daten?
  • Die Daten liegen in einer Datentabelle (Tibble / Data Frame) vor.
  • In jeder Spalte ist genau ein Merkmal.
  • In jeder Zeile ist genau eine Beobachtung.
  • Die Datentabelle enthält kein ,,unbrauchbaren’’ Daten mehr. Dies können offensichtlich falsche Werte oder fehlende Werte sein.
  • Die Merkmale liegen im richtigen Skalenniveau vor (numerisch, Faktoren, etc.).
WichtigDownload

Download der Daten als csv-Datei: Rohdaten_TSE_unbereinigt

In diesem Kapitel sollen die wichtigsten Methoden zur Datenbereinigung noch einmal erklärt werden. Dazu betrachten wir einen Beispieldatensatz an dem wir die notwendigen Schritte durchführen wollen.

WichtigBemerkung / Übung:

Um die Arbeitstschritte besser zu verstehen, werden wir jeden Schritt einzeln ausführen und dazu immer wieder neue R-Objekte erstellen (rohdaten, rohdaten2, …). In einem realistischen Szenario würden wir all diese Schritte in eine lange Pipe schreiben, so dass man nicht viele Schritte einzeln ausführen muss. Dabei sollten wir aber aufpassen, dass jeder einzelne Schritt innerhalb der Pipe auch das erwünschte Ergebnis liefert!

Aufgabe: Schreiben Sie (während sie das Kapitel bearbeiten) ein Skript (R oder besser gleich als quarto-Dokument) in dem der obige Datensatz in einer Pipe bereinigt wird! Am Ende sollen alle Items numerisch sein!

# Laden der notwendigen Pakete

library(pacman)
p_load(tidyverse, readxl)  


# Laden des Datensatzes, der im Arbeitsverzeichnis liegt
# die ersten beiden Zeilen müssen (in diesem Beispiel!!) 
# ausgelassen werden

rohdaten <- read_excel("Rohdaten_TSE.xlsx", skip = 2)

Ausführliche Erklärungen der Funktionen filter(), arrange(), select(), rename(), mutate() sowie group_by(), summarize() und die slice_*-Funktionen sind im Skript zur Wirtschaftsmathematik, Kapitel Daten Transformieren zu finden. Wir werden Daten bereinigen, wie sie bei Umfragen oder Experimenten in der Wirtschaftpsychologie auftauchen.

3.1 Überblick über die Daten

Um sich einen Überblick über die Daten zu verschaffen gibt es einige Möglichkeiten, die verschiedene Aspekte der Daten hervorheben. Insbesondere bei großen Datensätzen ist es sinnvoll sich nicht den kompletten Datensatz anzuschauen, sondern mit Hilfe von geeigneten Funktionen die wichtigen Informationen zu erhalten.

3.1.1 glimpse()

Die Funktion glimpse() aus dem Tidyverse-Paket zeigt folgendes an:

  • Anzahl der Spalten und Zeilen,
  • Merkmalsname (Spalten),
  • Datentypen der Merkmale und
  • die ersten Ausprägungen der Merkmale.

Hier ist ein Beispiel

glimpse(rohdaten)
Rows: 133
Columns: 22
$ Fall     <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18…
$ Alter    <chr> "21", "29", "18", "23", "19", "21", "19", "20", "21", "21", "…
$ SE01_01  <chr> "trifft eher zu", "trifft teils-teils zu", "trifft überwiegen…
$ SE01_02  <chr> "trifft überhaupt nicht zu", "trifft überwiegend zu", "trifft…
$ SE01_03  <chr> "trifft überwiegend zu", "trifft teils-teils zu", "trifft ehe…
$ SE01_04  <chr> "trifft überhaupt nicht zu", "trifft überhaupt nicht zu", "tr…
$ SE01_05  <chr> "trifft überwiegend zu", "trifft überwiegend zu", "trifft übe…
$ SE01_06  <chr> "trifft eher zu", "trifft eher zu", "trifft eher zu", "trifft…
$ SE01_07  <chr> "trifft teils-teils zu", "trifft teils-teils zu", "trifft ehe…
$ TE01_01  <chr> "trifft überwiegend zu", "trifft eher zu", "trifft eher zu", …
$ TE01_02  <chr> "trifft überwiegend nicht zu", "trifft teils-teils zu", "trif…
$ TE01_03  <chr> "trifft überwiegend zu", "trifft eher zu", "trifft überwiegen…
$ TE01_04  <chr> "trifft überwiegend zu", "trifft überwiegend zu", "trifft ehe…
$ TE01_05  <chr> "trifft überwiegend nicht zu", "trifft überwiegend zu", "trif…
$ TE01_06  <chr> "trifft überwiegend zu", "trifft überwiegend zu", "trifft übe…
$ TE01_07  <chr> "trifft überhaupt nicht zu", "trifft überwiegend zu", "trifft…
$ TIME001  <dbl> 32, 15, 14, 5, 5, 13, 8, 29, 11, 10, 5, 39, 10, 7, 13, 29, 41…
$ TIME002  <dbl> 53, 38, 42, 60, 61, 92, 72, 66, 2320, 38, NA, 63, 55, 42, NA,…
$ TIME003  <dbl> 66, 283, 37, 44, 43, 74, 47, 47, 100, 36, NA, 38, 51, 40, NA,…
$ TIME004  <dbl> 18, 7, 9, 10, 10, 11, 8, 12, 9, 8, NA, 10, 10, 9, NA, 12, 11,…
$ TIME_SUM <dbl> 169, 111, 102, 119, 119, 190, 135, 154, 177, 92, 5, 150, 126,…
$ TIME_RSI <dbl> 0.69, 0.98, 1.16, 1.30, 1.30, 0.77, 1.12, 0.80, 0.67, 1.32, 2…

Was ist auffällig?

  • Das Alter ist eine Zeichenkette <chr>. Dies sollte ein numerischer Wert und damit vom Typ <dbl> (Fließkommazahl) oder int (gannzahlig) sein.
  • Auch die Antworten auf die Fragen SE01_** bzw. TE01_** sind vom Typ <chr>. Hier würde man geordnete Faktoren <ord> erwarten.

3.1.2 summary()

Die Funktion summary() erstellt für jedes Merkmal eine kleine Zusammenfassung mit den wichtigsten Kenngrößen.

summary(rohdaten)
      Fall        Alter             SE01_01            SE01_02         
 Min.   :  1   Length:133         Length:133         Length:133        
 1st Qu.: 34   Class :character   Class :character   Class :character  
 Median : 67   Mode  :character   Mode  :character   Mode  :character  
 Mean   : 67                                                           
 3rd Qu.:100                                                           
 Max.   :133                                                           
                                                                       
   SE01_03            SE01_04            SE01_05            SE01_06         
 Length:133         Length:133         Length:133         Length:133        
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
                                                                            
   SE01_07            TE01_01            TE01_02            TE01_03         
 Length:133         Length:133         Length:133         Length:133        
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
                                                                            
   TE01_04            TE01_05            TE01_06            TE01_07         
 Length:133         Length:133         Length:133         Length:133        
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
                                                                            
    TIME001          TIME002          TIME003          TIME004      
 Min.   :  2.00   Min.   :    26   Min.   : 27.00   Min.   :  6.00  
 1st Qu.:  5.00   1st Qu.:    46   1st Qu.: 42.25   1st Qu.:  9.00  
 Median : 10.00   Median :    57   Median : 50.50   Median : 11.00  
 Mean   : 16.99   Mean   :  2480   Mean   : 61.45   Mean   : 16.21  
 3rd Qu.: 19.00   3rd Qu.:    73   3rd Qu.: 66.00   3rd Qu.: 14.00  
 Max.   :198.00   Max.   :230278   Max.   :424.00   Max.   :316.00  
                  NA's   :19       NA's   :23       NA's   :23      
    TIME_SUM        TIME_RSI    
 Min.   :  2.0   Min.   :0.050  
 1st Qu.: 98.0   1st Qu.:0.770  
 Median :122.0   Median :0.990  
 Mean   :115.8   Mean   :1.107  
 3rd Qu.:150.0   3rd Qu.:1.320  
 Max.   :217.0   Max.   :3.000  
                                
Datentyp Welche Kenngrößen zeigt summary() an?
lgl Anzahl FALSE, TRUE, NA
dbl / num / int Minimum, 1. Quantil, Median, Mittelwert, 3.Quantil, Maximum
fct Häufigkeiten je Faktorstufe
ord Häufigkeiten je geordneter Faktorstufe
chr Länge, Klasse, Modus
date Minimum, 1. Quantil, Median, Mittelwert, 3.Quantil, Maximum

Was ist auffällig?

  • Das Alter ist eine Zeichenkette
  • Auch die Antworten auf die Fragen SE01_** bzw. TE01_** sind vom Typ <chr>.
  • Bei den Merkmalen, die mit TIME beginnen, gibt es viele NAs. Dies deutet darauf hin, dass die Fragebögen nicht komplett ausgefüllt wurden.

3.2 Merkmale (Spalten) auswählen: select()

Wie auch im obigen Datensatz werden von Umfragetools oft Daten exportiert, die für die Auswertung nicht wichtig sind. So benötigen wir in diesem Beispiel die zeitbezogenen Merkmale nicht. Die Spalten können über die Spaltennamen, die Spaltennummer oder mit Hilfe der Tidyselect-Funktionen ausgewählt werden. Mit Hilfe von einem Minuszeichen - können wir auch Merkmale (Spalten) gezielt weglassen.

  • starts_with()
  • ends_with()
  • contains()
  • everything()
  • num_range()
  • where()

Im obigen Beispiel könnten wir zum Beispiel wie folgt die richtigen Merkmale auswählen.

rohdaten_ohne <- rohdaten |> select(-starts_with("TIME"))
rohdaten_ohne
# A tibble: 133 × 16
    Fall Alter SE01_01   SE01_02 SE01_03 SE01_04 SE01_05 SE01_06 SE01_07 TE01_01
   <int> <chr> <chr>     <chr>   <chr>   <chr>   <chr>   <chr>   <chr>   <chr>  
 1     1 21    trifft e… trifft… trifft… trifft… trifft… trifft… trifft… trifft…
 2     2 29    trifft t… trifft… trifft… trifft… trifft… trifft… trifft… trifft…
 3     3 18    trifft ü… trifft… trifft… trifft… trifft… trifft… trifft… trifft…
 4     4 23    trifft ü… trifft… trifft… trifft… trifft… trifft… trifft… trifft…
 5     5 19    trifft ü… trifft… trifft… trifft… trifft… trifft… trifft… trifft…
 6     6 21    trifft ü… trifft… trifft… trifft… trifft… trifft… trifft… trifft…
 7     7 19    trifft ü… trifft… trifft… trifft… trifft… trifft… trifft… trifft…
 8     8 20    trifft e… trifft… trifft… trifft… trifft… trifft… trifft… trifft…
 9     9 21    trifft ü… trifft… trifft… trifft… trifft… trifft… trifft… trifft…
10    10 21    trifft e… trifft… trifft… trifft… trifft… trifft… trifft… trifft…
# ℹ 123 more rows
# ℹ 6 more variables: TE01_02 <chr>, TE01_03 <chr>, TE01_04 <chr>,
#   TE01_05 <chr>, TE01_06 <chr>, TE01_07 <chr>

Alternativ ginge auch

rohdaten |> select(1:16)

3.3 Umbenennen von Merkmalen: rename()

Um mit den Daten sinnvoll zu arbeiten ist ein guter und sinnvoller Merkmalsnamen sehr hilfreich. Es gibt einige gute Gründe für eine Umbenennung der Merkmale.

  • Sperrige bzw. ungünstige Namen aus der Umfrage (z.B. die Fragestellung an sich) sind nicht als Merkmalsnamen geeignet.
  • Ebenso sind nicht R-konforme Merkmalsnamen (die z.B. Leerzeichen enthalten, mit einer Zahl anfangen o.ä.) ungünstig.
  • Ein weiterer Grund für eine Umbenennung ist den Merkmalsnamen ,,Muster’’ zu geben, so dass man einfach mit Hilfe der Tidyselect-Funktionen auswählen kann.

Im obigen Beispiel zum Beispiel sind die beiden Konstrukte bereits durch ihren Namen getrennt (SE** bzw. TE**), allerdings sind die inversen Merkmale (in unserem Beispieldatensatz sind das SE01_02, SE01_04, TE01_02, TE01_04 und TE01_06) nicht erkennbar. Um dies zu kennzeichnen, können wir die Merkmale umbenennen:

rohdaten2 <-  rohdaten_ohne |> rename(SE01_02_invers = SE01_02, 
                                      SE01_04_invers = SE01_04, 
                                      TE01_02_invers = TE01_02,
                                      TE01_04_invers = TE01_04,
                                      TE01_06_invers = TE01_06)

Dabei steht der neue Name links vom Gleichheitszeichen, der alte Name des Merkmals rechts davon. Sind die Namen nicht R-konform, so müssen diese in Anführungszeichen gesetzt werden.

3.4 Fehlende Werte entfernen

Fehlende Werte sind R durch NA in der jeweiligen Zelle gekennzeichnet. Leere Zellen wie in Excel gibt es nicht. Es gibt verschiedene Wege wie wir mit fehlenden Werten umgehen können.

  • Manche NAs sind ggf. nicht weiter tragisch: hat der Teilnehmer beispielsweise nicht alle soziographischen Fragen beantwortet, so ist das (ja nach Fragestellung) vertretbar, und die Beobachtung kann ggf. behalten werden.
  • Hat ein Teilnehmer nicht alle Testfragen beantwortet, so sollte diese Beobachtung komplett entfernt werden, da sie für die Auswertung unbrauchbar ist.

3.4.1 Die Funktion is.na()

Mit der Funktion is.na() können wir testen, ob eine Ausprägung eines R-Objekts NA ist. Das Resultat ist ein logischer Vektor.

is.na(c(1,2,NA,4,NA))
[1] FALSE FALSE  TRUE FALSE  TRUE

3.4.2 drop_na(data, ...)

Mit der Funktion drop_na() können Beobachtung entfernt werden, die NAs enthalten. Wenn wir der Funktion kein weiteres Argument (außer den Daten) übergeben, so werden alle Beobachtungen entfernt, die NAs enthalten. Wir können der Funktion aber auch Merkmale (Name der Spalten) übergeben, und nur Beobachtungen, die in diesen Merkmalen NAs enthalten, werden entfernt. Die Merkmale können mit den Tidyselect Funktionen ausgewählt werden.

In unserem Beispiel wollen wir nur die NAs aus den Antworten entfernen, NAs in anderen Merkmalen wie Fall oder Alter können beibehalten werden.

(rohdaten3 <- rohdaten2 |> drop_na(starts_with("SE0"), starts_with("TE0")))
# A tibble: 110 × 16
    Fall Alter SE01_01     SE01_02_invers SE01_03 SE01_04_invers SE01_05 SE01_06
   <int> <chr> <chr>       <chr>          <chr>   <chr>          <chr>   <chr>  
 1     1 21    trifft ehe… trifft überha… trifft… trifft überha… trifft… trifft…
 2     2 29    trifft tei… trifft überwi… trifft… trifft überha… trifft… trifft…
 3     3 18    trifft übe… trifft überwi… trifft… trifft überwi… trifft… trifft…
 4     4 23    trifft übe… trifft überha… trifft… trifft überha… trifft… trifft…
 5     5 19    trifft übe… trifft überha… trifft… trifft überha… trifft… trifft…
 6     6 21    trifft übe… trifft überha… trifft… trifft überha… trifft… trifft…
 7     7 19    trifft übe… trifft überha… trifft… trifft überha… trifft… trifft…
 8     8 20    trifft ehe… trifft überwi… trifft… trifft überha… trifft… trifft…
 9     9 21    trifft übe… trifft überha… trifft… trifft überha… trifft… trifft…
10    10 21    trifft ehe… trifft eher zu trifft… trifft überwi… trifft… trifft…
# ℹ 100 more rows
# ℹ 8 more variables: SE01_07 <chr>, TE01_01 <chr>, TE01_02_invers <chr>,
#   TE01_03 <chr>, TE01_04_invers <chr>, TE01_05 <chr>, TE01_06_invers <chr>,
#   TE01_07 <chr>

3.4.3 filter(.data, ...) bzw. filter_out(.data, ...)

3.4.4 Das Argument rm.na=

Viele Funktionen, die Kenngrößen berechnen, wie das arithmetische Mittel mean(), der Median median(), die Summe sum(), Standardabweichung sd() und Varianz var() oder die Quantile quantile() haben jeweils das Argument na.rm=. Setzen wir das Argument TRUE, so werden die NAs bei der Berechnung der Kenngrößen ignoriert. Ansonsten ist das Ergebnis NA.

3.5 Umkodieren von Daten

Wir wollen die Antworten zu den Fragen noch umkodieren. Dazu nutzen wir die Funktionen mutate() und across(). Innerhalb der Funktion across() gibt das erste Argument an, welche Spalten geändert werden sollen. Im zweiten Argument steht eine Funktion, die genau ein Argument haben darf. Diese Funktion ändert in unserem Fall die Merkmalsausprägung. Bei einer Fallunterscheidung nutzt man die Funktioen ifelse() falls es nur zwei Möglichkeiten gibt, oder case_when(), wenn es mehrere Möglichkeiten gibt.

rohdaten4 <- rohdaten3 |> mutate(
                           across(c(starts_with(c("SE0", "TE0"))), 
                                  \(x) case_when(x == "trifft überhaupt nicht zu" ~ 0, 
                                                 x == "trifft überwiegend nicht zu" ~ 1,
                                                 x == "trifft teils-teils zu" ~ 2,
                                                 x == "trifft eher zu" ~ 3,
                                                 x == "trifft überwiegend zu" ~ 4)
                                 )
                                )
rohdaten4
# A tibble: 110 × 16
    Fall Alter SE01_01 SE01_02_invers SE01_03 SE01_04_invers SE01_05 SE01_06
   <int> <chr>   <dbl>          <dbl>   <dbl>          <dbl>   <dbl>   <dbl>
 1     1 21          3              0       4              0       4       3
 2     2 29          2              4       2              0       4       3
 3     3 18          1              1       3              1       4       3
 4     4 23          4              0       4              0       3       2
 5     5 19          4              0       1              0       2       3
 6     6 21          4              0       3              0       3       4
 7     7 19          4              0       3              0       3       4
 8     8 20          3              1       3              0       3       4
 9     9 21          4              0       4              0       2       3
10    10 21          3              3       3              1       2       4
# ℹ 100 more rows
# ℹ 8 more variables: SE01_07 <dbl>, TE01_01 <dbl>, TE01_02_invers <dbl>,
#   TE01_03 <dbl>, TE01_04_invers <dbl>, TE01_05 <dbl>, TE01_06_invers <dbl>,
#   TE01_07 <dbl>
summary(rohdaten4)
      Fall           Alter              SE01_01      SE01_02_invers
 Min.   :  1.00   Length:110         Min.   :0.000   Min.   :0.0   
 1st Qu.: 30.25   Class :character   1st Qu.:2.250   1st Qu.:0.0   
 Median : 60.50   Mode  :character   Median :3.000   Median :0.0   
 Mean   : 63.92                      Mean   :3.118   Mean   :0.8   
 3rd Qu.: 96.75                      3rd Qu.:4.000   3rd Qu.:1.0   
 Max.   :133.00                      Max.   :4.000   Max.   :4.0   
    SE01_03      SE01_04_invers      SE01_05         SE01_06     
 Min.   :0.000   Min.   :0.0000   Min.   :0.000   Min.   :0.000  
 1st Qu.:2.000   1st Qu.:0.0000   1st Qu.:2.000   1st Qu.:3.000  
 Median :3.000   Median :0.0000   Median :3.000   Median :3.000  
 Mean   :2.973   Mean   :0.7818   Mean   :2.855   Mean   :3.055  
 3rd Qu.:4.000   3rd Qu.:1.0000   3rd Qu.:3.000   3rd Qu.:4.000  
 Max.   :4.000   Max.   :4.0000   Max.   :4.000   Max.   :4.000  
    SE01_07         TE01_01    TE01_02_invers     TE01_03      TE01_04_invers 
 Min.   :0.000   Min.   :0.0   Min.   :0.000   Min.   :0.000   Min.   :0.000  
 1st Qu.:2.000   1st Qu.:2.0   1st Qu.:1.250   1st Qu.:1.000   1st Qu.:3.000  
 Median :3.000   Median :2.0   Median :3.000   Median :1.000   Median :3.000  
 Mean   :2.882   Mean   :2.2   Mean   :2.373   Mean   :1.655   Mean   :3.118  
 3rd Qu.:4.000   3rd Qu.:3.0   3rd Qu.:3.000   3rd Qu.:2.000   3rd Qu.:4.000  
 Max.   :4.000   Max.   :4.0   Max.   :4.000   Max.   :4.000   Max.   :4.000  
    TE01_05      TE01_06_invers     TE01_07     
 Min.   :0.000   Min.   :0.000   Min.   :0.000  
 1st Qu.:0.000   1st Qu.:3.000   1st Qu.:1.000  
 Median :1.000   Median :3.000   Median :1.000  
 Mean   :1.336   Mean   :3.109   Mean   :1.609  
 3rd Qu.:2.000   3rd Qu.:4.000   3rd Qu.:3.000  
 Max.   :4.000   Max.   :4.000   Max.   :4.000  

3.5.1 Umkodieren numerischer Daten

Nun müssen wir noch die invers kodierten Antworten umkodieren, das bedeutet, dass wir jede 0 zu einer 4 kodieren, jede 1 zu einer 3 und so weiter.

rohdaten5 <- rohdaten4 |> mutate(across(c(ends_with("invers")), 
                                 \(x) {4-x}
                                 )
                                )
rohdaten5
# A tibble: 110 × 16
    Fall Alter SE01_01 SE01_02_invers SE01_03 SE01_04_invers SE01_05 SE01_06
   <int> <chr>   <dbl>          <dbl>   <dbl>          <dbl>   <dbl>   <dbl>
 1     1 21          3              4       4              4       4       3
 2     2 29          2              0       2              4       4       3
 3     3 18          1              3       3              3       4       3
 4     4 23          4              4       4              4       3       2
 5     5 19          4              4       1              4       2       3
 6     6 21          4              4       3              4       3       4
 7     7 19          4              4       3              4       3       4
 8     8 20          3              3       3              4       3       4
 9     9 21          4              4       4              4       2       3
10    10 21          3              1       3              3       2       4
# ℹ 100 more rows
# ℹ 8 more variables: SE01_07 <dbl>, TE01_01 <dbl>, TE01_02_invers <dbl>,
#   TE01_03 <dbl>, TE01_04_invers <dbl>, TE01_05 <dbl>, TE01_06_invers <dbl>,
#   TE01_07 <dbl>

Nun muss das Merkmal Alter noch umkodiert werden. Schauen wir uns dazu mal die Ausprägungen an:

rohdaten5 |> pull(Alter) 
  [1] "21"       "29"       "18"       "23"       "19"       "21"      
  [7] "19"       "20"       "21"       "21"       "19"       "24"      
 [13] "23"       "19"       "21"       "20"       "29"       "21"      
 [19] "22"       "24"       "28"       "23"       "18"       "21"      
 [25] "24"       "20"       "19"       "18"       "18"       "23"      
 [31] "21"       "19"       "21"       "22"       "27"       "23"      
 [37] "20"       "20"       "18"       "18"       "18"       "22"      
 [43] "20"       "30"       "20"       "21"       "23"       "20"      
 [49] "18"       "18"       "25"       "18"       "18"       "26"      
 [55] "19"       "23"       "29"       "19"       "18"       "23"      
 [61] "21"       "22"       "19"       "30"       "20"       "23"      
 [67] "20"       "21"       "18"       "24"       "25"       "23"      
 [73] "23"       "20"       "24"       "23"       "22"       "22"      
 [79] "21"       "19"       "27"       "19"       "19"       "22"      
 [85] "20"       "18"       "23"       "28"       "45 Jahre" "23"      
 [91] "22"       "20"       "19"       "24"       "21"       "20"      
 [97] "19"       "21"       "20"       "20"       "18"       "28"      
[103] "25"       "29"       "20"       "22"       "23"       "18"      
[109] "18"       "19"      

oder besser noch jede vorkommende Ausprägung, das heißt sollten Ausprägungen mehrfach vorkommen, so werden diese nur einmal aufgeführt:

rohdaten5 |> pull(Alter) |> unique()
 [1] "21"       "29"       "18"       "23"       "19"       "20"      
 [7] "24"       "22"       "28"       "27"       "30"       "25"      
[13] "26"       "45 Jahre"

Hier sehen wir sofort, dass der letzte Eintrag falsch ist. mit Hilfe von mutate() können wir diesen Eintrag (bzw. diese Einträge) leicht ändern.

rohdaten6 <- rohdaten5 |> mutate(across(Alter, \(x) {ifelse(x == "45 Jahre", 45, x)})) |> 
                          mutate(across(Alter, as.numeric))

Im ersten mutate() wird der Eintrag ,,45 Jahre’’ zu einer ,,45’’ geändert (alle anderen bleiben wie sie sind) und im zweiten mutate() wird das Alter dann zu einem numerischen Vektor transformiert.

summary(rohdaten6)
      Fall            Alter          SE01_01      SE01_02_invers
 Min.   :  1.00   Min.   :18.00   Min.   :0.000   Min.   :0.0   
 1st Qu.: 30.25   1st Qu.:19.00   1st Qu.:2.250   1st Qu.:3.0   
 Median : 60.50   Median :21.00   Median :3.000   Median :4.0   
 Mean   : 63.92   Mean   :21.75   Mean   :3.118   Mean   :3.2   
 3rd Qu.: 96.75   3rd Qu.:23.00   3rd Qu.:4.000   3rd Qu.:4.0   
 Max.   :133.00   Max.   :45.00   Max.   :4.000   Max.   :4.0   
    SE01_03      SE01_04_invers     SE01_05         SE01_06     
 Min.   :0.000   Min.   :0.000   Min.   :0.000   Min.   :0.000  
 1st Qu.:2.000   1st Qu.:3.000   1st Qu.:2.000   1st Qu.:3.000  
 Median :3.000   Median :4.000   Median :3.000   Median :3.000  
 Mean   :2.973   Mean   :3.218   Mean   :2.855   Mean   :3.055  
 3rd Qu.:4.000   3rd Qu.:4.000   3rd Qu.:3.000   3rd Qu.:4.000  
 Max.   :4.000   Max.   :4.000   Max.   :4.000   Max.   :4.000  
    SE01_07         TE01_01    TE01_02_invers     TE01_03      TE01_04_invers  
 Min.   :0.000   Min.   :0.0   Min.   :0.000   Min.   :0.000   Min.   :0.0000  
 1st Qu.:2.000   1st Qu.:2.0   1st Qu.:1.000   1st Qu.:1.000   1st Qu.:0.0000  
 Median :3.000   Median :2.0   Median :1.000   Median :1.000   Median :1.0000  
 Mean   :2.882   Mean   :2.2   Mean   :1.627   Mean   :1.655   Mean   :0.8818  
 3rd Qu.:4.000   3rd Qu.:3.0   3rd Qu.:2.750   3rd Qu.:2.000   3rd Qu.:1.0000  
 Max.   :4.000   Max.   :4.0   Max.   :4.000   Max.   :4.000   Max.   :4.0000  
    TE01_05      TE01_06_invers      TE01_07     
 Min.   :0.000   Min.   :0.0000   Min.   :0.000  
 1st Qu.:0.000   1st Qu.:0.0000   1st Qu.:1.000  
 Median :1.000   Median :1.0000   Median :1.000  
 Mean   :1.336   Mean   :0.8909   Mean   :1.609  
 3rd Qu.:2.000   3rd Qu.:1.0000   3rd Qu.:3.000  
 Max.   :4.000   Max.   :4.0000   Max.   :4.000  
HinweisAufgabe

Im Video UMFRAGEN AUSWERTEN MIT R | Teil 3: Daten einlesen, aufbereiten und bereinigen wird ein falscher Eintrag in einer Spalte geändert. Der Code im Video dazu lautet

daten |> mutate(Alter = case_match(Alter, "45 Jahre" ~ "45", .default = Alter))

Der Vorteil dieser Schreibweise ist, dass im case_match() mehrere Änderungen gleichzeitig gemacht werden können, was im obigen Beipsiel nicht geht. Allerdings ist die Syntax ein wenig umständlich, da dreimal der Merkmalsname benutzt wird. Um das gleiche zu erreichen kann man mit across() und replace_when() arbeiten. Geben Sie die Code-Zeile dazu an.

rohdaten5 |> mutate(across(Alter, \(x) replace_when(x, x == "45 Jahre" ~ "45")))
# A tibble: 110 × 16
    Fall Alter SE01_01 SE01_02_invers SE01_03 SE01_04_invers SE01_05 SE01_06
   <int> <chr>   <dbl>          <dbl>   <dbl>          <dbl>   <dbl>   <dbl>
 1     1 21          3              4       4              4       4       3
 2     2 29          2              0       2              4       4       3
 3     3 18          1              3       3              3       4       3
 4     4 23          4              4       4              4       3       2
 5     5 19          4              4       1              4       2       3
 6     6 21          4              4       3              4       3       4
 7     7 19          4              4       3              4       3       4
 8     8 20          3              3       3              4       3       4
 9     9 21          4              4       4              4       2       3
10    10 21          3              1       3              3       2       4
# ℹ 100 more rows
# ℹ 8 more variables: SE01_07 <dbl>, TE01_01 <dbl>, TE01_02_invers <dbl>,
#   TE01_03 <dbl>, TE01_04_invers <dbl>, TE01_05 <dbl>, TE01_06_invers <dbl>,
#   TE01_07 <dbl>

3.5.2 Umkodieren der Daten in geordnete Faktoren

Statt die Ausprägungen in die Zahlen von 0 bis 4 zu kodieren, könnten wir auch (je nach Anwendung) die Antworten in einen geordneten Faktor kodieren. Die Sysntax ist sehr ähnlich, lediglich die Funktion innerhalb von across() ist anders.

rohdaten4a <- rohdaten3 |> mutate(
                           across(c(starts_with(c("SE0", "TE0"))), 
                                  \(x) ordered(x, levels = c(
                                         "trifft überhaupt nicht zu", 
                                         "trifft überwiegend nicht zu",
                                         "trifft teils-teils zu",
                                         "trifft eher zu",
                                         "trifft überwiegend zu")
                                 )
                                ))

summary(rohdaten4a)
      Fall           Alter                                  SE01_01  
 Min.   :  1.00   Length:110         trifft überhaupt nicht zu  : 3  
 1st Qu.: 30.25   Class :character   trifft überwiegend nicht zu: 6  
 Median : 60.50   Mode  :character   trifft teils-teils zu      :19  
 Mean   : 63.92                      trifft eher zu             :29  
 3rd Qu.: 96.75                      trifft überwiegend zu      :53  
 Max.   :133.00                                                      
                     SE01_02_invers                        SE01_03  
 trifft überhaupt nicht zu  :59     trifft überhaupt nicht zu  : 5  
 trifft überwiegend nicht zu:30     trifft überwiegend nicht zu: 8  
 trifft teils-teils zu      :10     trifft teils-teils zu      :16  
 trifft eher zu             : 6     trifft eher zu             :37  
 trifft überwiegend zu      : 5     trifft überwiegend zu      :44  
                                                                    
                     SE01_04_invers                        SE01_05  
 trifft überhaupt nicht zu  :61     trifft überhaupt nicht zu  : 1  
 trifft überwiegend nicht zu:26     trifft überwiegend nicht zu: 6  
 trifft teils-teils zu      :12     trifft teils-teils zu      :28  
 trifft eher zu             : 8     trifft eher zu             :48  
 trifft überwiegend zu      : 3     trifft überwiegend zu      :27  
                                                                    
                        SE01_06                          SE01_07  
 trifft überhaupt nicht zu  : 2   trifft überhaupt nicht zu  : 5  
 trifft überwiegend nicht zu: 8   trifft überwiegend nicht zu:10  
 trifft teils-teils zu      :12   trifft teils-teils zu      :17  
 trifft eher zu             :48   trifft eher zu             :39  
 trifft überwiegend zu      :40   trifft überwiegend zu      :39  
                                                                  
                        TE01_01                       TE01_02_invers
 trifft überhaupt nicht zu  : 3   trifft überhaupt nicht zu  : 8    
 trifft überwiegend nicht zu:18   trifft überwiegend nicht zu:20    
 trifft teils-teils zu      :52   trifft teils-teils zu      :23    
 trifft eher zu             :28   trifft eher zu             :41    
 trifft überwiegend zu      : 9   trifft überwiegend zu      :18    
                                                                    
                        TE01_03                       TE01_04_invers
 trifft überhaupt nicht zu  :11   trifft überhaupt nicht zu  : 1    
 trifft überwiegend nicht zu:46   trifft überwiegend nicht zu: 4    
 trifft teils-teils zu      :27   trifft teils-teils zu      : 9    
 trifft eher zu             :22   trifft eher zu             :63    
 trifft überwiegend zu      : 4   trifft überwiegend zu      :33    
                                                                    
                        TE01_05                       TE01_06_invers
 trifft überhaupt nicht zu  :34   trifft überhaupt nicht zu  : 1    
 trifft überwiegend nicht zu:38   trifft überwiegend nicht zu: 4    
 trifft teils-teils zu      :15   trifft teils-teils zu      :15    
 trifft eher zu             :13   trifft eher zu             :52    
 trifft überwiegend zu      :10   trifft überwiegend zu      :38    
                                                                    
                        TE01_07  
 trifft überhaupt nicht zu  :21  
 trifft überwiegend nicht zu:38  
 trifft teils-teils zu      :21  
 trifft eher zu             :23  
 trifft überwiegend zu      : 7  
                                 

Die Funktion ordered() (oder alternativ factor(ordered=TRUE))

3.6 Merkmale erstellen

Ebenfalls mit der Funktion mutate() können wir neue Merkmale erstellen. Für die Auswertung benötigen wir jede Beobachtung die Summe der

rohdaten7 <- rohdaten6 |> rowwise() |> 
                          mutate(Summe_SE = sum(c_across(starts_with("SE"))), 
                                 Summe_TE = sum(c_across(starts_with("TE"))),
                                 .before = SE01_01) |>    
                          ungroup()

Bemerkungen

  • Mit dem Argument .before= (oder .after=) kann man wählen an welcher Stelle die neuen Merkmale stehen sollen. Im Beispiel wurde die Spalte so gewählt, dass wir sie hier sehen können.
  • Innerhalb der Funktion c_across() stehen die Merkmalsnamen, über die summiert werden sollen.
  • Die Funktion ungroup() beendet rowwise()
HinweisAufgabe

Erstellen Sie vier neue Spalten: MW_SE, MW_TE, SD_SE, SD_TE die jeweils das arithmetische Mittel bzw. die Standardabweichung der Konstrukte SE bzw. TE enthalten.