# Es werden Daten geladen, die im Unterordner "data" liegen. RDS-ist ein gutes R-Daten-Format
<- readRDS("data/DATEN_BEF.RDS")
DATEN_BF saveRDS(DATEN_BF, file = "data/DATEN_BEF.RDS") # speichern immer nach Laden, weil sonst schnell Fehler entstehen
<- readRDS("data/IAuBEF.RDS")
DATEN_IA saveRDS(DATEN_IA, file = "data/IAuBEF.RDS")
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.
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
|> sjmisc::frq(GESCHL)
DATEN_BF ## 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 ::var_labels(GESCHL = "Geschlecht")
sjlabelled
# Hier werden für die einzelnen Ausprägungen die Label vergeben
<- DATEN_BF |>
DATEN_BF ::set_labels(GESCHL, labels = c("mänlich" = 1, "weiblich" = 2, "divers" = 3, "k.A." = NA))
sjlabelled
# Mit dem Befehl für Häufigkeitstabellen (frq für frequencies) kann die Labelei schnell angesehen werden:
|>
DATEN_BF ::frq(GESCHL)
sjmisc## 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
::multiResponse() |> # Mehrfachantworten ansehen
ufsarrange(desc(Frequency)) |> # Sortieren nach Häufigkeit
::kable() |> # besser lesbare Tabelle daraus machen
kableExtra::kable_styling() # Styling
kableExtra## 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 ::var_labels(NACHRICHT_TITEL1 = "NZZ",
sjlabelledNACHRICHT_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 ::var_labels(KNTR = "Kontroverse") |>
sjlabelled::set_labels(KNTR, labels = c("keine" = 0, "gering" = 1, "stark" = 2, "k.A." = NA)) sjlabelled
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
|> sjmisc::frq(Befrag_Tag)
DATEN_BF ## 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 ::frq(Bildung) # erstmal angucken
sjmisc## 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 ::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
sjlabelled
|>
DATEN_BF ::frq(Bildung_gr)
sjmisc## 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 ::frq(HAUFIGKEIT_01:HAUFIGKEIT_05)
sjmisc## 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
::var_labels(HAUFIGKEIT_01_um0 = "Corona", # Hier noch Label für die Variablen
sjlabelledHAUFIGKEIT_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(
< 0 ~ NA_real_,
ALTER <= 25 ~ 1,
ALTER <= 45 ~ 2,
ALTER <= 65 ~ 3,
ALTER <= 85 ~ 4,
ALTER > 85 ~ 5
ALTER |>
)) ::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")
sjlabelled
|> sjmisc::frq(ALTER_gr)
DATEN_BF ## 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")) |>
::set_labels(Nenn_Gr, labels = (c("selten" = 1, "mittel" = 2, "häufig" = 3))) sjlabelled
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]"))
|> sjmisc::frq(Medium_Q)
DATEN_IA ## 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))
|> sjmisc::frq(Alt_Bild1)
DATEN_BF ## 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(
< 35 & Bildung_gr == 3 ~ 1,
ALTER > 75 & Bildung_gr == 3 ~ 2,
ALTER |>
)) ::var_labels(Alt_Bild2 = "Alter und Bildung") |>
sjlabelled::set_labels(Alt_Bild2, labels = c("Junggebildet" = 1, "Altgebildet" = 2)) |>
sjlabelled::frq(Alt_Bild2) # erstmal nur eine Frequencies als Ergebnis und nicht gleich den Daten hinzufügen
sjmisc## 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 |> # diese Zeile sorgt dafür, dass die DATEN_BF mit der Mutation in die DATEN_BF geschrieben werden
DATEN_BF mutate(Alt_Bild2 = case_when(
< 35 & Bildung_gr == 3 ~ 1,
ALTER > 75 & Bildung_gr == 3 ~ 2,
ALTER |>
)) ::var_labels(Alt_Bild2 = "Alter und Bildung") |>
sjlabelled::set_labels(Alt_Bild2, labels = c("Junggebildet" = 1, "Altgebildet" = 2)) sjlabelled
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 ::frq(MEDIEN_sum)
sjmisc## 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 ::frq(MEDIEN_mean)
sjmisc## 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)))
|> sjmisc::frq(NW_Sum_IND)
DATEN_IA ## 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.
<- 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
AV_und_UV select(Beachtung, PERS:KNTR, KAT:NAEHE) # Es werden alle UVs und die AV ausgewählt
<- 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.
NW_Modell
# 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
::add_predictions(NW_Modell) |>
modelrrename(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:
<- readxl::read_xlsx("data/Laender_Liste_Kodierung.xlsx", sheet = "Länderliste")
Laenderliste
# Die Codes für die Länder kommen aus einer anderen Untertabelle der Excel, darum steht hinten bei sheets etwas anderes:
<- readxl::read_xlsx("data/Laender_Liste_Kodierung.xlsx", sheet = "Ländercodes")
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
<- readxl::read_xlsx("data/Laender_Liste_Kodierung.xlsx", sheet = "AlphaISO") |>
Land_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
<- left_join(Laenderliste, Ländercodes, by = "Land") |>
Laender left_join(Land_AlphaISO, by = "alpha2")
# oh, und hier noch ein paar Handelsdaten, falls das jemanden interessiert
<- economiccomplexity::world_gdp_avg_1998_to_2000
WorldTrade
# So, die kleben wir jetzt auch noch hinten an unsere Laendervariable
<- left_join(Laender, WorldTrade, by = c("alpha3" = "country"))
Laender
# Schreibe die Laender-Daten raus in die Exceldatei "Laender_codes.xlsx"
::write_xlsx(Laender, "data/Laender_codes.xlsx")
writexl
# Hier die Laender-Daten wieder aus der (eventuell ergänzten Laender-Excel) in R laden:
<- readxl::read_xlsx("data/Laender_codes.xlsx")
Laender
# 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".
<- readxl::read_excel("data/IA_Gesamt.xlsx")
IA
# Hier werden alle Variablen aus der Laendertabelle hinten an die Inhaltsanalyse geklebt
<- left_join(IA, Laender, by = c("LAND" = "Code")) IA