--- title: "scCertify: Explainable Confidence Scoring for Single-Cell Annotations" author: - name: "Jaya Surya Doddetipalli" package: scCertify output: BiocStyle::html_document: toc: true number_sections: true vignette: > %\VignetteIndexEntry{scCertify: Explainable Confidence Scoring for Single-Cell Annotations} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- # Overview `scCertify` provides an explainable framework for evaluating confidence in single-cell RNA-sequencing cell-type annotations. The package combines several complementary sources of evidence: - marker-gene consistency, - neighborhood agreement, - entropy-based uncertainty, - doublet information, - calibrated confidence scores, and - interpretable confidence classes. `scCertify` supports both `SingleCellExperiment` and Seurat objects. ```{r setup} library(scCertify) library(SingleCellExperiment) library(SummarizedExperiment) library(Seurat) set.seed(42) ``` # Input Data The following example creates a small simulated `SingleCellExperiment` containing count data and predicted cell-type labels. ```{r simulate-data} n_genes <- 50 n_cells <- 40 counts <- matrix( rpois(n_genes * n_cells, lambda = 5), nrow = n_genes, ncol = n_cells, dimnames = list( paste0("Gene", seq_len(n_genes)), paste0("Cell", seq_len(n_cells)) ) ) sce <- SingleCellExperiment( assays = list( counts = counts ) ) colData(sce)$predicted_label <- rep( c("T cell", "B cell"), each = n_cells / 2 ) sce ``` The predicted cell labels are stored in `colData()`. ```{r sce-metadata} head(colData(sce)) ``` # Marker Gene Definitions A marker database is represented as a named list, with one element for each predicted cell type. ```{r marker-list} markers <- list( "T cell" = c("Gene1", "Gene2", "Gene3"), "B cell" = c("Gene4", "Gene5", "Gene6") ) markers ``` # Neighborhood Representation `neighbor_score()` evaluates agreement among nearby cells. For a `SingleCellExperiment`, a suitable low-dimensional representation is required. For this simulated example, a `logcounts` assay is created from a log-transformed count matrix. `marker_score()` requires this assay to be present, and the same log-transformed matrix is also used to calculate PCA. ```{r sce-pca} log_counts <- log1p( assay(sce, "counts") ) assay(sce, "logcounts") <- log_counts pca <- stats::prcomp( t(log_counts), center = TRUE, scale. = TRUE )$x[, seq_len(5), drop = FALSE] reducedDim(sce, "PCA") <- pca dim( reducedDim(sce, "PCA") ) ``` # Marker Consistency Marker consistency evaluates whether cells express genes expected for their predicted identity. `scCertify` uses rank-based enrichment scoring through UCell. ```{r marker-score} marker_scores <- marker_score( sce, markers, label_column = "predicted_label" ) head(marker_scores) ``` The resulting scores provide a cell-level measure of marker consistency. # Neighborhood Agreement The neighborhood score measures whether nearby cells tend to share the same predicted annotation. ```{r neighbor-score} neighbor_scores <- neighbor_score( sce, label_column = "predicted_label" ) head(neighbor_scores) ``` # Entropy-Based Uncertainty `entropy_score()` provides an uncertainty measure based on the distribution of expression values. ```{r entropy-score} entropy_values <- entropy_score( t(assay(sce, "counts")) ) head(entropy_values) ``` The values can be normalized and stored in the cell metadata. ```{r entropy-norm} entropy_norm <- entropy_values / max( entropy_values, na.rm = TRUE ) colData(sce)$entropy_norm <- entropy_norm head(colData(sce)$entropy_norm) ``` # Doublet Information For this simulated example, doublet scores are generated as demonstration metadata. In a real analysis, these values would normally come from a dedicated doublet detection method. ```{r doublet-score} colData(sce)$doublet_score <- runif( ncol(sce), min = 0, max = 1 ) head(colData(sce)$doublet_score) ``` # Cell Certification `cell_certify()` combines marker consistency, neighborhood agreement, entropy-based uncertainty, and doublet information into a calibrated confidence score. ```{r cell-certify} sce <- cell_certify( sce, markers, label_column = "predicted_label" ) head( colData(sce)[, c( "predicted_label", "marker_score", "neighbor_score", "entropy_norm", "doublet_score", "confidence_score", "confidence_class" ) ] ) ``` # Custom Confidence Thresholds Confidence classes can be customized using the `moderate_threshold` and `high_threshold` arguments. ```{r custom-thresholds} sce_custom <- cell_certify( sce, markers, label_column = "predicted_label", moderate_threshold = 0.4, high_threshold = 0.75 ) head( colData(sce_custom)[, c( "confidence_score", "confidence_class" ) ] ) ``` # Explaining Confidence `explain_confidence()` identifies factors that contributed to lower confidence for an individual cell. ```{r explain-confidence} explain_confidence( sce, cell_id = "Cell1" ) ``` `explain_cell()` provides a concise summary containing the predicted label, confidence score, individual evidence components, and interpretation. ```{r explain-cell} explain_cell( sce, cell_id = "Cell1" ) ``` # Seurat Interoperability `scCertify` also supports Seurat objects. The following example demonstrates a complete evaluated Seurat workflow. ```{r seurat-data} seurat_counts <- matrix( rpois(2000, lambda = 5), nrow = 100, ncol = 20, dimnames = list( paste0("Gene", seq_len(100)), paste0("Cell", seq_len(20)) ) ) seurat_object <- Seurat::CreateSeuratObject( counts = seurat_counts ) seurat_object$predicted_label <- rep( c("T cell", "B cell"), each = 10 ) seurat_object$entropy_norm <- runif( ncol(seurat_object) ) seurat_object$doublet_score <- runif( ncol(seurat_object) ) seurat_object ``` The Seurat object is processed using its standard normalization and PCA workflow. ```{r seurat-preprocessing} seurat_object <- Seurat::NormalizeData( seurat_object, verbose = FALSE ) seurat_object <- Seurat::FindVariableFeatures( seurat_object, verbose = FALSE ) seurat_object <- Seurat::ScaleData( seurat_object, verbose = FALSE ) seurat_object <- Seurat::RunPCA( seurat_object, npcs = 10, verbose = FALSE ) seurat_object ``` The same marker definitions can then be used with `scCertify`. ```{r seurat-certify} seurat_object <- cell_certify( seurat_object, markers, label_column = "predicted_label" ) head( seurat_object[[ c( "predicted_label", "marker_score", "neighbor_score", "entropy_norm", "doublet_score", "confidence_score", "confidence_class" ) ]] ) ``` The resulting confidence information is stored directly in the Seurat metadata. ```{r seurat-explain} explain_confidence( seurat_object, cell_id = "Cell1" ) explain_cell( seurat_object, cell_id = "Cell1" ) ``` # Summary This vignette demonstrates the complete `scCertify` workflow for both `SingleCellExperiment` and Seurat objects. The workflow consists of: 1. creating or loading an annotated single-cell object, 2. supplying marker genes, 3. calculating marker consistency, 4. evaluating neighborhood agreement, 5. estimating entropy-based uncertainty, 6. incorporating doublet information, 7. calculating calibrated confidence scores, 8. assigning confidence classes, and 9. explaining confidence for individual cells. Because all examples in this vignette are evaluated, the document also provides a continuously tested demonstration that the documented workflow remains functional with the package dependencies used by `scCertify`. # Session Information ```{r session-info} sessionInfo() ```