6  Datenaufbereitung

In dem Ordner, in dem diese Datei liegt, muss auch eine “_common.R” liegen, damit das Ganze funktioniert. Die haben Sie aber sicher schon und da auch angepasst. Darum nehmen Sie am besten die oder fragen Sie andernfalls im Forum nochmal nach.

Wer sich in die Datenaufbereitung (Data transformation) etwas tiefer einarbeiten will (oder weil er:sie muss), empfehle ich das gut lesbare und klaren Beispielen und schönem Code versehene «Data transformation» aus «r4ds».

Laden Sie sich als erstes die Datei Datenaufbereitungsvorlage.qmd herunter. Darin finden Sie Codebeispiele, die Sie kopieren können und so ändern, dass Sie auf Ihre Datensätze und zu Ihren Variablen passen. Wenn Sie erstmal ausprobieren wollen, ob das alles geht, können Sie sich noch die Beispieldaten “data” herunterladen und im selben Ordner ablegen, wo auch die Datenaufberietungsvorlage.qmd liegt. Dort müssen Sie sie dann noch entpacken (klar).

Erstmal ein paar Daten laden. Damit das funktioniert, muss in einem Ordner mit der Bezeichnung “data” im aktuellen Verzeichnis die DATEN_BEF.RDS liegen (funktioniert mit dem gezippten Beispieldatenornder “data.zip” von oben). Sie können Ihre Datensätze oder die Bezeichnung hier in den R-Codes ändern. Wenn Sie den Dateinamen Ihrer Datei umbenennen, ist die Chance grösser, dass auch der Code weiter hinten ganz gut funktioniert.

# Es werden Daten geladen, die im Unterordner "data" liegen. RDS-ist ein gutes R-Daten-Format
DATEN_BF <- readRDS("data/DATEN_BEF.RDS") 
saveRDS(DATEN_BF, file = "data/DATEN_BEF.RDS") # speichern immer nach Laden, weil sonst schnell Fehler entstehen

DATEN_IA <- readRDS("data/IAuBEF.RDS") 
saveRDS(DATEN_IA, file = "data/IAuBEF.RDS")

6.1 Leere Fälle löschen (TF E)

Hier gehe ich davon aus, dass ein Interview erfolgreich beendet wurde, wenn der:die Interviewer:in am Ende etwas zum Verständnis des Interviews eingegeben hat.

# Nehmen Sie eine Variable, die eigentlich für jede befragte Person erfasst sein sollte, wie die BEGRUESS, wo eigentlich nur abgehakt wird, dass das Interview geführt werden kann
DATEN_BF <- DATEN_BF |> 
  filter(!is.na(BEGRUESS))

## Hier löschen wir ein paar Variablen, die nur technisch sind und nicht gebraucht werden. 
DATEN_BF <- DATEN_BF |> 
  select(-any_of(c('SERIAL', 'REF', 'QUESTNNR', 'MODE'))) # -any_of() sorgt dafür, dass er keinen Fehler produziert, wenn die Dateien schon gelöscht sind.

6.2 Variablen umbenennen und löschen

Wenn Sie den einfachen Befehl “select” nehmen, dann werden die Variablen behalten, die Sie aufführen. Wenn Sie ein Minus davor schreiben, werden die Variablen gelöscht, die Sie aufführen. Häufig führt das später zu Fehlermeldungen, weil bei mehrfacher Ausführung gelöschte Variablen natürlich nicht mehr im Datensatz gefunden werden. Um diesen Fehlermeldungen aus dem Weg zu gehen, können Sie “any_of” verwenden. Dann prüft R, ob eine der aufgeführten Variablen im Datensatz sind und löscht diese. Wenn die Variablen nicht im Datensatz sind, dann macht R nichts weiter (meldet auch keinen Fehler und stoppt Ihren Durchlauf nicht.). Seien Sie damit also mir Vorsicht. Beim Befehl “rename” können Sie das auch machen. Mit “any_of” werden nur die Variablen umbenannt, die auch wirklich da sind. Manchmal kommt das bei jedem Durchlauf vor, weil zB bei join-Befehlen immer nochmal ein Datensatz gematcht wird und wie im Beispiel vorhandene Variablen wie “Nenn1” umbenannt werden in “Nenn1.x” und Nenn1.y” Wenn Sie jetzt die mit “.y” löschen und die mit “.x” umbenennen, dann haben Sie das Problem auch glöst, wenn Ihnen nicht ganz klar ist, warum die immer wieder auftauchen. Für’s Erste ist das also auch eine Lösung eines Problems. 🙃

# Manchmal macht es Sinn, von einer Variable eine Kopie mit besser lesbarem Namen anzulegen, wie hier:

DATEN_BF <- DATEN_BF |> 
  mutate(Alter = ALTER, 
        Geschlecht = GESCHL)

## verschiebe (relocat) die Variable GESCHL hinter die SD02. 
DATEN_BF <- DATEN_BF |> 
  relocate(Geschlecht, .after = GESCHL)

# So können Sie Variablen löschen. Durch das -any_of gibt es keine Fehler, wenn R die Variablen nicht findet
DATEN_BF <- DATEN_BF |> 
  select(-any_of(c("Nenn1.y", "Nenn2.y", "Nann3.y")))

