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:

  1. 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?
  2. 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.

Beispiel

Stellen Sie sich z.B. vor, Sie haben in Ihrem Datensatz eine Spalte, in der die Trialdauer angegeben ist. Sie sehen Zahlen zwischen 15.000 und 30.000. Was bedeuten die? Sollen das Millisekunden sein? Dann hätte ein Trial 15-30s gedauert. Entspricht das Ihrer Planung und dem, was Sie beim eigenen Testen Ihres Experiments erlebt haben? Wahrscheinlich nicht. Wurden also die Trialdauern vom Experimentalprogramm falsch abgespeichert? Nehmen Sie nun an, das Experimentalprogramm hat die Trialdauer gar nicht gespeichert, sondern Sie berechnen sie selbst in Ihrem R-Code. Haben Sie die richtigen Events für Trialbeginn und Trialende zugrunde gelegt? Haben Sie irgendwelche Umrechnungen vorgenommen und sich dabei vertan? Vielleicht ist aber auch alles ganz genau richtig berechnet, aber die Zeitangaben in Ihren Daten sind nicht Millisekunden, sondern Zehntel Millisekunden?

(Finden Sie stupide? Naja, kommt aus dem echten Leben - eine sehr weit verbreitete Software hat Zeiten lange in Zehntel ms abgespeichert und damit ab und an für Verwirrung gesorgt.)

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?

  1. 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.
  2. 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:

load("RTL_beispieldaten.RData")

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).

d <- bsp

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.

d$Participant <- as.factor( d$Participant ) # Variable in Faktor umwandeln

# 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.

d$soaNum <- d$SOA
# 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.

d$SOA <- as.factor(d$SOA)

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.

d$resp <- 1 #zunächst alles auf 1

d$resp[ d$Response.correct != "TRUE" ] <- 0 #Fehler auf 0

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" ...
d$rt <- as.numeric( as.character( d$Real_Release_RT ) )
# 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.

ds <- d %>% 
  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 ...