Data processing

This chapter uses tidyverse tools to wrangle the data to re-shape it, plot it, create summary data and get it ready for modelling.

The basic structure here is as follows:

  1. Read in wide format data.
  2. Wrangle to re-shape it into long format.
  3. Filter and create factors.
  4. Run some data checks.
  5. Plot the data.
  6. Save our the data ready for modelling.

1. Read in the data

dat_wide <- read_csv(
  "data/sim_dat_wide.csv",
  show_col_types = FALSE
)

head(dat_wide)
# A tibble: 6 × 12
  pid   group    test_time pre_score_z item_22 item_23 item_28 item_17 item_1
  <chr> <chr>    <chr>           <dbl>   <dbl>   <dbl>   <dbl>   <dbl>  <dbl>
1 P001  control  post            0.361       0       1       1       1      0
2 P002  control  post            1.33        1       1       0       0      1
3 P003  embodied post           -0.608       1       1       0       0      0
4 P004  control  post           -1.09        0       0       0       0      0
5 P006  control  post           -0.124       1       1       1       0      0
6 P007  embodied post           -0.608       1       1       1       1      1
# ℹ 3 more variables: item_26 <dbl>, item_25 <dbl>, item_19 <dbl>
# glimpse(dat_wide)
# summary(dat_wide)

2. Reshape from wide to long

dat_long <- dat_wide |>
  pivot_longer(
    cols = starts_with("item_"),
    names_to = "item_id",
    names_prefix = "item_",
    values_to = "correct"
  ) |>
  mutate(item_id = as.numeric(item_id)) |>
  relocate(item_id, .after = "pid")

head(dat_long)
# A tibble: 6 × 6
  pid   item_id group   test_time pre_score_z correct
  <chr>   <dbl> <chr>   <chr>           <dbl>   <dbl>
1 P001       22 control post            0.361       0
2 P001       23 control post            0.361       1
3 P001       28 control post            0.361       1
4 P001       17 control post            0.361       1
5 P001        1 control post            0.361       0
6 P001       26 control post            0.361       0
# glimpse(dat_long)
# summary(dat_long)

3. Filter and create factors for plotting

dat <- dat_long |>
  filter(test_time == "delay") |>
  select(-test_time) |>
  mutate(
    group = factor(
      group,
      levels = c("control", "embodied")
    )
  )

head(dat)
# A tibble: 6 × 5
  pid   item_id group   pre_score_z correct
  <chr>   <dbl> <fct>         <dbl>   <dbl>
1 P001       22 control       0.361       1
2 P001       23 control       0.361       1
3 P001       28 control       0.361       0
4 P001       17 control       0.361       1
5 P001        1 control       0.361       0
6 P001       26 control       0.361       1

4. Run some data checks

At this point, it would be worth running some checks on the data. This will almost always involve data visualisation at the same time.

Basic checks might be:

  • how many pids and trials per group?
  • Are there any implausible values? e.g., values outside of a sensible range, given the measure?
  • Any missing data?
  • Ceiling or floor effects per pid or item?
  • What do the data distributions look like? Density/Histrograms would be useful.
  • Have exclusion criteria been applied accurately and as per the pre-registration (if one exists)?

There will also be a bunch of other very sensible things that you should check and plot. And this is the engine room of data analysis, so seeking advice on good data hygiene and principles for data cleaning would be a good idea.

5. Plot the data

And now summarise and plot

dat_summary <- dat |>
  filter(!is.na(correct)) |>
  summarise(
    score = sum(correct),
    n_items = n(),
    .by = c(pid, group)
  ) |>
  arrange(pid, group)

head(dat_summary)
# A tibble: 6 × 4
  pid   group    score n_items
  <chr> <fct>    <dbl>   <int>
1 P001  control      4       8
2 P002  control      1       8
3 P003  embodied     2       8
4 P004  control      0       8
5 P006  control      3       8
6 P007  embodied     6       8
group_colours <- c(control = "#4477AA", embodied = "#228833")

p1 <- dat_summary |>
  ggplot(aes(y = score, fill = group, colour = group)) +
  # histogram slab nudged right
  stat_slab(
    aes(x = as.numeric(group) + 0.05, thickness = after_stat(pdf)),
    side = "right",
    scale = 0.4,
    alpha = 0.5,
    density = "histogram",
    breaks = breaks_fixed(width = 1)
  ) +
  # dots nudged left with jitter
  geom_point(
    aes(x = as.numeric(group) - 0.15),
    position = position_jitter(width = 0.1, height = 0),
    alpha = 0.4,
    size = 2
  ) +
  # mean + SE at centre
  stat_summary(
    aes(x = as.numeric(group)),
    fun.data = mean_se,
    geom = "pointrange",
    colour = "black",
    size = 0.6,
    linewidth = 1.2
  ) +
  stat_summary(
    aes(x = as.numeric(group), group = 1),
    fun = mean,
    geom = "line",
    linewidth = 1,
    colour = "black"
  ) +
  scale_x_continuous(
    breaks = 1:2,
    labels = c("control", "embodied"),
    expand = expansion(add = c(0.3, -0.3)) # more space left, less right
  ) +
  scale_fill_manual(values = group_colours, name = "group") +
  scale_colour_manual(values = group_colours, name = "group") +
  labs(
    title = "Score by group",
    x = NULL,
    y = "Score"
  ) +
  theme(
    axis.text.x = element_blank()
  )

print(p1)

6. Save out the data for modelling

write_csv(dat, "data/dat.csv")