# So nenne Sie Variablen um, wenn es sie gibt (vorne die neue Bezeichnung).
DATEN_BF <- DATEN_BF |> 
  rename(any_of(c("Nenn1" = "Nenn1.x", "Nenn2" = "Nenn2.x", "Nenn3" = "Nenn3.x"))) 

6.3 Label für Variablen und Ausprägungen (teils TF E)

Wenn Sie messen, dann stehen am Ende Zahlen für das was Sie gemessen, also zB erfragt haben. Zum Beispiel steht dann eine 1 für “trifft nicht zu” und 5 für “trifft vollkommen zu”. In Ihren Auswertungen müssen Sie aber wieder die verbalen Entsprechungen nutze, statt nur Tabellen oder Grafiken zu haben, wo nur Zahlen ausgewiesen werden (Sie können das noch verbinden, aber Ihre Leser:innen nicht). In anderen Programmen (wie SPSS) ist es daher üblich, dass die gemessenen Zahlen mit verbalen Labeln versehen werden. In Base-R geht das nicht so toll. Da müssen Sie mit “factors” arbeiten, wo also statt der Zahlen die verbalen Entsprechungen verwendet werden. Mühsam an den Faktoren ist, dass man mit ihnen wieder nicht mehr rechnen kann, also z.B. weder einen Mittelwert ausgeben noch eine Korrelation. Da hilft das Paket sjmisc weiter. Mit dem können Sie den Zahlenwerten Ihrer Variablen ihre Merkmalsausprägungen als Label zuordnen. Das geht mit set_label(labels = c(“tzrifft nicht zu” = 1, “trifft voll zu” = 5)):

# So können Label vergeben werden

DATEN_BF |> sjmisc::frq(GESCHL)
## GESCHL <numeric> 
## # total N=204 valid N=204 mean=1.49 sd=0.50
## 
## Value |   N | Raw % | Valid % | Cum. %
## --------------------------------------
##     1 | 104 | 50.98 |   50.98 |  50.98
##     2 | 100 | 49.02 |   49.02 | 100.00
##  <NA> |   0 |  0.00 |    <NA> |   <NA>

# Hier wird das Variablenlabel vergeben

DATEN_BF <- DATEN_BF |> 
  sjlabelled::var_labels(GESCHL = "Geschlecht") 

# Hier werden für die einzelnen Ausprägungen die Label vergeben
DATEN_BF <- DATEN_BF |> 
  sjlabelled::set_labels(GESCHL, labels = c("mänlich" = 1, "weiblich" = 2, "divers" = 3, "k.A." = NA))

# Mit dem Befehl für Häufigkeitstabellen (frq für frequencies) kann die Labelei schnell angesehen werden:

DATEN_BF |> 
  sjmisc::frq(GESCHL)
## Geschlecht (GESCHL) <numeric> 
## # total N=204 valid N=204 mean=1.49 sd=0.50
## 
## Value |    Label |   N | Raw % | Valid % | Cum. %
## -------------------------------------------------
##     1 |  mänlich | 104 | 50.98 |   50.98 |  50.98
##     2 | weiblich | 100 | 49.02 |   49.02 | 100.00
##     3 |   divers |   0 |  0.00 |    0.00 | 100.00
##  <NA> |     <NA> |   0 |  0.00 |    <NA> |   <NA>

## Hier werden für einige Variablen Label vergeben, die zusammengehören und später als Auswertung für Mehrfrachantworten verarbeitet werden

# Ersteinmal die Variablen angucken. Die Variablen gehen von NACHRICHT_TITEL1 in einer Reihe bis M112_23 (wurde nicht umbenannt in SosciSurvey)
DATEN_BF |> 
  select(NACHRICHT_TITEL1:M112_23) |> # Nur die interessierenden Variablen selektieren
  ufs::multiResponse() |> # Mehrfachantworten ansehen
  arrange(desc(Frequency)) |> # Sortieren nach Häufigkeit
  kableExtra::kable() |> # besser lesbare Tabelle daraus machen
  kableExtra::kable_styling() # Styling
## Registered S3 method overwritten by 'webshot':
##   method        from    
##   print.webshot webshot2
Option Frequency Percentage of responses Percentage of (203) cases
Total 616 100.0000000 303.4482759
NACHRICHT_TITEL3 107 17.3701299 52.7093596
NACHRICHT_TITEL6 79 12.8246753 38.9162562
M112_23 76 12.3376623 37.4384236
NACHRICHT_TITEL1 67 10.8766234 33.0049261
M112_20 66 10.7142857 32.5123153
NACHRICHT_TITEL2 57 9.2532468 28.0788177
NACHRICHT_TITEL4 43 6.9805195 21.1822660
NACHRICHT_TITEL5 32 5.1948052 15.7635468
M112_22 19 3.0844156 9.3596059
M112_21 17 2.7597403 8.3743842
NACHRICHT_TITEL8 10 1.6233766 4.9261084
NACHRICHT_TITEL7 8 1.2987013 3.9408867
NACHRICHT_TITEL15 7 1.1363636 3.4482759
NACHRICHT_TITEL19 7 1.1363636 3.4482759
NACHRICHT_TITEL9 5 0.8116883 2.4630542
NACHRICHT_TITEL10 4 0.6493506 1.9704433
NACHRICHT_TITEL16 4 0.6493506 1.9704433
NACHRICHT_TITEL11 2 0.3246753 0.9852217
NACHRICHT_TITEL13 2 0.3246753 0.9852217
NACHRICHT_TITEL14 2 0.3246753 0.9852217
NACHRICHT_TITEL12 1 0.1623377 0.4926108
NACHRICHT_TITEL18 1 0.1623377 0.4926108
NACHRICHT_TITEL17 0 0.0000000 0.0000000


