Skip to content

Latest commit

 

History

History
144 lines (111 loc) · 9.95 KB

File metadata and controls

144 lines (111 loc) · 9.95 KB

acsimdata — Project Context for Claude

Purpose

R package for generating simulated antigenic cartography data. Used to create reproducible test datasets for benchmarking Racmacs methods and evaluating the impact of noise, missing data, and surveillance structure on map quality.

Install from GitHub: devtools::install_github("drserajames/acsimdata")


Package structure

R/
  map_maker.R           # Coordinate and distance generation
  dist_to_titre.R       # Distance → HI titre conversion
  add_noise.R           # Noise injection
  missing_titres.R      # Random missing data
  missing_titres_ext.R  # Structured missing data (threshold, informed, block, by_distance)
  sim_surv_tables.R     # Multi-period surveillance table simulation
tests/testthat/         # One test file per R file
man/                    # Rd files — generated by devtools::document(), do not edit
NAMESPACE               # Generated by devtools::document(), do not edit

Typical pipeline

# 1. Generate map coordinates and distances
m <- map_maker_random(n_antigens, n_sera, range, seed = 1)
# m$antigen_coord  — n_ag × dimensions matrix, rownames "AG1"..."AGn"
# m$sera_coord     — n_sr × dimensions matrix, rownames "SR1"..."SRn"
# m$dist           — full (AG+SR) × (AG+SR) distance matrix
# m$slim_dist      — n_ag × n_sr submatrix

# 2. Add noise to distances
noisy <- add_noise(m$dist)
# noisy$noise_dist_table — distances + titre_noise + antigen_noise + serum_noise

# 3. Convert distances to HI titre values
ti <- dist_to_hi_titre(noisy$noise_dist_table)
# ti$round_titre    — numeric matrix (10, 20, 40, ...)
# ti$lessthan_titre — character matrix ("10", "<10", ...) — main downstream format

# 4. Introduce missing data (one or more mechanisms)
miss <- miss_titres_random(ti$lessthan_titre, proportion = 0.2)
# miss$rm_titre — character matrix with "*" for missing cells → pass to Racmacs

Exported functions

Map generation

Function Description
map_maker_random(n_antigens, n_sera, range, ...) Random uniform coordinates in [0, range]^dimensions
map_maker_coord(n_antigens, n_sera, true_ag_coord, true_sr_coord=true_ag_coord, ...) Cluster-based coordinates around specified centres. If true_ag_coord and true_sr_coord have different numbers of rows, the shorter is recycled to match the longer with a warning.

Distance → titre conversion

Function Description
dist_to_hi_titre(dists, base=2, divisor=10, max_log_titre=9, min_log_titre=0) Converts distance matrix to HI-like titres. Returns round_titre (numeric), lessthan_titre (character with "<X" floor), lessthanhack_titre (numeric floor substitute)
noise_dist_to_hi_titre(noise_dists, ...) Wrapper that converts both true and noisy distances

Noise

Function Description
add_noise(dists, ...) Three-component noise: per-titre (rnorm), per-antigen (rnorm), per-serum (runif). Each component is a configurable distribution
add_noise_targeted(dists, antigen, serum, ...) Noise on a single cell, entire antigen row, or entire serum column

Missing data — random

Function Description
miss_titres_random(titre, proportion, keep_homologous=TRUE) Uniform random removal of proportion of titres

Missing data — structured

All structured missing functions return at minimum: full_titre, rm_titre, rm_ind, rm_ind_arr, params. All accept keep_homologous=TRUE to protect homologous (diagonal) pairs.

Function Mechanism
miss_titres_threshold(titre, threshold, keep_homologous=TRUE) Deterministic: titres strictly below threshold (raw HI units) become "*". Handles numeric (round_titre) and character (lessthan_titre) input. For "<X" entries: removed when X <= threshold.
miss_titres_informed(titre, midpoint_titre=40, steepness=1, keep_homologous=TRUE, seed) Probabilistic MAR/MNAR: P(missing) = logistic(–steepness × log₂(titre / midpoint_titre)). P=0.5 at midpoint_titre, rising toward 1 as titre falls. Each cell sampled independently.
miss_titres_block(titre, antigens, sera, keep_homologous=TRUE) Deterministic: removes all cells in a rectangular antigen×serum subblock. antigens/sera accept character names or integer indices. Both must be specified.
miss_titres_by_distance(titre, ag_coord, sr_coord, midpoint_dist=3, steepness=1, keep_homologous=TRUE, seed) Probabilistic: P(missing) = logistic(steepness × (dist – midpoint_dist)). Computes pairwise Euclidean distances from coordinate matrices; reorders by rownames if present. Returns dist_matrix in output.
miss_titres_banded(titre, bandwidth, n_sera=NULL, keep_homologous=TRUE) Deterministic banded structure: cells where |row − col| > bandwidth become "*", mimicking surveillance practice where only contemporaneous antigen–serum pairs are tested. Optionally reduces to n_sera columns by dropping the most sparsely-filled sera after banding (ties broken by lower column index). Returns additional fields titre_reduced (banded matrix with dropped columns removed) and dropped_sera (names of dropped columns).

