Skip to contents

Reads the participant workbook, binds its per-course sheets, applies sdt_participant_dictionary() and returns one row per participant record with the raw and the normalised columns side by side.

Usage

sdt_read_participants(
  path,
  dictionary = sdt_participant_dictionary(),
  sheets = NULL,
  verbose = TRUE
)

Arguments

path

Path to the participant workbook (.xlsx). Read-only; nothing is written to it or beside it.

dictionary

A sdt_participant_dictionary.

sheets

Optional character vector of per-course sheet names to restrict to. NULL, the default, reads every sheet named in the workbook's Course_Index.

verbose

Report row counts, neutralised leaks and per-covariate missingness while reading.

Value

A sdt_participants object: a tibble::tibble() subclass, one row per participant record, with attributes course_index (one row per course, including the empty ones), dictionary and meta.

What this data can and cannot do

The register links a person to a course. It carries no group, team or "Gruppe" column, so a participant cannot be placed in group A rather than group B. Every group inside one course therefore shares the same composition row. In the behaviour model y ~ card + (1 | block) + (1 | group) these covariates are block-level: they can compete with the session random effect, and can never explain the team random effect, which has no composition variance to spend. Treat any composition analysis as a between-course regression on as many points as there are courses.

Missingness

Courses with no linked participants are kept, not dropped: the course_index attribute carries every course in the workbook with its n_participants and has_participants, so a caller sees the empty courses rather than inferring them from an absence.

Rows the extractor wrote a diagnostic into instead of an answer are detected and neutralised to NA before anything is normalised, and a row with nothing but such a diagnostic is a course placeholder rather than a person: it is removed from the participant rows and counted in course_index$n_placeholder_rows.

Two logical column families record what happened to every raw field:

  • .missing_<field> — the information is not available. For funktion this includes the declared non-answer "Nichts angegeben", which is missing information rather than a grade; for weiterbildungsjahre it includes unparseable free text such as ",".

  • .imputed_<field> — the normalised value was filled rather than observed. Only titel has a participant-level fill rule by default (an empty title box becomes none, see sdt_participant_dictionary()); the rest are filled, if at all, at course level by sdt_course_composition(). An imputed value is never indistinguishable from an observed one.

See also

sdt_course_composition() to aggregate to course level, sdt_participant_summary() for descriptives that state their denominators.

Examples

if (FALSE) { # \dontrun{
p <- sdt_read_participants("TDSC_course_participant_relations.xlsx")
p
attr(p, "course_index")
sdt_course_composition(p)
} # }