scPharm employs a multi-step computational pipeline to identify pharmacological subpopulations at single-cell resolution. This vignette describes the underlying algorithms and statistical methods.
scPharm analytical workflow
For tissue samples containing mixed tumor and normal cells, scPharm employs an integrated CopyKAT-based algorithm to distinguish malignant cells.
The CNV detection follows these steps:
For a gene \(g\) at genomic position \(p\), the relative copy number is estimated as:
\[\text{CNV}_{g} = \log_2\left(\frac{E_g^{tumor}}{E_g^{baseline}} + 1\right)\]
where \(E_g\) represents the normalized expression level.
CNV profile across chromosomes
MCA is used for dimensionality reduction, preserving the correspondence between genes and cells.
Unlike PCA which assumes continuous data, MCA is designed for categorical/count data and provides:
Given a normalized expression matrix \(\mathbf{X}\) with \(n\) cells and \(p\) genes:
MCA embedding showing cell-gene correspondence
scPharm implements MCA using RcppArmadillo for computational efficiency:
// Simplified MCA computation (actual implementation in src/mca.cpp)
arma::mat SparseMCAStep1(arma::sp_mat& X) {
// Column sums and total
arma::vec col_sum = arma::vec(arma::sum(X, 0).t());
double total = arma::accu(X);
// Compute standardized residuals
arma::mat Z = compute_residuals(X, col_sum, total);
return Z;
}For each cell, we extract a gene signature based on its position in MCA space.
The association between cell \(i\) and gene \(j\) is computed as:
\[d_{ij} = \sqrt{\sum_{k=1}^{K} (F_{ik} - G_{jk})^2}\]
where \(K\) is the number of MCA components.
For each cell, the top \(n\) genes (by distance) form its identity signature:
\[\text{Signature}_i = \{g_1, g_2, ..., g_n\} \text{ where } d_{i,g_1} < d_{i,g_2} < ... < d_{i,g_n}\]
GSEA quantifies the enrichment of drug sensitivity genes within each cell’s signature.
GSEA running enrichment score
Drug sensitivity gene sets are derived from GDSC2 database:
Cell NES values are modeled as a mixture of Gaussian distributions:
\[P(\text{NES}) = \pi_S \cdot \mathcal{N}(\mu_S, \sigma_S^2) + \pi_R \cdot \mathcal{N}(\mu_R, \sigma_R^2) + \pi_O \cdot \mathcal{N}(\mu_O, \sigma_O^2)\]
Gaussian Mixture Model for cell classification
Cells are classified based on NES thresholds:
| Classification | Criterion |
|---|---|
| Sensitive | NES > threshold_s (default: 1.0) |
| Resistant | NES < threshold_r (default: -1.0) |
| Other | threshold_r ≤ NES ≤ threshold_s |
\[Dr = 1 - \left(\alpha \cdot \frac{n_S}{n_{tumor}} + \beta \cdot \overline{\text{NES}}_S\right)\]
where: - \(n_S\) = number of sensitive cells - \(n_{tumor}\) = total tumor cells - \(\overline{\text{NES}}_S\) = mean NES of sensitive cells - \(\alpha, \beta\) = weighting parameters
Interpretation: Lower Dr indicates better drug candidate.
\[Dse = \frac{n_{S,adj}}{n_{adj}} \cdot \overline{\text{NES}}_{S,adj}\]
where subscript \(adj\) denotes adjacent (non-tumor) cells.
Interpretation: Higher Dse indicates more potential side effects.
| Step | Complexity | Notes |
|---|---|---|
| CNV Detection | O(n × g) | n = cells, g = genes |
| MCA | O(min(n,g)³) | SVD computation |
| Cell Signatures | O(n × k) | k = MCA components |
| GSEA | O(n × d × g) | d = drugs |
| Classification | O(n × d) | GMM fitting |
Gao R, et al. (2021). Delineating copy number and clonal substructure in human tumors from single-cell transcriptomes. Nature Biotechnology.
Subramanian A, et al. (2005). Gene set enrichment analysis: A knowledge-based approach. PNAS.
Yang W, et al. (2013). Genomics of Drug Sensitivity in Cancer (GDSC). Nucleic Acids Research.
Cortal A, et al. (2021). Gene signature extraction and cell identity recognition at the single-cell level with CelliD. Nature Biotechnology.
sessionInfo()
#> R version 4.5.3 (2026-03-11)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.4 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.26.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] dplyr_1.2.1 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.2.0
#> [5] xfun_0.57 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.5.3 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.5.3 RColorBrewer_1.1-3 pkgconfig_2.0.3 farver_2.1.2
#> [29] digest_0.6.39 R6_2.6.1 tidyselect_1.2.1 pillar_1.11.1
#> [33] magrittr_2.0.5 bslib_0.10.0 withr_3.0.2 tools_4.5.3
#> [37] gtable_0.3.6 cachem_1.1.0