Skip to contents

Introduction

This vignette demonstrates how to efficiently retrieve, filter, and summarize classification results using LundTaxR’s utility functions. After classifying samples, you often need to extract specific subsets, order samples for visualization, or compute summary metrics for downstream analysis. LundTaxR provides a suite of helper functions to streamline these common tasks.

What’s Covered

In this vignette, you’ll learn how to:

  • Extract subsets of predictions for specific sample groups using get_prediction_subset
  • Order samples based on subtype, score, or other criteria with get_sample_order
  • Compute and interpret subtype metrics using get_subtype_metrics for summary statistics and quality control

Each section includes practical code examples that you can adapt to your own data and workflows.


1. Extracting Prediction Subsets with get_prediction_subset

After classifying your samples, you may want to focus your analysis on a specific subset of samples—such as those belonging to a particular group or cohort. The get_prediction_subset function is designed to help you do just that: it extracts only the relevant samples from all components of your prediction results, whether those components are data frames or named vectors.

You can specify the samples to keep either by providing a vector of sample IDs, or by passing a metadata data frame that contains the desired samples (the metadata must contain a column with valid sample Ids, typically named “sample_id”). The function will return a new predictions list for the subset of samples specified.

Example: Subsetting by Sample IDs

Suppose you want to examine only a handful of samples from your classification results:

# Run the classifier (if not already done)
data("sjodahl_2017")
data("sjodahl_2017_meta")
results <- classify_samples(
  this_data = sjodahl_2017,
  include_data = TRUE,
  verbose = FALSE
)

# Example 1: Select a few sample IDs
selected_samples <- head(sjodahl_2017_meta$sample_id)

# Subset the results to just these samples
subset_results <- get_prediction_subset(
  these_predictions = results,
  these_sample_ids = selected_samples
)

# View the subsetted data
head(subset_results$data)
#>           1.CEL    2.CEL     3.CEL    4.CEL    5.CEL    6.CEL
#> A1CF   4.248274 4.153923  4.186689 4.877813 4.106269 5.278318
#> A2M    8.348800 7.969504 10.755738 8.467495 8.979222 9.520587
#> A2ML1  6.694896 4.442973  8.871067 4.392010 7.685045 4.493648
#> A4GALT 7.255671 6.337239  6.925670 6.239185 6.032115 6.539985
#> A4GNT  3.740418 3.830598  3.999331 3.813662 3.718752 3.567144
#> AAAS   6.837006 7.525639  6.778506 6.658134 7.354926 6.611625
head(subset_results$subtype_scores)
#>          Uro   UroA   UroB   UroC     GU   BaSq    Mes   ScNE
#> 1.CEL 0.9924 0.9350 0.0048 0.0602 0.0072 0.0004 0.0000 0.0000
#> 2.CEL 0.0016     NA     NA     NA 0.0052 0.0054 0.9804 0.0074
#> 3.CEL 0.0682     NA     NA     NA 0.7754 0.0834 0.0390 0.0340
#> 4.CEL 0.9930 0.9334 0.0028 0.0638 0.0066 0.0004 0.0000 0.0000
#> 5.CEL 0.9808 0.0058 0.9878 0.0064 0.0076 0.0090 0.0006 0.0020
#> 6.CEL 0.0082     NA     NA     NA 0.9890 0.0002 0.0004 0.0022
#>       prediction_delta_5_class prediction_delta_7_class
#> 1.CEL                   0.9852                   0.8748
#> 2.CEL                   0.9730                       NA
#> 3.CEL                   0.6920                       NA
#> 4.CEL                   0.9864                   0.8696
#> 5.CEL                   0.9718                   0.9814
#> 6.CEL                   0.9808                       NA
#>       prediction_delta_collapsed
#> 1.CEL                     0.8748
#> 2.CEL                     0.9730
#> 3.CEL                     0.6920
#> 4.CEL                     0.8696
#> 5.CEL                     0.9814
#> 6.CEL                     0.9808
head(subset_results$predictions_5classes)
#> 1.CEL 2.CEL 3.CEL 4.CEL 5.CEL 6.CEL 
#> "Uro" "Mes"  "GU" "Uro" "Uro"  "GU"

# Example 2: Using a metadata subset to the sample IDs of interest
metadata_sub = sjodahl_2017_meta %>% filter(turb_cis == 1)

# Subset the results to the samples in the filtered metadata
subset_results_meta <- get_prediction_subset(
  these_predictions = results,
  these_samples_metadata = metadata_sub
)