# Mit set_variable_labels werden hier die Variablenlabel vergeben
DATEN_BF <- DATEN_BF |>
  sjlabelled::var_labels(NACHRICHT_TITEL1 = "NZZ", 
                      NACHRICHT_TITEL2 = "TA", 
                      NACHRICHT_TITEL3 = "20 Minuten",
                      NACHRICHT_TITEL4 = "Blick", 
                      NACHRICHT_TITEL5 = "Watson",
                      NACHRICHT_TITEL6 = "SRF News", 
                      M112_20 = "Social Media",
                      M112_21 = "Google News",
                      M112_23 = "anderes"
                      )

# Hier mal für den Nachrichtenfaktor "Kontroverse" aus der Inhaltsanalyse

DATEN_IA <- DATEN_IA |> 
 sjlabelled::var_labels(KNTR = "Kontroverse") |> 
 sjlabelled::set_labels(KNTR, labels = c("keine" = 0, "gering" = 1, "stark" = 2, "k.A." = NA))

6.4 Befragungstag aus dem Datum

Mit diesem Befehl kann der Befragungstag aus der Datumsvariable erzeugt werden, die von SosciSurvey automatisch erzeugt wird. Wenn Sie den Tag schon als solchen haben, brauchen Sie das natürlich nicht.

DATEN_BF <- DATEN_BF |> 
  mutate(Befrag_Tag = day(STARTED)) |> # mit day wird aus der Datumsvariable der Tag rausgezogen
  relocate(Befrag_Tag, .after = STARTED) # Hiermit wird die Variable für den Befragungsstart an den Anfang gepackt

DATEN_BF |> sjmisc::frq(Befrag_Tag)
## Befrag_Tag <integer> 
## # total N=204 valid N=204 mean=27.76 sd=0.80
## 
## Value |  N | Raw % | Valid % | Cum. %
## -------------------------------------
##    26 |  1 |  0.49 |    0.49 |   0.49
##    27 | 93 | 45.59 |   45.59 |  46.08
##    28 | 64 | 31.37 |   31.37 |  77.45
##    29 | 46 | 22.55 |   22.55 | 100.00
##  <NA> |  0 |  0.00 |    <NA> |   <NA>

6.5 Umkodieren

6.5.1 Werte wechseln

Umkodieren bedeutet, dass Ausprägungen (also Werte) in einer Variablen verändert werden oder zu anderen Werten in einer neuen Variable werden. Typische Umkodierungen sind Veränderungen der Codes (also zB wenn man eine Skala umdrehen möchte von 1 bis 5 auf 5 bis 1) und Zusammenfassungen von Codes, also zB 1 und 2 werden neu in 1 zusammengefasst 3 wird die neue 2 und 4 sowie 5 werden als neue 3 kodiert. Dann hat man jeweils zwei Abstufungen in den Ausprägungen zu jeweils einer zusammengefasst.

DATEN_BF <- DATEN_BF  |> 
# rename(Bildung = BILDUNG) # funktioniert nur einmal, weil beim zweiten Ausführen R BILDUNG nicht mehr findet (es ist ja umbenannt) 
  mutate(Bildung = BILDUNG) # funktioniert immer

## Hier machen wir aus den beiden tieferen Bildungsgruppen eine einzelne Gruppe. In den Klammern kann man die Value Label gleich mit vergeben:

DATEN_BF  |> 
 sjmisc::frq(Bildung) # erstmal angucken
## Bildung <numeric> 
## # total N=204 valid N=203 mean=2.63 sd=1.12
## 
## Value |  N | Raw % | Valid % | Cum. %
## -------------------------------------
##     1 | 33 | 16.18 |   16.26 |  16.26
##     2 | 69 | 33.82 |   33.99 |  50.25
##     3 | 51 | 25.00 |   25.12 |  75.37
##     4 | 40 | 19.61 |   19.70 |  95.07
##     5 | 10 |  4.90 |    4.93 | 100.00
##  <NA> |  1 |  0.49 |    <NA> |   <NA>

# Erstelle mit mutate eine neue Variable Bildung_gr, die eine rekodierte Bildung (zB 1 und 2 werden)
DATEN_BF <- DATEN_BF |> 
 mutate(Bildung_gr = sjmisc::rec(Bildung, rec = "1:2 = 1; 3 = 2; 4 = 3; 5 = 4"))  # die offenen müssen noch kodiert werden

DATEN_BF <- DATEN_BF |> 
  sjlabelled::set_labels(Bildung_gr, labels = c("tief" = 1, "mittel" = 2, "hoch" = 3, "noch kodieren" = 4), force.labels = TRUE) |> 
  sjlabelled::var_labels(Bildung_gr = "Bildung (gruppiert)")  # hier das Variablenlabel

DATEN_BF |> 
    sjmisc::frq(Bildung_gr)
