ras_scan: Run the RAS Scan (Repetition Screening Loop)

View source: R/pipeline.R

ras_scanR Documentation

Run the RAS Scan (Repetition Screening Loop)

Description

Computes the averaged -\log_{10}(p)-value profile over num_rep independent 50/50 train/hold-out splits.

Usage

ras_scan(
  geno,
  phenotype,
  covariates,
  covariate_cols,
  is_continuous,
  num_rep = 5,
  skip1 = 10,
  skip2 = 20,
  chrom = 1,
  save_dir = file.path(tempdir(), "RAS"),
  min_window_size = 5,
  max_window_size = 100,
  scan_test = c("glm", "score")
)

Arguments

geno

Matrix of genotype dosages (n samples \times N variants). Rows must be aligned with phenotype and covariates.

phenotype

Numeric vector of length n. Raw phenotype values. For continuous traits the function residualises covariates from the training phenotype internally each repetition; pass the original un-residualised values here.

covariates

Data frame with n rows aligned with geno. Must contain all columns named in covariate_cols; additional columns (e.g., an ID column) are silently ignored.

covariate_cols

Character vector of column names in covariates to include in the regression models.

is_continuous

Logical. TRUE for quantitative traits, FALSE for binary (case/control) traits.

num_rep

Integer. Number of independent 50/50 splits to average over. Default 5.

skip1

Integer. Step size for the primary SNP position grid (seq(1, N, by = skip1)). Default 10.

skip2

Integer. Sub-step used to grow the scan window at each grid position. Default 20.

chrom

Integer. Chromosome number used in saved file names. Default 1.

save_dir

Character. Directory for intermediate .rds output files; created recursively if it does not exist. Defaults to a per-session subdirectory of tempdir(); set an explicit path to keep the outputs.

min_window_size

Integer. Minimum scan window half-size passed to screen_forward_max_region. Default 5.

max_window_size

Integer. Maximum scan window half-size passed to screen_forward_max_region. Default 100.

scan_test

Character. Per-window test for binary traits, passed to screen_forward_max_region. "glm" (default) fits a full logistic model per window (Wald p-value); "score" fits the null logistic model once and uses a Rao score test per window (asymptotically equivalent, much faster at scale). Has no effect for continuous traits.

Details

For each of the num_rep repetitions the function performs three steps:

  1. GWAS weights. A fresh 50/50 random split of all n samples is drawn. compute_gwas_weights fits a per-SNP regression on the training half and returns an N \times 4 coefficient matrix; the first column (effect-size estimates) is used as PGS weights.

  2. PGS contribution matrix. compute_pgs_matrix multiplies each hold-out individual's dosage vector by the per-SNP weights, producing an n_{\text{holdout}} \times N matrix of weighted contributions.

  3. Forward scan. screen_forward_max_region slides an expanding window across the genome. At each position it accumulates weighted dosages, regresses them against the hold-out phenotype, and records the minimum p-value over window sizes in [min_window_size, max_window_size]. The result is a vector of -\log_{10}(p) values on the grid seq(1, N, by = skip1).

The -\log_{10}(p) vectors from all repetitions are summed and divided by num_rep to form the final profile.

For continuous traits (is_continuous = TRUE), covariates are residualised from the training phenotype using only training individuals before the GWAS step, so no hold-out information leaks into the effect-size estimates. The residualisation is repeated from the original phenotype vector each repetition. For binary traits (is_continuous = FALSE) the raw phenotype is passed directly to the GWAS step, and the scan step fits a logistic model via glm(family = binomial()).

After each repetition the large intermediate matrices (coef.mat, pgs.mat) are removed from the R session and release_memory is called to return free heap pages to the OS. On Linux/glibc this calls malloc_trim(0) and can substantially reduce RSS between repetitions.

Value

Invisibly returns a named list with two elements:

x

Integer vector of length \lceil N / \texttt{skip1} \rceil. The SNP position index grid seq(1, N, by = skip1).

y

Numeric vector, same length as x. Averaged -\log_{10}(p)-value profile across all num_rep repetitions.

The following .rds files are written to save_dir:

chr-<chrom>_coef_mat-<rep>.rds

The N \times 4 GWAS coefficient matrix from repetition rep.

mean_p_values_chr<chrom>_reps1-<num_rep>.rds

The averaged -\log_{10}(p) vector y.

See Also

ras for a single-call wrapper that also runs changepoint detection and plotting. compute_gwas_weights, compute_pgs_matrix, screen_forward_max_region for the constituent steps. ras_detect, ras_validate for downstream changepoint analysis. ras_memory to check memory requirements before loading large genotype data. release_memory for OS-level heap reclamation.

Examples


set.seed(42)
n_samp <- 80; n_snp <- 60
geno <- matrix(
  sample(0:2, n_samp * n_snp, replace = TRUE, prob = c(0.6, 0.3, 0.1)),
  nrow = n_samp, ncol = n_snp)
pheno <- rnorm(n_samp)
cov_df <- data.frame(age = rnorm(n_samp), sex = rbinom(n_samp, 1, 0.5))
cov_df$age_squared <- cov_df$age^2
cov_df$age_sex     <- cov_df$age * cov_df$sex
for (i in 1:10) cov_df[[paste0("pc", i)]] <- rnorm(n_samp)

scan <- ras_scan(
  geno            = geno,
  phenotype       = pheno,
  covariates      = cov_df,
  covariate_cols  = c("age", "sex", "age_squared", "age_sex",
                      paste0("pc", 1:10)),
  is_continuous   = TRUE,
  num_rep         = 2,
  skip1           = 5,
  skip2           = 5,
  min_window_size = 2,
  max_window_size = 10,
  chrom           = 1,
  save_dir        = tempdir()
)
plot(scan$x, scan$y, type = "l",
     xlab = "SNP index", ylab = expression(-log[10](p)),
     main = "RAS scan profile")


RAS documentation built on July 24, 2026, 5:06 p.m.