Experimental design and data processing

The Data

The training data consists of 4 studies which measured cytokines in response to influenza vaccination. These studies have a mean of 32 participants per study.

train <- read.delim("../datasets/260512/train/train_cytokine.tsv", sep = "\t", stringsAsFactors = FALSE)
challenge <- read.delim("../datasets/260512/train/challenge_cytokine.tsv", sep = "\t", stringsAsFactors = FALSE)

train$set <- "train"
challenge$set <- "challenge"

train = train %>% filter(!timepoint %in% c(-14,0))
challenge = challenge %>% filter(!timepoint %in% c(-14,0))

#table(train$timepoint)
#table(challenge$timepoint)

tp_levels_train    <- c("Pre-vacc", "1")
tp_levels_challenge<- c("Pre-vacc", "1")

train$timepoint    <- factor(train$timepoint,    levels = tp_levels_train)
challenge$timepoint<- factor(challenge$timepoint, levels = tp_levels_challenge)

both <- bind_rows(train, challenge)
participants_per_study <- both %>%
  distinct(set, study_accession, participant_id) %>%
  count(set, study_accession, name = "n_participants")

p1 <- ggplot(participants_per_study,
             aes(x = reorder(study_accession, n_participants), y = n_participants,
                 fill = set)) +
  geom_col(position = position_dodge(width = 0.7), width = 0.6) +
  geom_text(aes(label = n_participants),
            position = position_dodge(width = 0.7), hjust = -0.2, size = 3.5) +
  coord_flip() +
  scale_fill_manual(values = c(train = "#2C7FB8", challenge = "#E34A33")) +
  labs(title = "Participants per study",
       x = "Study accession", y = "# distinct participants", fill = NULL) +
  expand_limits(y = max(participants_per_study$n_participants) * 1.15)

p1

Below is the distribution of cytokine measures found in the training data.

train_order <- train %>%
  group_by(analyte) %>%
  summarise(med = median(value), .groups = "drop") %>%
  arrange(desc(med)) %>%
  pull(analyte)

train_plot <- train %>% mutate(analyte = factor(analyte, levels = train_order))

p4 <- ggplot(train_plot, aes(x = analyte, y = value)) +
  geom_boxplot(outlier.size = 0.5, outlier.alpha = 0.3, fill = "#2C7FB8", alpha = 0.6) +
  scale_y_log10(labels = label_number()) +
  coord_flip() +
  labs(title = "Distribution of each cytokine (train set)",
       x = NULL, y = "pg/ml (log10)") +
  theme(axis.text.y = element_text(size = 9))
p4

  • Pre-vaccination data : Day0 timepoints are available.

Across all assay data, we also provide a “Pre-vacc” measure, which is the mean of all pre-vaccination data for each subject and each cytokine. In the case of the cytokine data, “Pre-vacc” measures will be the same as Day 0 measures since there are no other pre-vaccination timepoints.

  • Post-vaccination data : Day 1 timepoints are provided.

Prediction Task

Task 1.1 asks contestants to predict the fold change of IP10 (CXCL10) from Pre-vacc to Day 1, for the 40 donors found in the 2025LJI challenge dataset.

More details about all tasks are available here: https://docs.google.com/spreadsheets/d/1mmnSfJ2t24-AfBugTbLcAwcIdg3-I_v1X93WFWS3HxY/edit?gid=0#gid=0

The distribution of IP10 in the different studies is shown below.

ip10 <- both %>% filter(analyte == "IP10")

p5b <- ggplot(ip10, aes(x = timepoint, y = value, fill = set)) +
  geom_boxplot(alpha = 0.7) +
  scale_y_log10(labels = label_number()) +
  facet_wrap(~set, scales = "free_x") +
  scale_fill_manual(values = c(train = "#2C7FB8", challenge = "#E34A33")) +
  labs(title = "IP10 by timepoint", x = "Timepoint", y = "IP10 (pg/ml, log10 scale)",
       fill = NULL) +
  theme(legend.position = "none")

p5b