load("RTL_beispieldaten.RData")
4 Analysen planen und Variablentypen anpassen
4.1 Die Planung der Analyse beginnt schon vor der Erhebung
4.1.1 Die richtige Analyse für das vorliegende Design wählen
Bevor man mit der Erhebung losgegt, muss man sich überlegen, wie das Experimentaldesign aussieht und später in der Analyse umgesetzt werden muss. Dazu gehört:
- Was ist/sind meine abhängige Variable/n (AV)?
- Welches Skalenniveau (nominal, ordinal, kardinal) hat/haben meine AV?
(Beachte ggf. Abschnitt “Umgang mit %-Daten” weiter unten) - Was sind meine unabhängigen Variablen (UV)? Dies sind i.d.R. unsere experimentellen Faktoren.
- Welches Skalenniveau haben meine UV?
- Welche Ausprägungen bzw. wieviele Stufen haben meine UV?
- Handelt es sich um Innersubjektfaktoren (within-subject, abhängige Messungen bzw. Messwiederholungen) und/ oder Zwischensubjektfakoren (between-subject, unabhängige Messungen)?
- Between-subjects: verschiedene Stufen eines Faktors werden nicht in derselben Person erhoben , sondern in verschiedenen Gruppen.
- Within-subjects: Stufen eines Faktors werden alle in derselben Person erhoben
- Sind die entsprechenden Variablen in R im korrekten Format?
- Diskrete UV sollten als “Factor” vorliegen
- Kontinuierliche UV als “int” (=integer = Ganzzahlen) oder “numeric” (Kommazahlen).
- siehe ggf. Abschnitt “Daten ins richtige Format bringen” (verlinken)
- Sind alle Variablen, die ich benötige, schon im Datensatz vorhanden, oder muss ich neue Variablen berechnen?
4.1.2 Grundsatz: immer nachdenken, immer prüfen
4.1.2.1 Datengesundheit (data health)
= Daten enthalten wirklich das, was sie enthalten müssen. Bevor Sie mit Ihrem Experiment richtig loslegen, sollten Sie unbedingt prüfen, ob die erhobenen Datensätze vollständig sind.
Dies beinhaltet zwei Aspekte. Testen Sie beide, indem Sie bspw. sich selbst testen und dann die Daten so weit analysieren, bis sie diese Fragen beantworten können:
- Sind alle Variablen erfasst, die ich für meine geplante Analyse benötige?
Beispiel: wenn ich ein Experiment mit einem 2-faktoriellen 2x4 Design geplant habe, kann ich dann aus den Logfiles bzw. aus dem Datensatz, den ich von meine:r Anleiter:in erhalte, auch wirklich 2 Faktoren mit 2 bzw. 4 Levels rekonstruieren?
- Sind von allen Bedingungen und Bedingungskombinationen wirklich so viele Trials vorhanden, wie ich es erwarte?
Diese Strategie ist wichtig, damit Sie nicht versehentlich einen ganzen Datensatz erheben, den Sie hinterher nicht richtig auswerten können, nur weil z.B, vom Experimentalprogramm eine Manipulation im Logfile nicht eingetragen wurde.
Sie bedeutet auch, dass Sie das Einlesen und Vorbereiten Ihrer Daten bereits vor dem richtigen Start Ihres Experiments umsetzen sollten.
4.1.2.2 Datenplausibilität
Mit Datenplausibilität ist ein anderer Aspekt gemeint. Nehmen Sie Daten, und erst recht berechnete Werte (so wie Mittelwerte etc.) niemals einfach so hin. Fragen Sie sich immer, ob die Werte dem entsprechen, was Sie erwarten würden. Wenn dies nicht so ist, gehen Sie der Diskrepanz nach und prüfen Sie, ob es sich um einen Fehler im Experiment, in der Analyse bzw. Interpretation der Datenwerte oder in Ihrer Erwartung handelt.
4.1.2.3 So lange nachdenken und rumprobieren, bis alles klar ist
Die Herangehensweise ist immer: glaube nie, dass alles stimmt. Fragen und prüfen Sie so lange, bis Sie sicher sind, dass alles so ist, wie es entweder sein soll, weil Sie es so geplant haben (Anzahl Trials, Faktoren, Faktorlevel, Stimulus-Timing…) oder wie es sein könnte, weil es plausibel erscheint (Trialdauer, Reaktionszeiten, Fehlerzahl, …). Wenn Sie sich nicht sicher sind, überlegen Sie, wo Sie die Infos herbekommen können:
- Entsprechen Fehlerzahlen und RTs in etwa dem, was Sie in Artikeln gelesen haben?
- Entsprechen die Zahlen dem, was Ihr eigener Eindruck ist (s.o. Trialdauer)?
- Entsprechen die Zahlen dem, was Ihr*e Anleiter*in gesagt hat? (Und wenn sie nichts gesagt hat, können Sie nachfragen.)
4.2 Daten ins richtige Format bringen
Zeitplanung: nach den ersten 1-2 Erhebungen
Nachdem die Daten geladen sind, muss man sie so bearbeiten, dass man sie richtig nutzen kann. Gründe dafür sind, z.B.:
- Manche Variablen haben möglicherweise ein ungünstiges Format (z.B. s statt ms)
- R weiß noch nicht, welche Variablen welchen Typ haben; insbesondere muss man R sagen, welche Variablen Faktoren sind, da sonst viele statistische Auswertungen und manchmal Abbildungen nicht funktionieren.
Was muss man dabei typischerweise beachten?
Alle Variablen, die man aus einer Textdatei an Texten importiert hat, sind in R zunächst “chr” (steht für character). Dies sind normalerweise in unserer Experimentallogik Faktoren:
VP-Bezeichnungen - eine Vp ist ein Faktorlevel auf dem Faktor “subject” (bei uns oft subjNr). Eine Vp wird bei uns oft nicht numerisch als 1, 2, … bezeichnet, sondern komplexer, bspw. als B006_s01. Wie diese Bezeichnungen zustandekommen, ist für Sie nicht wichtig. Wichtig ist aber, dass alle Daten, die den gleichen Eintrag unter dieser Variable haben, von derselben Person stammen (denken Sie an die Unterscheidung within/between-subjects).
Daten wie “gekreuzt, ungekreuzt” - es ist sinnvoll, wenn man solche Bezeichnungen im Datensatz als Wort belässt; nur muss R wissen, dass man damit Bedingungen meint (und nicht zB einzelne Wörter)
Sonderfall - wenn man unterschiedliche stimulus onset asynchronies (SOA) verwendet und diese in die Analyse aufnehmen will: dies sind ja Zahlen (zB 100, 200, 300 ms zwischen einem Prime und einem Stimulus); aber in einer Anova sind es Faktorstufen. Darum muss man sie als Faktor codieren.
Häufig enthalten Datenfiles allerlei Spalten, die man gar nicht braucht. Darum erstellt man für Übersichtlichkeit am Schluss ein data.frame, das nur die Sachen enthält, die man wirklich braucht.
Wir werden jetzt step-by-step diese Schritte abarbeiten.
4.2.1 Überblick über Datensatz verschaffen
Zunächst muss man sich orientieren: was hat man eigentlich geladen?? Im Folgenden wird angenommen, dass die .RData Daten geladen wurden:
Im “Environment” bei RStudio sieht man, dass es ein data.frame “bsp” gibt.
Mit dem Befehl “head” stellt man die ersten Zeilen dar.
head(bsp)
Participant Tactor1 Tactor2 Stimuli Time Condition Repetition
1 B006b-08 6 1 6_1 2018-11-27-15-56-08 uncrossed 1
2 B006b-08 5 2 5_2 2018-11-27-14-30-16 uncrossed 1
3 B006b-08 6 2 6_2 2018-11-27-15-54-17 uncrossed 1
4 B006b-08 6 1 6_1 2018-11-27-14-24-41 uncrossed 1
5 B006b-08 2 5 2_5 2018-11-27-16-17-10 crossed 1
6 B006b-08 1 6 1_6 2018-11-27-15-16-24 crossed 1
Trialnumber Trialtype SOA Stim1Intens Stim2Intens ITI TimeAfterBeep Response
1 163 360 800 90 75 1000 996 3_4
2 170 378 100 90 80 1000 612 3_4
3 138 313 50 100 75 1000 969 1_2
4 91 343 300 100 70 1000 821 3_4
5 58 276 800 75 100 1000 721 3_4
6 305 245 50 80 90 1000 656 3_4
Release_RT Real_Release_RT RT1_press_raw RT1_release_raw RT2_press_raw
1 1433 618 [] [] []
2 939 824 [] [] []
3 817 752 1115 824 1124
4 961 646 [] [] []
5 1684 869 [] [] []
6 1001 936 [] [] []
RT2_release_raw RT3_press_raw RT3_release_raw RT4_press_raw RT4_release_raw
1 [] 1746 1475 1739 1433
2 [] 1272 960 1299 939
3 817 [] [] [] []
4 [] 1308 963 1336 961
5 [] 1985 1702 2000 1684
6 [] 1318 1017 1326 1001
Trial_ok Trial_repeated Reason LoadSucess Run Tactor1Side Tactor2Side
1 True False No reason success Run2 left right
2 True False No reason success Run1 right left
3 True False No reason success Run2 left left
4 True False No reason success Run1 left right
5 True False No reason success Run2 left right
6 True False No reason success Run1 right left
Tactor1Segment Tactor2Segment StimSide StimSegment Order
1 upper lower different different uncrossed first
2 upper lower different different uncrossed first
3 upper lower same different uncrossed first
4 upper lower different different uncrossed first
5 lower upper different different uncrossed first
6 lower upper different different uncrossed first
ResponseCoding Response.meaning Response.correct
1 1_2 (Zehen hoch) means same different TRUE
2 1_2 (Zehen hoch) means same different TRUE
3 1_2 (Zehen hoch) means same same TRUE
4 1_2 (Zehen hoch) means same different TRUE
5 1_2 (Zehen hoch) means same different TRUE
6 1_2 (Zehen hoch) means same different TRUE
Man sieht, dass da sehr viel Zeug drin ist.
Mit “str” kann man sich die Struktur des Datensatzes anschauen, d.h., herausfinden was für Variablen er enthält und was für Typen die Variablen haben.
Vorne steht der Variablenname, danach der Typ; z.B. bei Participant “chr”, also Text und noch nicht Faktor!
Selbiges gilt für viele andere Variablen auch. Nach der Typangabe sieht man ein paar Beispiele, was für Daten in der jeweiligen Variable drin sind.
str( bsp )
'data.frame': 32455 obs. of 40 variables:
$ Participant : chr "B006b-08" "B006b-08" "B006b-08" "B006b-08" ...
$ Tactor1 : int 6 5 6 6 2 1 1 1 4 2 ...
$ Tactor2 : int 1 2 2 1 5 6 3 5 1 5 ...
$ Stimuli : chr "6_1" "5_2" "6_2" "6_1" ...
$ Time : chr "2018-11-27-15-56-08" "2018-11-27-14-30-16" "2018-11-27-15-54-17" "2018-11-27-14-24-41" ...
$ Condition : chr "uncrossed" "uncrossed" "uncrossed" "uncrossed" ...
$ Repetition : chr "1" "1" "1" "1" ...
$ Trialnumber : int 163 170 138 91 58 305 224 203 117 123 ...
$ Trialtype : int 360 378 313 343 276 245 21 203 162 272 ...
$ SOA : int 800 100 50 300 800 50 50 300 100 800 ...
$ Stim1Intens : int 90 90 100 100 75 80 70 75 80 80 ...
$ Stim2Intens : int 75 80 75 70 100 90 85 100 80 90 ...
$ ITI : int 1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 ...
$ TimeAfterBeep : int 996 612 969 821 721 656 592 786 684 504 ...
$ Response : chr "3_4" "3_4" "1_2" "3_4" ...
$ Release_RT : chr "1433" "939" "817" "961" ...
$ Real_Release_RT : chr "618" "824" "752" "646" ...
$ RT1_press_raw : chr "[]" "[]" "1115" "[]" ...
$ RT1_release_raw : chr "[]" "[]" "824" "[]" ...
$ RT2_press_raw : chr "[]" "[]" "1124" "[]" ...
$ RT2_release_raw : chr "[]" "[]" "817" "[]" ...
$ RT3_press_raw : chr "1746" "1272" "[]" "1308" ...
$ RT3_release_raw : chr "1475" "960" "[]" "963" ...
$ RT4_press_raw : chr "1739" "1299" "[]" "1336" ...
$ RT4_release_raw : chr "1433" "939" "[]" "961" ...
$ Trial_ok : chr "True" "True" "True" "True" ...
$ Trial_repeated : chr "False" "False" "False" "False" ...
$ Reason : chr "No reason" "No reason" "No reason" "No reason" ...
$ LoadSucess : chr "success" "success" "success" "success" ...
$ Run : chr "Run2" "Run1" "Run2" "Run1" ...
$ Tactor1Side : Factor w/ 2 levels "left","right": 1 2 1 1 1 2 2 2 1 1 ...
$ Tactor2Side : Factor w/ 2 levels "left","right": 2 1 1 2 2 1 2 2 2 2 ...
$ Tactor1Segment : Factor w/ 2 levels "lower","upper": 2 2 2 2 1 1 1 1 1 1 ...
$ Tactor2Segment : Factor w/ 2 levels "lower","upper": 1 1 1 1 2 2 1 2 1 2 ...
$ StimSide : chr "different" "different" "same" "different" ...
$ StimSegment : chr "different" "different" "different" "different" ...
$ Order : chr "uncrossed first" "uncrossed first" "uncrossed first" "uncrossed first" ...
$ ResponseCoding : chr "1_2 (Zehen hoch) means same" "1_2 (Zehen hoch) means same" "1_2 (Zehen hoch) means same" "1_2 (Zehen hoch) means same" ...
$ Response.meaning: chr "different" "different" "same" "different" ...
$ Response.correct: logi TRUE TRUE TRUE TRUE TRUE TRUE ...
Wir sehen, dass bei Participant ziemlich lange Namen drin sind. Da sie informativ sind, wollen wir sie auch gern behalten. Dies ist kein Problem, weil Faktor-Level lange Namen haben dürfen. Hingegen ist es für Abbildungen oft praktischer, wenn Faktoren nicht so lange Namen haben, denn die sind dann schlecht lesbar in der Abbildung. Wir werden unten daher “uncrossed” in der Variable “Condition” umbenennen.
4.2.2 Kopie des originalen Datensatzes machen
Weil man häufiger zu dem originalen Datensatz zurückkehren möchte (z.B., weil man später doch noch eine Variable braucht, die man vorher schon eliminiert hatte), empfehlt es sich, den originalen Datensatz im Workspace zu behalten und zum Bearbeiten lieber eine Kopie anzulegen. Dazu kopiert man ihn einfach in eine neue Variable. Weil man nicht so viel tippen will, kann man seinen Datensatz am besten sehr kurz benennen. Wir nennen ihn einfach mal “d” (für “Daten”).
Das hat den Nebeneffekt, dass man immer vergleichen kann, wie die Daten am Anfang aussahen (bsp) und wie sie aussehen, nachdem man etwas dran gemacht hat (d).
<- bsp d
4.2.3 Variablen und Faktorlevels umbenennen
4.2.3.1 Sinnvolle Variablennamen
Benennen Sie Variablen, Faktoren und Faktorlevel so, dass sie für andere Leute verständlich sind, die Ihre Analyse nicht so gut kennen wie man selbst (z.B. die Anleiter*in, die Statistik-Hilfe etc.):
Vermeiden Sie generische Namen wie “a”, “bedingung”, “var”, etc. Wenn Sie zwei Faktoren menipuliert haben, ist “bedingung” schon missverständlich, weil man nicht weiß, ob es sich auf den ersten oder zweiten Faktor bezieht.
Nutzen Sie durchgängig eine Benennungslogik, bspw. meineVariable, meine_variable, meine.variable, aber eben nur eine dieser Varianten und nicht alle drei verschiedenen Formen. Manche empfehlen, verschiedene Code-Typen unterschiedlich zu benennen, z.B. Namen mit Unterstrich für Filenamen, mit Punkt für Variablen etc. Dies kann helfen, den Code lesbarer zu machen.
- Oft nervt es, wenn Variablennamen zwar verständlich, dafür aber lang sind. Dann wird Code schwerer lesbar und man muss mehr tippen.
Wenn Sie Variablen mit Kürzeln benennen, dann stellen Sie dem Code einen Kommentar voran, in dem sie die Variablennamen kurz begründen, z.B. “stdAbw = Standardabweichung”.
Zögern Sie nicht, Benennugnen für den gesamten data.frame Ihren Bedürfnissen anzupassen. Wenn die Variablen so heißen, wie es Ihnen sinnvoll erscheint bzw. wie Sie es gewohnt sind, wird Ihnen das Programmieren leichter fallen. Außerdem kann man Code super zwischen Skripten kopieren, wenn man immer ähnliche Variablen-Benennungen verwendet.
4.2.3.2 Ordnung von Faktorlevels Zu 1a und 1b: Variablen in Faktoren umwandeln und richtig ordnen
R sortiert von sich aus alphabetisch. Diese Reihenfolge wird dann in Grafiken auch verwendet. Um das so zu haben, wie man es sich wünscht, sortiert man selbst. Da für das Beispiel der Inhalt des Experiments egal ist, benennen wir die Faktorlevel in Level 1 und Level 2 um. Wir belassen aber uncrossed/crossed, weil das bei unseren Datensätzen oft vorkommt.
$Participant <- as.factor( d$Participant ) # Variable in Faktor umwandeln
d
# vor dem = der alte Name, dahinter der neue; mutate ist eine Funktion von tidyverse
<- d %>%
d mutate( Condition = recode_factor( as.factor( Condition ), "uncrossed" = "uncr", "crossed" = "crossed" ) )
<- d %>%
d mutate( StimSide = recode_factor( as.factor( StimSide ), "same" = "Level_1", "different" = "Level_2" ) )
<- d %>%
d mutate( StimSegment = recode_factor( as.factor( StimSegment ), "same" = "Level_1", "different" = "Level_2" ) )
zu 1c: Das Bsp-Experiment hatte auch verschiedene SOAs.
Zunächst prüfen wir, welche SOAs vorliegen.
str( d$SOA )
int [1:32455] 800 100 50 300 800 50 50 300 100 800 ...
Wir schauen mal rein, was für Werte drin sind: Integer-Zahlen 50, 100, 300, 800
Wir erstellen eine zweite Variable, die dieselben Daten aufnimmt.
$soaNum <- d$SOA
d# das Anhängsel Num zeigt an, dass diese Variable numerisch bleiben wird.
# Der Effekt davon wäre bspw. beim Erstellen einer Grafik, dass der Abstand
# zwischen 50 und 100 kleiner dargestellt würde als zwischen 300 und 800.
# Codiert man die Variable hingegen als Faktor, sind die Abstände zwischen
# Bedingungen in einer Abbildung alle gleich.
Anschließend machen wir aus der alten Variable einen Faktor.
$SOA <- as.factor(d$SOA) d
Wenn man SOA in einer ANOVA verwenden will, dann muss es als Faktor eingehen.
Manchmal möchte man Daten aber so plotten, dass die Abstände zwischen den Punkten den echten Wert widerspiegeln. Dazu muss man dann die Integer-Zahlen nutzen. Weil die Integer-Variable jetzt “num” heißt, weiß man, dass man die nur dann nimmt, wenn man keinen Faktor haben will. Wenn man diesen Schritt (Faktor machen) vergisst, erhält man seltsame Fehlermeldungen in ezAnova oder afex.
Man muss sich auf diese Weise alle Daten ansehen und überlegen, welche Spalten man braucht, ob sie im richtigen Format sind etc. Bitte fragen Sie im Zweifel gern Ihre:n Anleiter:in, wie Sie vorgehen sollen.
4.2.4 Abhängige Variablen prüfen und in richtiges Format bringen
Unsere abhängigen Variablen sind, (1) ob eine die korrekte Antwort gegeben wurde und (2) die Reaktionszeit.
4.2.4.1 AV Antwortverhalten
Die Codierung für die Antworten liegt noch nicht so vor, wie wir sie gern hätten.
str( d$Response.correct )
logi [1:32455] TRUE TRUE TRUE TRUE TRUE TRUE ...
Da sind Wörter “TRUE, FALSE”, und Variablentyp “logi” = binär richtig/falsch.
Wir erstellen daher eine neue Variable und füllen sie zunächst mit 1 für “richtig” oder “TRUE”. Überall, wo nicht TRUE (also entsprechend stattdessen FALSE) steht, setzen wir dann eine 0 rein. Diese Codierung erlaubt uns später, die Anzahl der richtigen Trials durch einfaches Addieren der Spalte zu ermitteln, weil alle Fehler mit 0 eingehen und somit nicht gezählt werden.
$resp <- 1 #zunächst alles auf 1
d
$resp[ d$Response.correct != "TRUE" ] <- 0 #Fehler auf 0 d
4.2.4.2 AV Reaktionszeit
Die RT ist auch nicht so, wie wir sie brauchen, denn der “str”-Befehl zeigt an, dass die Variable als “chr” formatiert ist.
str(d$Real_Release_RT)
chr [1:32455] "618" "824" "752" "646" "869" "936" "544" "1029" "779" "504" ...
$rt <- as.numeric( as.character( d$Real_Release_RT ) )
d# durch as.character würde die Variable immer erst in Text umgewandelt, selbst wenn
# in der Zukunft die Einlese-Funktion kein chr, sondern bspw. eine Zahl zurückgeben würde.
# wir stellen so sicher, dass das Ergebnis immer dasselbe bleibt.
str(d$rt)
num [1:32455] 618 824 752 646 869 ...
Jetzt sind es Zahlen.
Vielleicht haben Sie bemerkt, dass man sehr einfach Variablentypen ändern kann: der Befehl ist immer “as.” plus das, was man haben will - as.numeric, as.integer, as.character…
4.3 Variablen von Interesse auswählen
Am Schluss erstellen wir einen neuen data.frame, der nur enthält, was wir wirklich brauchen. Damit wird im vorliegenden Fall aus einem data.frame mit 40 Spalten (sehr unübesichtlich) ein viel kürzerer. Dabei kann man auch gleich noch Namen umbenennen, die einem nicht gefallen.
Z.B. ist die Bezeichnung “Condition” sehr ungünstig, weil sehr unspezifisch (s. Hinweis oben). Wir nennen sie “Posture”.
Für das vorliegende Bsp. nennen wir die anderen Faktoren A und B, da für unser Bsp. egal ist, was da genau getestet wurde.
Wieder machen wir (wie oben) eine Kopie des Datensatzes. Der neue Name “ds” steht für “data selected” und ist immer noch angenehm kurz.
<- d %>%
ds select( participant = Participant,
factor_A = StimSegment, factor_B = StimSide,
posture = Condition,
SOA, soaNum, resp, rt )# beachte, leider ist hier die Reihenfolge bei der Umbenennung andersrum als bei mutate: vor dem = steht der NEUE Name, hinter dem = der ALTE.
4.4 Ergebnis überprüfen
Das Ergebnis sollte man unbedingt anschauen und prüfen, ob alles wie erwartet aussieht!
head(ds)
participant factor_A factor_B posture SOA soaNum resp rt
1 B006b-08 Level_2 Level_2 uncr 800 800 1 618
2 B006b-08 Level_2 Level_2 uncr 100 100 1 824
3 B006b-08 Level_2 Level_1 uncr 50 50 1 752
4 B006b-08 Level_2 Level_2 uncr 300 300 1 646
5 B006b-08 Level_2 Level_2 crossed 800 800 1 869
6 B006b-08 Level_2 Level_2 crossed 50 50 1 936
str(ds)
'data.frame': 32455 obs. of 8 variables:
$ participant: Factor w/ 21 levels "B006b-08","B006b-09",..: 1 1 1 1 1 1 1 1 1 1 ...
$ factor_A : Factor w/ 2 levels "Level_1","Level_2": 2 2 2 2 2 2 1 2 1 2 ...
$ factor_B : Factor w/ 2 levels "Level_1","Level_2": 2 2 1 2 2 2 1 1 2 2 ...
$ posture : Factor w/ 2 levels "uncr","crossed": 1 1 1 1 2 2 2 1 1 1 ...
$ SOA : Factor w/ 4 levels "50","100","300",..: 4 2 1 3 4 1 1 3 2 4 ...
$ soaNum : int 800 100 50 300 800 50 50 300 100 800 ...
$ resp : num 1 1 1 1 1 1 1 1 1 1 ...
$ rt : num 618 824 752 646 869 ...