## Bildung (gruppiert) (Bildung_gr) <numeric> 
## # total N=204 valid N=203 mean=1.79 sd=0.93
## 
## Value |         Label |   N | Raw % | Valid % | Cum. %
## ------------------------------------------------------
##     1 |          tief | 102 | 50.00 |   50.25 |  50.25
##     2 |        mittel |  51 | 25.00 |   25.12 |  75.37
##     3 |          hoch |  40 | 19.61 |   19.70 |  95.07
##     4 | noch kodieren |  10 |  4.90 |    4.93 | 100.00
##  <NA> |          <NA> |   1 |  0.49 |    <NA> |   <NA>

6.5.2 Mehrere auf einmal umkodieren

Das geht super mit across! Der Befehl macht zwar alle ein bisschen komplizierter, aber er spart sehr viele Zeilen Code. Das bringt vor allem viel, wenn Sie dann doch mal etwas ändern wollen und dann nicht 23 Zeilen für 23 Variablen neu machen müssen, sondern nur eine. Das Grundschema ist immer across(Variablenliste, ~ funktion(.x)), wobei die Tilde (~) immer andeuten, dass gleich eine Funktion kommt, und das .x immer da steht, wo man im einfacheren Fall die eine Variable reingeschrieben hätte. Die Variablenliste können tatsächlich Listen von Variablen sein mit einem Doppelpunkte dazwischen wie zB V1:V7, wobei dann derselbe Befehl für alle Variablen von V1 bis V7 in der Reihenfolge des Datensatzes ausgeführt wird. Im Folgenden ist das für die Funktion ~ sjmisc::rec(.x) angewendet worden. Schauen Sie doch mal, wie schön das ist! 😃

DATEN_BF |> 
  sjmisc::frq(HAUFIGKEIT_01:HAUFIGKEIT_05)
## HAUFIGKEIT_01 <numeric> 
## # total N=204 valid N=203 mean=4.20 sd=0.80
## 
## Value |  N | Raw % | Valid % | Cum. %
## -------------------------------------
##     2 |  4 |  1.96 |    1.97 |   1.97
##     3 | 36 | 17.65 |   17.73 |  19.70
##     4 | 79 | 38.73 |   38.92 |  58.62
##     5 | 84 | 41.18 |   41.38 | 100.00
##  <NA> |  1 |  0.49 |    <NA> |   <NA>
## 
## HAUFIGKEIT_02 <numeric> 
## # total N=204 valid N=203 mean=2.80 sd=0.86
## 
## Value |   N | Raw % | Valid % | Cum. %
## --------------------------------------
##    -1 |   3 |  1.47 |    1.48 |   1.48
##     1 |   5 |  2.45 |    2.46 |   3.94
##     2 |  51 | 25.00 |   25.12 |  29.06
##     3 | 116 | 56.86 |   57.14 |  86.21
##     4 |  24 | 11.76 |   11.82 |  98.03
##     5 |   4 |  1.96 |    1.97 | 100.00
##  <NA> |   1 |  0.49 |    <NA> |   <NA>
## 
## HAUFIGKEIT_03 <numeric> 
## # total N=204 valid N=203 mean=2.24 sd=1.68
## 
## Value |  N | Raw % | Valid % | Cum. %
## -------------------------------------
##    -2 |  6 |  2.94 |    2.96 |   2.96
##    -1 | 24 | 11.76 |   11.82 |  14.78
##     1 | 11 |  5.39 |    5.42 |  20.20
##     2 | 50 | 24.51 |   24.63 |  44.83
##     3 | 79 | 38.73 |   38.92 |  83.74
##     4 | 23 | 11.27 |   11.33 |  95.07
##     5 | 10 |  4.90 |    4.93 | 100.00
##  <NA> |  1 |  0.49 |    <NA> |   <NA>
## 
## HAUFIGKEIT_04 <numeric> 
## # total N=204 valid N=203 mean=2.54 sd=1.25
## 
## Value |  N | Raw % | Valid % | Cum. %
## -------------------------------------
##    -2 |  2 |  0.98 |    0.99 |   0.99
##    -1 |  1 |  0.49 |    0.49 |   1.48
##     1 | 38 | 18.63 |   18.72 |  20.20
##     2 | 58 | 28.43 |   28.57 |  48.77
##     3 | 62 | 30.39 |   30.54 |  79.31
##     4 | 29 | 14.22 |   14.29 |  93.60
##     5 | 13 |  6.37 |    6.40 | 100.00
##  <NA> |  1 |  0.49 |    <NA> |   <NA>
## 
## HAUFIGKEIT_05 <numeric> 
## # total N=204 valid N=203 mean=2.29 sd=1.14
## 
## Value |  N | Raw % | Valid % | Cum. %
## -------------------------------------
##    -2 |  2 |  0.98 |    0.99 |   0.99
##    -1 |  5 |  2.45 |    2.46 |   3.45
##     1 | 29 | 14.22 |   14.29 |  17.73
##     2 | 81 | 39.71 |   39.90 |  57.64
##     3 | 67 | 32.84 |   33.00 |  90.64
##     4 | 13 |  6.37 |    6.40 |  97.04
##     5 |  6 |  2.94 |    2.96 | 100.00
##  <NA> |  1 |  0.49 |    <NA> |   <NA>

