
Vom Testcenter zum Skalierungsdatensatz
standard-workflow.RmdPaketstand: eatPrepTBA 0.9.8.9043.
Dieser Workflow führt von Testcenter-Antworten zu einem Datensatz mit einer Zeile je Person und einer Punktespalte je ausgewerteter Aufgabe (Item). Dazu werden die Antworten kodiert, Missings eingeordnet und psychometrische Kennwerte berechnet. Das Beispiel umfasst einen Testzeitpunkt und einen Bereich (Lesen) mit Autocode-Kodierschemata. Für Daten ohne solche Schemata, etwa aus StarS, siehe den Hinweis in Abschnitt 2.
| Quelle | Benötigte Daten |
|---|---|
| Studio | Units mit Kodierschemata, Item-Metadaten und Seiteninformationen |
| Testcenter | Antworten sowie Testdesign aus Testpersonen und Testheften |
Dateipfade, Serveradresse, Version, Workspace-IDs und Testmodus sind Platzhalter. Die folgenden Blöcke sind für die Ausführung mit eigenen Daten vorgesehen.
1. Studio: Units und Kodierschemata laden
Eine Unit ist eine Aufgabeneinheit mit einer oder
mehreren Variablen. Die Units müssen zur eingesetzten Testversion
passen. metadata = TRUE liefert die Item-Verknüpfungen,
unit_definition = TRUE die Seiteninformationen.
Ein Kodierschema legt für jede Variable fest, welche Antwort welchen Code und wie viele Punkte erhält, etwa „richtige Auswahl → Code 1 → 1 Punkt“. Es kann auch Regeln zur Ableitung weiterer Variablen enthalten.
login_studio()
meldet am Studio an, access_workspace()
wählt den Arbeitsbereich. get_units() lädt die
Units; add_coding_scheme()
bereitet ihre vorhandenen Kodierschemata für die Auswertung auf.
Das Beispiel setzt eine bereits auf 21.0.0 aktualisierte
Studio-Instanz voraus. Trage bei app_version die genaue
Version deiner Anmeldeseite ein, einschließlich eines möglichen
Beta-Zusatzes. Bis zum Update gilt die bisherige Version. Nach dem
Update erneut anmelden und das Workspace-Objekt neu erstellen.
studio_login <- login_studio(app_version = "21.0.0")
studio <- access_workspace(studio_login, ws_id = 123)
units <- get_units(studio, metadata = TRUE, unit_definition = TRUE)
units <- add_coding_scheme(units)2. Testcenter: Antworten und Design bereitstellen
Testcenter-Verbindung herstellen
Auch beim CSV-Import wird hier Testcenter-Zugriff
benötigt: get_design() lädt das vollständige
Testdesign. Erst damit lassen sich später fehlende Antworten als nicht
erreicht (Not reached) oder ausgelassen einordnen.
read_responses() allein reicht dafür nicht aus.
Anmeldung mit login_testcenter(),
Auswahl des Arbeitsbereichs mit access_workspace().
testcenter_login <- login_testcenter(base_url = "https://TESTCENTER-ADRESSE/")
testcenter <- access_workspace(testcenter_login, ws_id = 1)Antworten: eine der beiden Alternativen wählen
A – direkt aus dem Testcenter mit get_responses():
responses <- get_responses(testcenter)B – bereits heruntergeladenen CSV-Export einlesen
mit read_responses():
responses <- read_responses("daten/Responses.csv")Ohne Autocode-Kodierschema (z. B. StarS): prepare_responses(responses)
entpackt die Rohantworten zur eigenen Weiterverarbeitung; es vergibt
keine Codes oder Scores. Bereits im Export gespeicherte Kodierungen
lassen sich mit prepare_coded(responses)
entpacken. Die folgenden Schritte zeigen den Weg mit
Kodierschemata; die entpackten Daten sind dafür kein direkter
Ersatz.
Das vollständige Testdesign laden
get_design()
liefert für jede Person die Variablen, die in ihrem Testheft vorgesehen
waren.
Im gewählten Testcenter-Workspace müssen dafür die Materialien der Erhebung liegen:
-
Testpersonen-XML (z. B.
testtakers.xml): Gruppen, Logins, Codes, Anmeldemodus und Zuordnung zu den Testheften. - Die zugehörigen Testheft-XML-Dateien (Booklets): referenzierte Units und ihre Reihenfolge innerhalb der Testlets.
Die Dateien müssen dem Stand der Durchführung entsprechen. Die
Variablenliste wird aus den Kodierschemata im zuvor aus Studio geladenen
Objekt units ergänzt. Seiten und Abschnitte kommen aus der
Unitdefinition; die Beziehungen zwischen Ableitungen und ihren Quellen
stehen im Kodierschema.
design <- get_design(testcenter, units = units, mode = "run-hot-return")mode muss zum Anmeldemodus der Erhebung passen.
units muss alle relevanten Aufgaben enthalten; Antworten
und Design müssen dieselbe Erhebung abdecken.
3. Automatisch kodieren und Ergebnis prüfen
code_responses()
vergibt anhand des Kodierschemas Codes (code_id) und Punkte
(code_score). Dafür nutzt es eatAutoCode mit
dem IQB-Autocoder.
prepare = TRUE bereitet das Ergebnis für die weiteren
Schritte auf. Die abschließende Missing-Zuweisung folgt erst in
Abschnitt 5.
coded <- code_responses(responses, units, prepare = TRUE)
count(coded, code_status, code_type)Entscheidend sind die Variablen, die später als Items ausgewertet werden:
code_status |
Bewertung und nächster Schritt |
|---|---|
CODING_COMPLETE |
In Ordnung: Die Itemvariable ist fertig kodiert. |
CODING_INCOMPLETE,
DERIVE_PENDING
|
Noch offen: Kodierung bzw. benötigte Ausgangscodes prüfen; ggf. manuelle Codes ergänzen (Abschnitt 4). |
UNSET, CODING_ERROR,
DERIVE_ERROR
|
Prüfen: Kodierschema und Antworten kontrollieren; nach Korrekturen Units neu laden und erneut kodieren. |
DISPLAYED, PARTLY_DISPLAYED,
NOT_REACHED, INVALID
|
In der Regel in Ordnung: erwartbare Missing-Status, die in Abschnitt 5 behandelt werden. Unerwartete Häufungen prüfen. |
Untervariablen, die selbst keine Items werden, können andere Status behalten, ohne dass ein Problem vorliegt. Zu klären sind offene Kodierungen und Fehler, die die Itemvariablen oder deren Berechnung betreffen.
Die voreingestellte Missing-Zuordnung
Diese Tabelle ist in complete_design() bereits
hinterlegt. Du musst das Objekt missings für die
Beispielaufrufe nicht anlegen oder übergeben. Auslassungen und ungültige
Antworten erhalten 0 Punkte, Not reached und Kodierfehler
NA (keine Punktzahl).
missings <- tibble::tribble(
~code_id, ~code_status, ~code_score, ~code_type,
-96, "NOT_REACHED", NA_real_, "MISSING_NOT_REACHED",
-97, "CODING_ERROR", NA_real_, "MISSING_CODING_IMPOSSIBLE",
-98, "INVALID", 0, "MISSING_INVALID_RESPONSE",
-99, "DISPLAYED", 0, "MISSING_BY_OMISSION")complete_design() bestimmt die Missing-Art
(code_type) und setzt dazu Code und Punktzahl aus der
Tabelle. code_status bleibt unverändert,
auch NA bei neu ergänzten Zeilen. Die Statuszuordnung
benötigt code_responses() für manuelle Missing-Codes, etwa
-99 → DISPLAYED. Die endgültigen
Missing-Punktzahlen vergibt erst complete_design() in
Abschnitt 5.
Eigene Missing-Regeln: Den Tabellenblock oben
anpassen und ausführen. Dann missings = missings als
Argument in Abschnitt 4 (falls genutzt) und 5 ergänzen.
4. Optional: manuelle Codes einfügen
Nur nötig, wenn Antworten manuell kodiert werden. Sonst
weiter mit Abschnitt 5. Die fertige Tabelle
codes_manual benötigt group_id,
login_name, login_code,
booklet_id, unit_key, variable_id
und code_id: genau einen Code je zu kodierender Antwort,
passend zum Kodierschema. code_id enthält den Code, nicht
die Punktzahl.
# Kennungen als Text, code_id als Ganzzahl einlesen
codes_manual <- readr::read_csv("daten/codes_manual.csv",
col_types = readr::cols(.default = "c", code_id = "i"))
coded <- code_responses(responses, units, prepare = TRUE,
codes_manual = codes_manual)
count(coded, code_status, code_type)Erneut die ursprünglichen responses übergeben: So werden
die manuellen Codes eingefügt und davon abhängige Variablen neu
berechnet. Anschließend die Status wie in Abschnitt 3 prüfen.
5. Design vervollständigen und Missings zuweisen
complete_design()
ergänzt fehlende Zeilen: Alle laut Testdesign vorgesehenen Antworten
sollen im Datensatz stehen. Bei fehlenden Antworten wird geprüft, ob die
Person danach im selben Testabschnitt weitergearbeitet hat.
Für die Referenzstudien verwenden wir zwei Einstellungen:
-
recode_omissions_to_not_reached = TRUE: Auslassungen nach der letzten Bearbeitung werden zu „nicht erreicht“ (NR). Ihre Punktzahl wirdNA. -
preserve_not_reached = TRUE: Bereits als NR erkannte Antworten bleiben NR, auch wenn danach noch eine Bearbeitung folgt.
Beispiel im selben Testabschnitt: Auslassung – Antwort –
Auslassung wird zu Auslassung – Antwort – NR.
Die erste Auslassung behält 0 Punkte. Ohne Angabe stehen beide Optionen
auf FALSE.
design_coded <- complete_design(coded = coded, units = units, design = design,
recode_omissions_to_not_reached = TRUE,
preserve_not_reached = TRUE)
count(design_coded, id_used, code_type)
analysis_data <- filter(design_coded, id_used)Der Filter id_used behält Personen mit mindestens einem
gespeicherten Kodierstatus. Die endgültige Missing-Art steht in
code_type, die Punktzahl in code_score.
code_status bleibt unverändert.
Als Bearbeitung zählen Items und die Variablen, aus denen sie
berechnet werden. Fehlen dafür nötige Angaben in units,
können auch andere Variablen mitzählen; die Funktion gibt dann eine
Warnung aus. Bereits berechnete Itemergebnisse werden hier nicht neu
berechnet.
Besonderheit bei Markieraufgaben: Sie können einen
Code bekommen, obwohl sie gar nicht erreicht wurden. Ein solcher Code
zählt nicht als Beleg dafür, dass die Person weitergearbeitet hat. Code
und Punktzahl bleiben erhalten. Damit dies auch für bestehende
Datensätze funktioniert, code_responses() erneut mit den
ursprünglichen Antworten und gegebenenfalls den manuellen Codes
ausführen. Zusätzliche Einstellungen sind nicht nötig.
Der Herkunftsmarker gilt für die jeweilige Antwort. Ein daraus
berechnetes reguläres Itemergebnis, etwa eine Summe oder Kopie, kann
weiterhin als Bearbeitung zählen. Das ist auch bei ausschließlich aus NR
umgewandelten Quellen möglich. preserve_not_reached = TRUE
schützt dann bereits vorhandenes NR, macht eine davorliegende Auslassung
aber nicht zu NR.
Weitere Fälle zeigen die Missing-Beispiele.
Aufgaben, die laut Design gar nicht vorgesehen waren, sind
Missing by Design; ihre Zellen bleiben beim späteren
Umformen NA.
Missing-Anzahlen und -Anteile je Person
summarise_missings()
zählt die Missingtypen auf Itemebene. Vorher ergänzt
add_item_id() die Zuordnung aus den Studio-Metadaten;
Variablen ohne Item-ID werden nicht mitgezählt.
design_items <- add_item_id(design_coded, units)
missing_summary <- summarise_missings(design_items)
# Optional: nur Personen mit id_used = TRUE
missing_summary_used <- summarise_missings(design_items, used_only = TRUE)Standardmäßig bleibt jede Person aus design_items
erhalten. n_items ist die Zahl ihrer vorgesehenen Items.
n_not_reached zählt davon Not reached;
prop_not_reached ist der Anteil zwischen 0 und 1, z. B.
0.15 für 15 %. Die anderen Missingtypen erhalten ebenfalls
Anzahl und Anteil. n_missing und prop_missing
fassen alle Antwort-Missingtypen zusammen, einschließlich Auslassungen
und ungültiger Antworten mit 0 Punkten. Noch ungeklärte Kodierungen
werden separat ausgewiesen.
Gezählt wird code_type, nicht der unveränderte
Softwarestatus code_status. Jedes Item
(unit_key und item_id) darf je Person nur
einmal vorkommen; Doppelzählungen führen zu einem Fehler. Ohne
vorgesehene Items sind die Anzahlen 0 und die Anteile NA.
Bei einer anderen Personenkennung nutze beispielsweise
identifiers = "IDSTUD".
6. Psychometrische Kennwerte berechnen
Im Beispiel gehören alle Units zum Bereich Lesen; bei mehreren
Bereichen enthält domains die jeweilige Zuordnung (ein
Bereich je Unit). evaluate_psychometrics()
berechnet die Kennwerte.
domains <- distinct(units, unit_key)
domains$domain <- "Lesen"
psychometrics <- evaluate_psychometrics(analysis_data, units, domains = domains)
psychometrics <- add_item_id(psychometrics, units)
psychometrics |>
select(item_id, unit_key, variable_id, code_id, code_score,
code_n, code_p_valid, code_pbc) |>
distinct()code_n zählt, wie oft ein Code vorkommt.
code_p_valid ist sein Anteil unter Antworten mit Punktzahl
ungleich NA (einschließlich als 0 gewerteter Missings).
code_pbc ist die Korrelation seines Auftretens mit dem
mittleren Itemscore des Bereichs. Der eigene Itemscore fließt in dieses
Mittel mit ein.
7. Personen × Items für eatModel
add_item_id()
ergänzt die Item-ID aus den Studio-Metadaten über unit_key
und variable_id. Variablen ohne Item-Verknüpfung erhalten
NA; im Beispiel werden nur verknüpfte Itemvariablen
übernommen.
Für die Spaltennamen wird item nach der Konvention
unit_key__item_id gebildet, z. B. DH001__08.
item_id bleibt dabei eine Zeichenkette: Führende Nullen
müssen erhalten bleiben und dürfen nicht durch eine Umwandlung in Zahlen
verloren gehen.
item_data <- add_item_id(analysis_data, units)
item_data <- filter(item_data, !is.na(item_id))Optional: fehlende führende Nullen ergänzen. Falls
die Studio-Metadaten einstellige Item-IDs wie "8"
enthalten, diesen Chunk vor dem nächsten Schritt ausführen. Nach der
Konvention besteht item_id hier aus genau zwei Ziffern:
"8" wird zu "08", "08" und
"12" bleiben unverändert. Die Prüfung bricht bei anderen
Formaten ab, damit keine ungültigen IDs entstehen.
stopifnot(all(grepl("^[0-9]{1,2}$", item_data$item_id)))
item_data <- mutate(item_data,
item_id = stringr::str_pad(item_id, width = 2, pad = "0"))Anschließend die Itemnamen bilden und ins weite Format umformen:
item_data <- mutate(item_data, item = paste0(unit_key, "__", item_id))
scaling_data <- item_data |>
select(any_of(c("group_id", "login_name", "login_code", "IDSTUD")),
item, code_score) |>
pivot_wider(names_from = item, values_from = code_score)pivot_wider()
erzeugt eine Zeile je Person und eine Scorespalte je Item; die
vorhandenen Kennungen (group_id, login_name,
login_code, IDSTUD) bleiben erhalten.
any_of() überspringt fehlende Kennungsspalten.
Voraussetzung sind eindeutige Itemnamen und genau ein Score je Person
und Item. Fehlende Werte bleiben NA, sie werden nicht mit 0
aufgefüllt. analysis_data aufbewahren: Darin bleiben die
Missing-Arten unterscheidbar.
Für Referenzstudien: Diesen Workflow und den Szenarienvergleich als HTML zusammen mit der verwendeten Paketversion zur Auswertung ablegen. Die Online-Dokumentation wird weiterentwickelt.
Die weiteren Schritte zur Skalierung beschreibt die eatModel-Dokumentation.