| name | bio-single-cell-batch-integration |
| description | Integrate multiple scRNA-seq samples/batches using Harmony, scVI, Seurat anchors, and fastMNN. Remove technical variation while preserving biological differences. Use when integrating multiple scRNA-seq batches or datasets. |
| tool_type | mixed |
| primary_tool | Harmony |
Batch Integration
Integrate multiple scRNA-seq datasets to remove batch effects while preserving biological variation.
Tool Comparison
| Tool | Speed | Scalability | Best For |
|---|
| Harmony | Fast | Good | Quick integration, most use cases |
| scVI | Moderate | Excellent | Large datasets, deep learning |
| Seurat CCA/RPCA | Moderate | Good | Conserved biology across batches |
| fastMNN | Fast | Good | MNN-based correction |
Harmony (R/Python)
R with Seurat
library(Seurat)
library(harmony)
merged <- merge(sample1, y = list(sample2, sample3), add.cell.ids = c('S1', 'S2', 'S3'))
merged <- NormalizeData(merged)
merged <- FindVariableFeatures(merged)
merged <- ScaleData(merged)
merged <- RunPCA(merged)
merged <- RunHarmony(merged, group.by.vars = 'orig.ident', dims.use = 1:30)
merged <- RunUMAP(merged, reduction = 'harmony', dims = 1:30)
merged <- FindNeighbors(merged, reduction = 'harmony', dims = 1:30)
merged <- FindClusters(merged, resolution = 0.5)
Multiple Batch Variables
merged <- RunHarmony(merged, group.by.vars = c('sample', 'technology'),
dims.use = 1:30, max.iter.harmony = 20)
Python with Scanpy
import scanpy as sc
import scanpy.external as sce
adata = sc.read_h5ad('merged.h5ad')
sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)
sc.pp.highly_variable_genes(adata, batch_key='batch')
adata = adata[:, adata.var.highly_variable]
sc.pp.scale(adata)
sc.tl.pca(adata)
sce.pp.harmony_integrate(adata, key='batch')
sc.pp.neighbors(adata, use_rep='X_pca_harmony')
sc.tl.umap(adata)
sc.tl.leiden(adata)
scVI (Python)
Deep learning-based integration for large datasets.
import scvi
import scanpy as sc
adata = sc.read_h5ad('merged.h5ad')
scvi.model.SCVI.setup_anndata(adata, batch_key='batch')
model = scvi.model.SCVI(adata, n_latent=30, n_layers=2)
model.train(max_epochs=100, early_stopping=True)
adata.obsm['X_scVI'] = model.get_latent_representation()
sc.pp.neighbors(adata, use_rep='X_scVI')
sc.tl.umap(adata)
sc.tl.leiden(adata)
scVI with Covariates
scvi.model.SCVI.setup_anndata(adata, batch_key='batch',
continuous_covariate_keys=['percent_mito'])
model = scvi.model.SCVI(adata, n_latent=30)
model.train()
scANVI (with cell type labels)
scvi.model.SCANVI.setup_anndata(adata, batch_key='batch', labels_key='cell_type',
unlabeled_category='Unknown')
model = scvi.model.SCANVI(adata, n_latent=30)
model.train(max_epochs=100)
adata.obs['predicted_type'] = model.predict()
Seurat Integration (R)
CCA-based Integration
library(Seurat)
obj_list <- SplitObject(merged, split.by = 'batch')
obj_list <- lapply(obj_list, function(x) {
x <- NormalizeData(x)
x <- FindVariableFeatures(x, selection.method = 'vst', nfeatures = 2000)
return(x)
})
anchors <- FindIntegrationAnchors(object.list = obj_list, dims = 1:30)
integrated <- IntegrateData(anchorset = anchors, dims = 1:30)
DefaultAssayintegrated
integrated ScaleDataintegrated
integrated RunPCAintegrated
integrated RunUMAPintegrated dims
RPCA (Faster for Large Datasets)
anchors <- FindIntegrationAnchors(object.list = obj_list, dims = 1:30,
reduction = 'rpca')
integrated <- IntegrateData(anchorset = anchors, dims = 1:30)
Seurat v5 Integration
merged[['RNA']] <- split(merged[['RNA']], f = merged$batch)
merged <- IntegrateLayers(merged, method = CCAIntegration, orig.reduction = 'pca',
new.reduction = 'integrated.cca')
merged <- JoinLayers(merged)
fastMNN (R)
library(batchelor)
library(SingleCellExperiment)
sce <- as.SingleCellExperiment(merged)
corrected <- fastMNN(sce, batch = sce$batch, d = 30, k = 20)
reducedDim(sce, 'MNN') <- reducedDim(corrected, 'corrected')
Evaluate Integration
Mixing Metrics (R)
library(lisi)
lisi_scores <- compute_lisi(Embeddings(merged, 'harmony'),
merged@meta.data, c('batch', 'cell_type'))
mean(lisi_scores$batch)
mean(lisi_scores$cell_type)
Visual Assessment
DimPlot(merged, reduction = 'pca', group.by = 'batch')
DimPlot(merged, reduction = 'pca', group.by = 'cell_type')
DimPlot(merged, reduction = 'harmony', group.by = 'batch')
DimPlot(merged, reduction = 'harmony', group.by = 'cell_type')
Silhouette Score (Python)
from sklearn.metrics import silhouette_score
batch_sil = silhouette_score(adata.obsm['X_scVI'], adata.obs['batch'])
celltype_sil = silhouette_score(adata.obsm['X_scVI'], adata.obs['cell_type'])
Complete Workflow
library(Seurat)
library(harmony)
samples <- list.files('data/', pattern = '*.h5', full.names = TRUE)
obj_list <- lapply(samples, Read10X_h5)
names(obj_list) <- gsub('.h5', '', basename(samples))
merged <- merge(CreateSeuratObject(obj_list[[1]], project = names(obj_list)[1]),
y = lapply(2:length(obj_list), functioni
CreateSeuratObjectobj_listi project obj_listi
merged PercentageFeatureSetmerged pattern
merged subsetmerged nFeature_RNA nFeature_RNA percent.mt
merged NormalizeDatamerged
merged FindVariableFeaturesmerged nfeatures
merged ScaleDatamerged vars.to.regress
merged RunPCAmerged npcs
merged RunHarmonymerged group.by.vars
merged RunUMAPmerged reduction dims
merged FindNeighborsmerged reduction dims
merged FindClustersmerged resolution
DimPlotmerged group.by ncol
When to Use Each Method
| Scenario | Recommended |
|---|
| Quick integration, most cases | Harmony |
| Large datasets (>500k cells) | scVI or Harmony |
| Strong batch effects | scVI |
| Reference mapping | Seurat anchors or scANVI |
| Preserving rare populations | fastMNN |
Related Skills
- single-cell/preprocessing - QC before integration
- single-cell/clustering - Clustering after integration
- single-cell/cell-annotation - Annotation after integration
- single-cell/multimodal-integration - Multi-omic integration (different from batch)