# mutiere über (across) die ganze Liste der Variablen von:bis, als Funktion (~) rec(.x) wobei .x für die Variablen der Liste steht
DATEN_BF <- DATEN_BF |> 
  mutate(across(HAUFIGKEIT_01:HAUFIGKEIT_05, 
                ~ sjmisc::rec(.x, rec = "1 = -2 [viel zu wenig]; 2 = -1 [zu wenig]; 3 = 0 [richtig]; 4 = 1  [zu viel]; 5 = 2 [viel zu viel]; else = NA"), 
                       .names = "{.col}_um0")) |> # HIer werden an die Variablennamen Suffixe "_um0" angehängt
  sjlabelled::var_labels(HAUFIGKEIT_01_um0 = "Corona", # Hier noch Label für die Variablen
             HAUFIGKEIT_02_um0 = "Abstimmungen", 
             HAUFIGKEIT_03_um0 = "Finanz", 
             HAUFIGKEIT_04_um0 = "Klima", 
             HAUFIGKEIT_05_um0 = "Geflüchtete")

# DATEN_BF |> 
#   sjmisc::frq(HAUFIGKEIT_01_um0:HAUFIGKEIT_05_um0)

6.5.3 NA durch 0 ersetzen

Die Grundstruktur von across-Befehlen ist an erster Stelle, zum Beispiel in mutate der Aufruf across gefolgt von der Liste der Variablen, für die dieselbe Mutationsfunktion durchgeführt werden soll. Im folgenden Beispiel ist es across(Nenn1:Nenn5). Dann folgt die Funktion, was durch ~angezeigt beziehungsweise gemacht wird. Immer da, wo man die Variablen einsetzen würde (also zB, wenn man die Funktion nur für Nenn1 schreiben würde, wo man die Nenn1 hinsetzt), wird .x geschrieben. Also wie oben, aber eine andere Funktion, nämlich if_else(), die so augebaut ist, dass in der Klammer als erstes die Bedingung kommt (im Fall is.na(.x), was so viel bedeutet wie: is die Variable im Fall na?). Nach dem darauffolgenden Komma kommt das, was R tun soll, wenn die Bedingung mit “wahr” (true) beantwortet werden kann (im Beispiel steht noch == TRUE, was eigentlich nicht nötig wäre, weil is.na() sowieso schon einen logischen Wert zurückgibt, also FALSE oder TRUE). Stimmt im Beispiel also bei einem Fall die Bedingung, dass in einer den Variablen Nenn1:Nenn5 ein “NA” steh, dann wird dafür jeweils eine 0 in die Daten geschrieben und sonst das .x, also die sonstigen gültigen Werte der Variablen.

DATEN_IA <- DATEN_IA |> 
  mutate(across(Nenn1:Nenn5, ~if_else(is.na(.x) == TRUE, 0, .x)))

6.5.4 Ausprägungen zusammenfassen

Mit dem sehr stark kombinierbaren Befehl case_when können Sie eine neue Variable erstellen (zB ALTER_GR) in der Klammer von case_when() die Bedingungen folgen (zB ALTER < 0) und dann das Funktionszeichen ~und dann der Wert, der an der Stelle, wo die Bedingung stimmt, hingeschrieben werden soll, also zum Beispiel die 1, wenn ALTER \<= 25, dann (\~) 1.

# Das Alter in Gruppen zusammenfassen
DATEN_BF <- DATEN_BF |> 
  mutate(ALTER_gr = case_when(
    ALTER < 0 ~ NA_real_,
    ALTER <= 25 ~ 1,
    ALTER <= 45 ~ 2,
    ALTER <= 65 ~ 3,
    ALTER <= 85 ~ 4,
    ALTER > 85 ~ 5
  ))  |> 
  sjlabelled::set_labels(ALTER_gr, labels = c("bis 25"  = 1, "26-45" = 2, "46-65" = 3, "66-85" = 4, "85+" = 5)) |> 
  sjlabelled::var_labels(ALTER_gr = "Alter gruppiert")

DATEN_BF |> sjmisc::frq(ALTER_gr)
## Alter gruppiert (ALTER_gr) <numeric> 
## # total N=204 valid N=204 mean=3.11 sd=1.06
## 
## Value |  Label |  N | Raw % | Valid % | Cum. %
## ----------------------------------------------
##     1 | bis 25 | 20 |  9.80 |    9.80 |   9.80
##     2 |  26-45 | 40 | 19.61 |   19.61 |  29.41
##     3 |  46-65 | 46 | 22.55 |   22.55 |  51.96
##     4 |  66-85 | 94 | 46.08 |   46.08 |  98.04
##     5 |    85+ |  4 |  1.96 |    1.96 | 100.00
##  <NA> |   <NA> |  0 |  0.00 |    <NA> |   <NA>

# Hier werden für die Inhaltsanalyse die Anzahl Worte in Gruppen zusammengefasst. Das geschieht mit dem Paket `sjmisc`, was den Vorteil hat, dass man bei jeder Ausprägunge auch gleich noch das Label dazuschreiben kann.