# View the subset prediction results
head(subset_results_meta$subtype_scores)
#>           Uro   UroA   UroB   UroC     GU   BaSq    Mes   ScNE
#> 10.CEL 0.9986 0.1270 0.0136 0.8594 0.0014 0.0000 0.0000 0.0000
#> 19.CEL 0.0058     NA     NA     NA 0.0116 0.0996 0.8772 0.0058
#> 21.CEL 0.9896 0.0212 0.9596 0.0192 0.0064 0.0026 0.0006 0.0008
#> 30.CEL 0.0018     NA     NA     NA 0.9974 0.0002 0.0000 0.0006
#> 43.CEL 0.9996 0.0642 0.8204 0.1154 0.0004 0.0000 0.0000 0.0000
#> 48.CEL 0.1608     NA     NA     NA 0.0208 0.8112 0.0040 0.0032
#>        prediction_delta_5_class prediction_delta_7_class
#> 10.CEL                   0.9972                   0.7324
#> 19.CEL                   0.7776                       NA
#> 21.CEL                   0.9832                   0.9384
#> 30.CEL                   0.9956                       NA
#> 43.CEL                   0.9992                   0.7050
#> 48.CEL                   0.6504                       NA
#>        prediction_delta_collapsed
#> 10.CEL                     0.7324
#> 19.CEL                     0.7776
#> 21.CEL                     0.9384
#> 30.CEL                     0.9956
#> 43.CEL                     0.7050
#> 48.CEL                     0.6504

Example: Subsetting by Metadata

Alternatively, you can subset your results using a metadata data frame. This is useful if you have filtered your metadata for a specific group (e.g., only tumor samples, or only a certain clinical stage):

# Take a subset of the metadata
meta_subset <- head(sjodahl_2017_meta)

# Subset the results using the metadata
subset_results_meta <- get_prediction_subset(
  these_predictions = results,
  these_samples_metadata = meta_subset,
  samples_rownames = FALSE
)

# View the subsetted data
head(subset_results_meta$data)
#>           1.CEL    2.CEL     3.CEL    4.CEL    5.CEL    6.CEL
#> A1CF   4.248274 4.153923  4.186689 4.877813 4.106269 5.278318
#> A2M    8.348800 7.969504 10.755738 8.467495 8.979222 9.520587
#> A2ML1  6.694896 4.442973  8.871067 4.392010 7.685045 4.493648
#> A4GALT 7.255671 6.337239  6.925670 6.239185 6.032115 6.539985
#> A4GNT  3.740418 3.830598  3.999331 3.813662 3.718752 3.567144
#> AAAS   6.837006 7.525639  6.778506 6.658134 7.354926 6.611625

2. Ordering Samples by Proliferation Score with get_sample_order

When visualizing or analyzing your classification results, it’s often helpful to arrange samples in a biologically meaningful order. The get_sample_order function provides a convenient way to sort your samples based on their proliferation score, specifically the late/early cell cycle sugnature ratio. Note, this is the implemented sample order that is shown in the plot_classification_heatmap.

This function is especially useful for downstream plotting, as it returns a vector of sample names ordered by their proliferation status. You can use this order to consistently arrange samples in heatmaps or other visualizations.

Example: Ordering by Late/Early Cell Cycle Signature Ratio

To use get_sample_order, make sure you ran classify_samples with include_data = TRUE so the expression data is available:

# Get the sample order based on late/early ratio (default)
ordered_samples <- get_sample_order(expr_data = results$data)
#>   [1] 158 194 142 171  43  76 235  83 160  31  68 237 232 187  22 130 259 163
#>  [19] 134 245  55 168 131 234  99  47 161  61 137   7  85 236 199  28 264 175
#>  [37] 254 202 266  13  94 184   3 253 231  26  54 164  95 103 178 179 221 223
#>  [55]  73 224 132 113  46  49 102 166 241 112  97 100  41 167 107 249 239  15
#>  [73] 220  91   9   4 114 242  64  36 119  62 233  56 243  29  98 191 246 225
#>  [91] 247 205  63 222 240 206 227 156  14  79  21 252  58 190  65   1 248 145
#> [109] 117 125 151 200 251 101 155 172 215  51 212 165  78  69  77 162  75  20
#> [127] 218  81 229  24 116 244 126 170 108 105 123  60 141 136 256 133  80 111
#> [145] 138  23  19  48 208  93 159 188  72 216  12 217 192  25 209 147 182   5
#> [163] 181 122 110  18 230  92  27 124  86 135 257 228 152  66  71 183 118  10
#> [181] 204  44  50 121  57  37 250 186  40 197 153 115 219 203  89  30 177  90
#> [199]  96 139 143  42 201 144  11 106  70 176 150 260 154   6 169 238 185 193
#> [217] 207 180  87  33 173  16 149 104 262 195  35 127 258 109 129  59 261  32
#> [235]  52 211 213 148 263  82  38 120   2  45  53  84  74 196 140 174 267 146
#> [253]  39  67 265  88  17 210 255 214 189 226 128   8  34 157 198
head(ordered_samples)
#> [1] 158 194 142 171  43  76