Surveillance simulation

Function Description
sim_surv_tables(n_tables, n_ag_per_table, n_sr_per_table, n_ref_ag=0, n_ref_sr=0, n_ref_ag_overlap=NULL, n_ref_sr_overlap=NULL, ag_drift, ...) Generates sequential HI tables mimicking surveillance data. Each table has two groups: reference antigens/sera (shared across multiple tables) and table-specific antigens/sera (unique to one table). Antigens drift along dimension 1 by ag_drift per period. Returns merged_titre_table, per-table coordinate and membership information.

Simulation from existing maps

Function Description
sim_from_map(map, coord_noise_sd=0, layers=FALSE, noise_params=list(), base=2, divisor=10, max_log_titre=9, min_log_titre=0, seed) Treats the optimised coordinates of a Racmacs acmap as the ground truth and simulates new HI titre data from them. Observed missingness from the real titer table is stamped onto the simulated titres. Optionally adds noise via add_noise() and/or preserves layer structure. Requires Racmacs.

sim_from_map — key details:

  • Extracts agCoords, srCoords, and titerTable from the map; computes slim AG×SR distances internally.
  • coord_noise_sd: Gaussian noise (in antigenic units) added to each coordinate dimension before computing distances. Prevents the source coordinates sitting at the exact titre-space minimum — important for absolute benchmarking. Default 0 (no perturbation).
  • noise_params: named list forwarded to add_noise() (omit dists — injected automatically). Adds measurement noise after distances are computed. Empty list = no noise. The two noise sources are independent.
  • layers = TRUE: additionally calls titerTableLayers(map) and applies each layer's "*" pattern independently; returns sim_titre_layers (named list of matrices). The merged sim_titre is unaffected.
  • max_log_titre: accepts a per-serum vector; pass Racmacs::srColbases(map) to match the original titre scale.
  • Internal AG1/AG2…/SR1/SR2… naming is used for pipeline compatibility; original antigen/serum names are restored in all output matrices.
  • Returns: sim_titre (merged missingness), full_sim_titre (no missingness), sim_titre_layers (NULL or list), observed_titre, dist, noise, ag_coord/sr_coord (perturbed if coord_noise_sd > 0), params.

sim_surv_tables — reference vs table-specific structure:

  • n_ag_per_table / n_sr_per_table: table-specific points, unique to each table. Accept scalar or vector of length n_tables.
  • n_ref_ag / n_ref_sr: reference points shared across multiple tables.
  • n_ref_ag_overlap / n_ref_sr_overlap: how many references carry over between consecutive tables.
    • Default (NULLn_ref_ag): simple case — all references fixed, same set in every table.
    • Set lower: complex/WHO-like case — reference set rotates; n_ref_ag − n_ref_ag_overlap references are replaced each period.
  • In the merged output, antigen indices 1..n_ref_ag (first introduced) are reference; higher indices are table-specific.

CDC H3N2 hi_gp surveillance data characteristics (for parameter guidance):

  • 345 tables; ~55 antigens/table (~38 table-specific, ~17 reference), ~13 sera/table (nearly all reference)
  • ~40 antigens added/dropped per transition; sera change in ~42% of transitions, usually by 1–2 at a time
  • Serum persistence: median 6 tables, long tail (some appear in 250+ tables)

Key conventions

  • Matrix naming: antigens are rows ("AG1", "AG2", ...), sera are columns ("SR1", "SR2", ...). The full distance matrix from map_maker_* has both AG and SR as rows and columns; use $slim_dist for the AG×SR submatrix.
  • Missing value encoding: "*" = not measured (truly absent), "<X" = measured but below detection (censored). Both are standard Racmacs inputs.
  • Titre scale: default base=2, divisor=10 → titres 10, 20, 40, 80, ... (standard HI dilution series). Log₂(titre/10) gives the log-scale used internally.
  • Homologous titres: the diagonal where AG number = SR number. Protected by keep_homologous=TRUE in all missing-data functions; identified by matching the numeric suffix in "AGn"/"SRn" names.
  • Seeds: pass seed for reproducibility in any stochastic function; omitted seeds are sampled randomly and stored in $params$seed.

Development

devtools::document()   # regenerate NAMESPACE and man/ from roxygen2 tags
devtools::test()       # run all tests (372 as of June 2026)
devtools::check()      # full R CMD check

NAMESPACE and man/ are fully generated — never edit them directly. All new functions need #' @export in their roxygen block and a corresponding test file in tests/testthat/.

Internal helper functions (not exported) are prefixed with . (e.g. .homologous_ind, .parse_titre_numeric in missing_titres_ext.R).