DATEN_IA <- DATEN_IA |> 
  mutate(WORTE_gr = sjmisc::rec(TC, 
                        rec = "0:100 = 1 [Kurzmeldung];
                        101:150 = 2 [kurzer Artikel]; 
                        151:300 = 3 [länger]; 
                        301:500 = 4 [lang]; 
                        501:max = 5 [Langtext]")) |> 
    relocate(WORTE_gr, .after = TC) 


### Rekodierung der Anzahl Nennungen in wenige Gruppen
DATEN_IA <- DATEN_IA |> 
  mutate(Nenn_Gr = sjmisc::rec(Nenn_Gesamt, rec = "1:3 = 1; 4:16 = 2; 17:100 = 3")) |> 
  sjlabelled::set_labels(Nenn_Gr, labels = (c("selten" = 1, "mittel" = 2, "häufig" = 3)))

6.5.5 Medium umkodieren

Mit den folgenden Befehlen könnten Sie eine Mediumsvariable in eine neue Variable umkodieren, die zwischen “Qualitätszeitungen” und “Boulevardzeitungen” unterscheidet (auch wenn ich die Unterscheidung immer ein bisschen bildungsbürgerlich ideologisch finde – egal, is ja erstmal nur ein Beispiel).

# 1 SRF
# 2 20min
# 3 Watson
# 4 NZZ
# 5 Tagesanzeiger
# 6 Blick

DATEN_IA <- DATEN_IA |> 
  mutate(Medium_Q = sjmisc::rec(MEDIUM, 
                    rec = "1,4,5 = 1 [Qualität]; 2,3,6 = 2 [Boulevard]")) 

DATEN_IA |> sjmisc::frq(Medium_Q)
## Medium_Q <numeric> 
## # total N=499 valid N=499 mean=1.50 sd=0.50
## 
## Value |     Label |   N | Raw % | Valid % | Cum. %
## --------------------------------------------------
##     1 |  Qualität | 249 | 49.90 |   49.90 |  49.90
##     2 | Boulevard | 250 | 50.10 |   50.10 | 100.00
##  <NA> |      <NA> |   0 |  0.00 |    <NA> |   <NA>

6.5.6 Bedingt umkodieren

Bedingt umkodieren heisst, dass Sie nur bestimmte Fälle umkodieren und andere so lassen, wie sie sind. Die Fälle suchen Sie mit der Bedingung des bedingten Umkodierens aus.

# DATEN_BF |> 
#  sjmisc::frq(ALTER, Bildung_gr)

DATEN_BF <- DATEN_BF |> 
  mutate(Alt_Bild1 = if_else(ALTER < 35 & Bildung_gr == 3, 1, 2)) 

DATEN_BF |>  sjmisc::frq(Alt_Bild1)
## Alt_Bild1 <numeric> 
## # total N=204 valid N=204 mean=1.97 sd=0.18
## 
## Value |   N | Raw % | Valid % | Cum. %
## --------------------------------------
##     1 |   7 |  3.43 |    3.43 |   3.43
##     2 | 197 | 96.57 |   96.57 | 100.00
##  <NA> |   0 |  0.00 |    <NA> |   <NA>

# Hier erstmal umkodieren und anschauen

DATEN_BF |> 
  mutate(Alt_Bild2 = case_when(
    ALTER < 35 & Bildung_gr == 3 ~ 1, 
    ALTER > 75 & Bildung_gr == 3 ~ 2,
  )) |> 
  sjlabelled::var_labels(Alt_Bild2 = "Alter und Bildung") |> 
  sjlabelled::set_labels(Alt_Bild2, labels = c("Junggebildet" = 1, "Altgebildet" = 2)) |> 
  sjmisc::frq(Alt_Bild2) # erstmal nur eine Frequencies als Ergebnis und nicht gleich den Daten hinzufügen
## Alter und Bildung (Alt_Bild2) <numeric> 
## # total N=204 valid N=10 mean=1.30 sd=0.48
## 
## Value |        Label |   N | Raw % | Valid % | Cum. %
## -----------------------------------------------------
##     1 | Junggebildet |   7 |  3.43 |      70 |     70
##     2 |  Altgebildet |   3 |  1.47 |      30 |    100
##  <NA> |         <NA> | 194 | 95.10 |    <NA> |   <NA>

# Dann dem Datensatz hinzufügen
DATEN_BF <- DATEN_BF |> # diese Zeile sorgt dafür, dass die DATEN_BF mit der Mutation in die DATEN_BF geschrieben werden
  mutate(Alt_Bild2 = case_when(
    ALTER < 35 & Bildung_gr == 3 ~ 1, 
    ALTER > 75 & Bildung_gr == 3 ~ 2,
  )) |> 
  sjlabelled::var_labels(Alt_Bild2 = "Alter und Bildung") |> 
  sjlabelled::set_labels(Alt_Bild2, labels = c("Junggebildet" = 1, "Altgebildet" = 2))

6.6 Variablen zu Indizes zusammenfassen

Indizes können Mittelwertindizes sein, Summenindizes oder sogar Faktoren aus einer Faktorenanalyse (PCA).

# Ein Summenindex für 10 Variablen zur Nachrichtennutzung Es wird zeilenweise die Summe für die Dummys (0/1-Variablen) berechnet

# wichtig ist hier rowSum, damit die Summe nicht über die Fälle, sondern die Variablen gebildet wird

DATEN_BF <- DATEN_BF |> 
  mutate(MEDIEN_sum = rowSums(across(NACHRICHT_TITEL1:NACHRICHT_TITEL10), na.rm = TRUE)) 

DATEN_BF |> 
  sjmisc::frq(MEDIEN_sum)
## MEDIEN_sum <numeric> 
## # total N=204 valid N=204 mean=2.02 sd=1.25
## 
## Value |  N | Raw % | Valid % | Cum. %
## -------------------------------------
##     0 | 17 |  8.33 |    8.33 |   8.33
##     1 | 57 | 27.94 |   27.94 |  36.27
##     2 | 69 | 33.82 |   33.82 |  70.10
##     3 | 39 | 19.12 |   19.12 |  89.22
##     4 | 13 |  6.37 |    6.37 |  95.59
##     5 |  6 |  2.94 |    2.94 |  98.53
##     6 |  3 |  1.47 |    1.47 | 100.00
##  <NA> |  0 |  0.00 |    <NA> |   <NA>

# Hier noch der Durchschnittswert als Index, was bei Dummys der Anteil der 1-er ist, also wenn 68 von knapp 200 Leuten 2 Medien nannten, dann gibt es 68 mal die 0.2 

DATEN_BF <- DATEN_BF |> 
  mutate(MEDIEN_mean = rowMeans(across(NACHRICHT_TITEL1:NACHRICHT_TITEL10), na.rm = TRUE))

DATEN_BF |> 
  sjmisc::frq(MEDIEN_mean)
## MEDIEN_mean <numeric> 
## # total N=204 valid N=203 mean=0.20 sd=0.12
## 
## Value |  N | Raw % | Valid % | Cum. %
## -------------------------------------
##  0.00 | 16 |  7.84 |    7.88 |   7.88
##  0.10 | 57 | 27.94 |   28.08 |  35.96
##  0.20 | 69 | 33.82 |   33.99 |  69.95
##  0.30 | 39 | 19.12 |   19.21 |  89.16
##  0.40 | 13 |  6.37 |    6.40 |  95.57
##  0.50 |  6 |  2.94 |    2.96 |  98.52
##  0.60 |  3 |  1.47 |    1.48 | 100.00
##  <NA> |  1 |  0.49 |    <NA> |   <NA>

6.6.1 NW-Index als Summe der NF

Im ersten Schritt werden die Nachrichtenfaktoren auf 0 gesetzt, wenn sie einen fehlenden Wert haben (also NA sind oder -9). Dann wird zweilenweise (rowwise) die Summe (Additivität) der NF gebildet. Das Resultat ist eine neue Variable im Datensatz, die NW_Sum_INDX heisst.

DATEN_IA <- DATEN_IA |> 
  mutate(across(c(PERS:KNTR, KAT:NAEHE), ~replace(.x, is.na(.x),0))) |> 
  mutate(across(c(PERS:KNTR, KAT:NAEHE), ~replace(.x, .x == -9,0))) |> 
  rowwise() |> 
  mutate(NW_Sum_IND = sum(c(PERS:KNTR, KAT:NAEHE)))

DATEN_IA |> sjmisc::frq(NW_Sum_IND)
## NW_Sum_IND <integer> 
## # total N=499 valid N=499 mean=3.74 sd=2.86
## 
## Value |   N | Raw % | Valid % | Cum. %
## --------------------------------------
##     0 |  50 | 10.02 |   10.02 |  10.02
##     1 | 106 | 21.24 |   21.24 |  31.26
##     2 |  31 |  6.21 |    6.21 |  37.47
##     3 |  94 | 18.84 |   18.84 |  56.31
##     4 |  58 | 11.62 |   11.62 |  67.94
##     5 |   5 |  1.00 |    1.00 |  68.94
##     6 |  44 |  8.82 |    8.82 |  77.76
##     7 |  44 |  8.82 |    8.82 |  86.57
##     8 |  16 |  3.21 |    3.21 |  89.78
##     9 |  50 | 10.02 |   10.02 |  99.80
##    11 |   1 |  0.20 |    0.20 | 100.00
##  <NA> |   0 |  0.00 |    <NA> |   <NA>

6.6.2 Beachtungsindex

Im Folgenden wird die Platzierung PLATZ und die Wortzahl TC zu einem Summenindex zusammengerechnet. Das Problem ist dabei, dass die beiden Variablen nicht annähernd die gleiche Skalierung haben (die Wortzahl geht im Beispiel von 1000 bis 9400 und die Platzierung von 1 bis 13, wobei eine kleinere Platzierung auf eine bessere Platzierung, also eine höhere Beachtung hinweisst). Damit wir die beidne Variablen ersteinmal angleichen, standardisieren wir sie beide mit scale auf z-transformierte Variablen und drehen dabei gleich die Variable um (darum das - vor PLATZ), so dass grössere Werte, stärkere Beachtung bedeuten. Dann bauen wir wieder einen Index, was bedeutet, dass wir den Mittelwert der beiden Beachtungsindikatoren zeilenweise berechnen (darum rowwise()). In der Mittelwertfunktion mean()steht hinter der z-Transformierten PLATZ_z noch * 2. Das sorgt dafür, dass die Platzierung mit dem doppelten Gewicht in die Berechnung des Beachtungsindexes eingeht, weil die Grundannahme ist, dass die Platzierung mehr über die journalistische Beachtung sagt, als der Umfang der Meldungen (online spielt der Platz ja nicht sooo eine Rolle wie bei Zeitungen oder Nachrichtensendungen im TV (früher)).

# erstmal die beiden Beachtungsindikatoren angucken
# DATEN_IA |> sjmisc::frq(PLATZ, TC) # nur auskommentiert, damit es im Output nicht elendig lang wird

DATEN_IA <- DATEN_IA |> 
  mutate(PLATZ_z = scale(-PLATZ), # PLATZ_z ist die z-Transformierte und umgekehrte Version von PLATZ (je grösser der Wert, desto grösser die Beachtung)
         TC_z = scale(TC)) |> # die z-Transformierte der Wortzahl TC
  rowwise() |> 
  mutate(Beachtung = mean(c(PLATZ_z * 2, TC_z), na.rm = TRUE)) |> # Mittelwert aus den z-Transformierten Variablen, wobei die Platzerierung mit doppeltem Gewicht (*2) eingeht
  ungroup() # die Gruppierung von rowwise wieder zurücksetzen

# DATEN_IA |> sjmisc::frq(Beachtung) # angucken

6.6.3 NW-Index aus dem Nachrichtenwertmodell

Ok, das wird jetzt recht heftig. Wer Regressionen in Statistik Aufbau nicht cool fand oder noch garnicht hatte, muss sich das Folgende nicht antun. Die Idee ist, dass wir einen Nachrichtenwertindex (NW) bauen, der sich aus den vorhergesagten Werten der Beachtung ergibt, wenn wir die Nachrichtenfaktoren (NF) in einem additiven Modell die Beachtungsindikatoren vorhersagen lassen. Im Vergleich zu dem NW_Sum_INDX von oben, gehen in diesen NW_Modell_INDX nicht alle NF mit demselben Gewicht ein, sondern mit den Gewichten, die die journalistische Beachtung vorhersagen. Sie können diesen Index nehmen und durch Datenfusion an den Datensatz der Befragung anhängen. Dann können Sie schauen, wer stärker und wer weniger auf die gewichteten NF reagiert. Wer also sehr typisch oder sehr untypisch Nachrichten rezipiert.

AV_und_UV <- DATEN_IA |> # wichtig hier, dass ein neues Datenobjekt AV_und_UV angelegt wird, weil Sie sich sonst alle andere Variablen aus ihrem Datensatz löschen
  select(Beachtung, PERS:KNTR, KAT:NAEHE) # Es werden alle UVs und die AV ausgewählt

NW_Modell <- lm(Beachtung ~ ., data = AV_und_UV) # der Punkte steht für alle Variablen (also die oben ausgewählten); So braucht man nicht jeden NF mit + hintereinander in das Modell tun.

# summary(NW_Modell) # hiermit mal die Auswertung anschauen.

DATEN_IA <- DATEN_IA  |> 
  select(-any_of("NW_INDX")) |> # löschen, wenn die Variable schon da ist, damit es keine Konflikte gibt
  modelr::add_predictions(NW_Modell) |> 
  rename(NW_INDX = pred)

# DATEN_IA |> sjmisc::frq(NW_INDX) # Sehr viele detaillierte Werte

6.6.4 Gemitteltes NF-Gewicht von Befragten

Wenn an den Befragungsdatensatz die Inhaltsanalyse angehängt wird, gibt es für jede von den Befragten genannte Meldung den Mittelwert der NF-Intensitäten. Das soll nun für die Befragten zu einem Mittelwert zusammengefasst werden.

6.6.5 Umfangreiche Umkodierungstabellen (TF E)

Zum Beispiel für Ländereigenschaften über die Ländercodes.

# Aus der Länderliste mit den Kodierungen kommen die Variablen für eine Laenderliste:
Laenderliste <- readxl::read_xlsx("data/Laender_Liste_Kodierung.xlsx", sheet = "Länderliste")

# Die Codes für die Länder kommen aus einer anderen Untertabelle der Excel, darum steht hinten bei sheets etwas anderes:
Ländercodes <- readxl::read_xlsx("data/Laender_Liste_Kodierung.xlsx", sheet = "Ländercodes")

# Dann gibt es noch lauter weitere Codes, die wir jetzt anmatchen können, die können wir später gut gebrauchen, weil verschiedene Datensätze aus dem Internetz verschiedene Ländercodes verwenden

Land_AlphaISO <- readxl::read_xlsx("data/Laender_Liste_Kodierung.xlsx", sheet = "AlphaISO") |> 
  select(name, "alpha2", "alpha3", "CountryCode")

# Hier binden wir die zusammen, erst die Ländercodes an die Laenderliste und dann noch die Land_AlphaISO hinten dran
Laender <- left_join(Laenderliste, Ländercodes, by = "Land") |>
  left_join(Land_AlphaISO, by = "alpha2")

# oh, und hier noch ein paar Handelsdaten, falls das jemanden interessiert
WorldTrade <- economiccomplexity::world_gdp_avg_1998_to_2000

# So, die kleben wir jetzt auch noch hinten an unsere Laendervariable
Laender <- left_join(Laender, WorldTrade, by = c("alpha3" = "country"))

# Schreibe die Laender-Daten raus in die Exceldatei "Laender_codes.xlsx"
writexl::write_xlsx(Laender, "data/Laender_codes.xlsx")

# Hier die Laender-Daten wieder aus der (eventuell ergänzten Laender-Excel) in R laden:
Laender <- readxl::read_xlsx("data/Laender_codes.xlsx")

# Jetzt kommt die Magie. Wie matchen die Laendervariable an die Inhaltsanalysedaten:

# Hier lade ich die Inhaltanalysedaten aus meiner Excel. Vermutlich heisst die Excel bei Ihnen anders und liegt vielleicht auch nicht im Unterordner "Daten".
IA <- readxl::read_excel("data/IA_Gesamt.xlsx")

# Hier werden alle Variablen aus der Laendertabelle hinten an die Inhaltsanalyse geklebt
IA <- left_join(IA, Laender, by = c("LAND" = "Code"))