Algorithm and Methodology

Overview

scPAS identifies phenotype-associated cell subpopulations through a multi-step computational pipeline that integrates bulk and single-cell RNA-seq data.

scPAS Workflow Overview

scPAS Workflow Overview

Mathematical Framework

Problem Formulation

Given:

  • Bulk expression matrix \(\mathbf{X} \in \mathbb{R}^{n \times p}\) (n samples × p genes)
  • Phenotype vector \(\mathbf{y}\) (continuous, binary, or survival)
  • Single-cell expression matrix \(\mathbf{S} \in \mathbb{R}^{m \times p}\) (m cells × p genes)

The goal is to find gene weights \(\boldsymbol{\beta}\) that associate gene expression with phenotype, then apply these weights to single-cell data to compute per-cell risk scores.

Network-Regularized Sparse Regression

scPAS uses the APML0 (Augmented and Penalized Minimization L0) algorithm with network regularization:

\[ \hat{\boldsymbol{\beta}} = \arg\min_{\boldsymbol{\beta}} \left\{ L(\boldsymbol{\beta}; \mathbf{X}, \mathbf{y}) + \lambda_1 \|\boldsymbol{\beta}\|_1 + \lambda_2 \boldsymbol{\beta}^T \mathbf{L} \boldsymbol{\beta} \right\} \]

Where:

  • \(L(\boldsymbol{\beta})\) is the loss function (depends on phenotype type)
  • \(\lambda_1 \|\boldsymbol{\beta}\|_1\) is the L1 penalty (LASSO) for sparsity
  • \(\lambda_2 \boldsymbol{\beta}^T \mathbf{L} \boldsymbol{\beta}\) is the Laplacian penalty for network regularization
  • \(\mathbf{L}\) is the Laplacian matrix of the gene-gene network
Effect of Network Regularization

Effect of Network Regularization

Loss Functions by Phenotype Type

Gaussian Family (Continuous)

For continuous phenotypes, we minimize the squared error:

\[ L(\boldsymbol{\beta}) = \frac{1}{2n} \sum_{i=1}^{n} (y_i - \mathbf{x}_i^T \boldsymbol{\beta})^2 \]

Binomial Family (Binary)

For binary outcomes, we use logistic regression:

\[ L(\boldsymbol{\beta}) = -\frac{1}{n} \sum_{i=1}^{n} \left[ y_i \log(p_i) + (1-y_i) \log(1-p_i) \right] \]

where \(p_i = \frac{1}{1 + e^{-\mathbf{x}_i^T \boldsymbol{\beta}}}\)

Cox Family (Survival)

For time-to-event data, we minimize the negative partial log-likelihood:

\[ L(\boldsymbol{\beta}) = -\frac{1}{n} \sum_{i: \delta_i = 1} \left[ \mathbf{x}_i^T \boldsymbol{\beta} - \log \sum_{j \in R(t_i)} e^{\mathbf{x}_j^T \boldsymbol{\beta}} \right] \]

where \(R(t_i)\) is the risk set at time \(t_i\) and \(\delta_i\) is the event indicator.

Gene Network Construction

Shared Nearest Neighbor (SNN) Network

scPAS constructs a gene-gene similarity network from single-cell data using the SNN algorithm:

SNN Network Construction

SNN Network Construction

The network construction process:

  1. Calculate gene correlations from single-cell expression
  2. Find k-nearest neighbors for each gene
  3. Compute SNN similarity based on shared neighbors
  4. Threshold to create binary adjacency matrix

Risk Score Calculation

Per-Cell Risk Score

Once the model is trained, the risk score for each cell is computed as:

\[ RS_j = \sum_{g=1}^{p} \hat{\beta}_g \cdot \tilde{S}_{jg} \]

where:

  • \(RS_j\) is the risk score for cell \(j\)
  • \(\hat{\beta}_g\) is the learned coefficient for gene \(g\)
  • \(\tilde{S}_{jg}\) is the standardized expression of gene \(g\) in cell \(j\)
Risk Score Distribution

Risk Score Distribution

Normalized Risk Score

The raw risk score is converted to a Z-statistic:

\[ NRS_j = \frac{RS_j - \mu_{bg}}{\sigma_{bg}} \]

