Build the (sample_id, Y, X, trait, ...) bundle that fit_null_model / marginal_scan and the GLOW SNV-set pipeline consume, by merging three sources onto a single GDS sample order: a raw outcome vector, an external phenotype/covariate table, and (optionally) a principal-component matrix. Cohort-specific column names and recoding rules are passed as arguments; the file I/O (opening the GDS, reading the CSV / PCs) is the caller's responsibility, so this function is pure and testable.

This is the packaged form of the per-cohort "prepare pheno-covariates" step. Sample order is anchored to sample_ids (typically the GDS sample order); the returned bundle preserves that order minus any dropped rows.

assemble_pheno_covar(
  sample_ids,
  outcome,
  trait = c("binary", "continuous"),
  pheno = NULL,
  pheno_id_col = NULL,
  covariates = NULL,
  pcs = NULL,
  drop_incomplete = TRUE,
  covar_set = NULL,
  verbose = 1
)

Arguments

sample_ids

Character vector: the sample-order anchor (e.g. a GDS's sample.id). All other sources are aligned to this order.

outcome

A list list(values=, map=) giving the raw outcome values (a vector aligned to sample_ids) and an optional map: a named vector (e.g. c("1"=0L, "2"=1L); unmapped values become NA) or a function function(values) -> Y. If map is NULL, values are used as-is (coerced with as.numeric).

trait

Either "binary" or "continuous" — recorded in the bundle.

pheno

Optional data frame: the external phenotype/covariate table from which covariate columns are drawn. Merged onto sample_ids by pheno_id_col.

pheno_id_col

Name of the column in pheno matching sample_ids (required when covariates draws from pheno).

covariates

Named list defining the covariate (design) columns of X, in order. Each element is either a string (a pheno column name, coerced with as.numeric) or a list list(col=, map=) where map is a named recode vector (unmapped -> NA) or a function. The list names become the X column names.

pcs

Optional list list(scores=, id_col=, cols=) appending PC columns to X: scores is a data frame / matrix of PC scores, cols the PC column names to take, and id_col (optional) a column of scores matched to sample_ids (if NULL, scores rows are assumed already in sample_ids order). The taken cols keep their names in X.

drop_incomplete

If TRUE (default), after dropping NA-outcome samples, drop any remaining sample with an NA in X (complete.cases).

covar_set

Optional label recorded in the bundle (covar_set).

verbose

0 = silent, >=1 = progress messages.

Value

A list with:

sample_id

retained sample IDs (subset of sample_ids, original order)

Y

the outcome for retained samples

X

numeric covariate matrix (covariate columns then PC columns)

trait

"binary" or "continuous"

n_total

length(sample_ids)

n_excluded

n_total minus the number retained

covar_set

the covar_set label

covar_names

colnames(X)

See also

extract_pheno_covar_gds (reads pheno/covar from a GDS node), fit_null_model, marginal_scan

Examples

set.seed(1)
ids <- paste0("S", 1:6)
pheno <- data.frame(
  iid = ids, status = c(2, 1, 2, 1, 2, -9),
  sex = c("F", "M", "F", "M", "F", "F"), age = c(50, 60, 55, 65, 58, 70),
  stringsAsFactors = FALSE)
pcs <- data.frame(iid = ids, PC1 = rnorm(6), PC2 = rnorm(6))
b <- assemble_pheno_covar(
  sample_ids = ids,
  outcome = list(values = pheno$status, map = c("1" = 0L, "2" = 1L)),
  trait = "binary",
  pheno = pheno, pheno_id_col = "iid",
  covariates = list(sex_numeric = list(col = "sex", map = c(F = 1, M = 0)),
                    age = "age"),
  pcs = list(scores = pcs, id_col = "iid", cols = c("PC1", "PC2")),
  covar_set = "demo")
#>   pheno match: 6 / 6 samples
#>   PC match: 6 / 6 samples
#>   valid outcome: 5, missing: 1
#>   final: 5 samples, 4 covariates [sex_numeric, age, PC1, PC2]
str(b)
#> List of 8
#>  $ sample_id  : chr [1:5] "S1" "S2" "S3" "S4" ...
#>  $ Y          : int [1:5] 1 0 1 0 1
#>  $ X          : num [1:5, 1:4] 1 0 1 0 1 50 60 55 65 58 ...
#>   ..- attr(*, "dimnames")=List of 2
#>   .. ..$ : NULL
#>   .. ..$ : chr [1:4] "sex_numeric" "age" "PC1" "PC2"
#>  $ trait      : chr "binary"
#>  $ n_total    : int 6
#>  $ n_excluded : int 1
#>  $ covar_set  : chr "demo"
#>  $ covar_names: chr [1:4] "sex_numeric" "age" "PC1" "PC2"