# If you want the actual late/early ratio values instead of the order:
late_early_ratios <- get_sample_order(expr_data = results$data, return_this = "late_early")
#>   [1] 158 194 142 171  43  76 235  83 160  31  68 237 232 187  22 130 259 163
#>  [19] 134 245  55 168 131 234  99  47 161  61 137   7  85 236 199  28 264 175
#>  [37] 254 202 266  13  94 184   3 253 231  26  54 164  95 103 178 179 221 223
#>  [55]  73 224 132 113  46  49 102 166 241 112  97 100  41 167 107 249 239  15
#>  [73] 220  91   9   4 114 242  64  36 119  62 233  56 243  29  98 191 246 225
#>  [91] 247 205  63 222 240 206 227 156  14  79  21 252  58 190  65   1 248 145
#> [109] 117 125 151 200 251 101 155 172 215  51 212 165  78  69  77 162  75  20
#> [127] 218  81 229  24 116 244 126 170 108 105 123  60 141 136 256 133  80 111
#> [145] 138  23  19  48 208  93 159 188  72 216  12 217 192  25 209 147 182   5
#> [163] 181 122 110  18 230  92  27 124  86 135 257 228 152  66  71 183 118  10
#> [181] 204  44  50 121  57  37 250 186  40 197 153 115 219 203  89  30 177  90
#> [199]  96 139 143  42 201 144  11 106  70 176 150 260 154   6 169 238 185 193
#> [217] 207 180  87  33 173  16 149 104 262 195  35 127 258 109 129  59 261  32
#> [235]  52 211 213 148 263  82  38 120   2  45  53  84  74 196 140 174 267 146
#> [253]  39  67 265  88  17 210 255 214 189 226 128   8  34 157 198
head(late_early_ratios)
#>       late_early_ratio
#> 1.CEL      -0.85912360
#> 2.CEL       0.08838817
#> 3.CEL      -1.35966918
#> 4.CEL      -1.14506690
#> 5.CEL      -0.50815862
#> 6.CEL      -0.18543936

This ordering can be used directly in plotting functions or to structure your data for further analysis, ensuring that samples are consistently arranged by their proliferation characteristics.

3. Summarizing Subtype Metrics with get_subtype_metrics

Understanding how clinical or experimental variables are distributed across molecular subtypes is a key part of downstream analysis. The get_subtype_metrics function makes it easy to tabulate and summarize metadata variables (such as sex, stage, survival events, or other annotations) by subtype classification.

This function works by matching sample IDs between your metadata and prediction results, then counting the number of samples for each subtype and each level of your chosen metadata variable. You can focus on a specific value (e.g., only males, or only events) or get a full breakdown for all levels.

Example: Counting Events by Subtype

Suppose you want to see how many overall survival events occurred in each subtype:

# Run the classifier if not already done
results <- classify_samples(
  this_data = sjodahl_2017,
  include_data = TRUE,
  verbose = FALSE
)

# Tabulate survival events (e.g., "surv_os_event" column)
metrics_events <- get_subtype_metrics(
  these_predictions = results,
  this_metadata = sjodahl_2017_meta,
  this_metadata_variable = "surv_os_event",
  factor_level = 1
)

#set subtype order for table output
desired_order <- c("Uro", "GU", "BaSq", "Mes", "ScNE")

#print table
metrics_events %>%
  mutate(prediction = factor(prediction, levels = desired_order)) %>%
  arrange(prediction) %>%
  knitr::kable()
prediction total_samples surv_os_event_1
Uro 121 58
GU 54 29
BaSq 56 30
Mes 16 11
ScNE 20 9

Example: Summarizing Sex Distribution

You can also use this function to summarize categorical variables, such as sex:

metrics_gender <- get_subtype_metrics(
  these_predictions = results,
  this_metadata = sjodahl_2017_meta,
  this_metadata_variable = "gender",
  factor_level = "Male"
)


desired_order <- c("Uro", "GU", "BaSq", "Mes", "ScNE")

metrics_gender %>%
  mutate(prediction = factor(prediction, levels = desired_order)) %>%
  arrange(prediction) %>%
  knitr::kable()
prediction total_samples gender_Male
Uro 121 95
GU 54 42
BaSq 56 41
Mes 16 13
ScNE 20 14

This approach helps you quickly assess the distribution of key variables across subtypes, supporting both quality control and hypothesis generation in your analyses.