where \(\mu_{bg}\) and \(\sigma_{bg}\) are the mean and standard deviation of the background distribution estimated from permutation.

Statistical Significance Testing

Permutation Test

To assess significance, scPAS performs a permutation test:

Permutation Test Principle

Permutation Test Principle

Algorithm:

  1. For each permutation \(b = 1, \ldots, B\):
    • Randomly shuffle the gene coefficients \(\boldsymbol{\beta}\)
    • Calculate permuted risk scores for all cells
  2. Compute two-tailed P-value:

\[ p_j = \frac{1}{B} \sum_{b=1}^{B} \mathbb{I}(|RS_j^{(b)}| \geq |RS_j|) \]

FDR Correction

Multiple testing correction using Benjamini-Hochberg procedure:

\[ FDR_j = \min\left(1, \frac{p_j \cdot m}{\text{rank}(p_j)}\right) \]

where \(m\) is the total number of cells.

Cell Classification

Cells are classified based on:

  1. Statistical significance: FDR < threshold (default 0.05)
  2. Direction of association: Sign of normalized risk score
Category Criteria
scPAS+ FDR < 0.05 AND NRS > 0
scPAS- FDR < 0.05 AND NRS < 0
0 FDR ≥ 0.05
Cell Classification Scheme

Cell Classification Scheme

Implementation Details

Sparse Matrix Operations

scPAS uses efficient sparse matrix operations for large-scale single-cell data:

# Efficient correlation calculation for sparse matrices
sparse.cor <- function(x) {
  # Uses optimized algorithm that avoids dense conversion
  # Handles numerical precision issues
  # Returns proper correlation matrix
}

# Efficient row scaling
sparse_row_scale <- function(x, center = TRUE, scale = TRUE) {
  # Row-wise standardization
  # Preserves sparsity when only scaling (not centering)
}

Parallel Computing

For large permutation counts, scPAS supports parallel processing:

result <- scPAS(
  bulk_dataset = bulk_data,
  sc_dataset = sc_obj,
  phenotype = phenotype,
  permutation_times = 5000,
  n_cores = 4  # Use 4 CPU cores
)

References

  1. Original scPAS Paper: Xie A, et al. (2024). scPAS: single-cell phenotype-associated subpopulation identifier. Briefings in Bioinformatics, 26(1):bbae655.

  2. Network-Regularized Regression: Zou H, Hastie T. (2005). Regularization and variable selection via the elastic net. JRSS-B, 67(2):301-320.

  3. Permutation Testing: Westfall PH, Young SS. (1993). Resampling-Based Multiple Testing. Wiley.

Session Information

sessionInfo()
#> R version 4.6.1 (2026-06-24)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 26.04 LTS
#> 
#> Matrix products: default
#> BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.32.so;  LAPACK version 3.12.0
#> 
#> locale:
#>  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
#>  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
#>  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
#>  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
#>  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
#> 
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] Matrix_1.7-5   ggplot2_4.0.3  rmarkdown_2.31
#> 
#> loaded via a namespace (and not attached):
#>  [1] vctrs_0.7.3        cli_3.6.6          knitr_1.51         rlang_1.3.0       
#>  [5] xfun_0.60          otel_0.2.0         generics_0.1.4     S7_0.2.2          
#>  [9] jsonlite_2.0.0     labeling_0.4.3     glue_1.8.1         buildtools_1.0.0  
#> [13] htmltools_0.5.9    maketools_1.3.2    sys_3.4.3          sass_0.4.10       
#> [17] scales_1.4.0       grid_4.6.1         tibble_3.3.1       evaluate_1.0.5    
#> [21] jquerylib_0.1.4    fastmap_1.2.0      yaml_2.3.12        lifecycle_1.0.5   
#> [25] compiler_4.6.1     dplyr_1.2.1        RColorBrewer_1.1-3 pkgconfig_2.0.3   
#> [29] lattice_0.22-9     farver_2.1.2       digest_0.6.39      R6_2.6.1          
#> [33] tidyselect_1.2.1   pillar_1.11.1      magrittr_2.0.5     bslib_0.11.0      
#> [37] withr_3.0.3        tools_4.6.1        gtable_0.3.6       cachem_1.1.0