bHIVE is an R/Bioconductor package that implements a modular Artificial Immune System (AIS) for clustering and classification of high-dimensional data such as mass cytometry and single-cell profiles. Built on AI-Net (de Castro & Von Zuben 2001), bHIVE learns a set of prototypes (antibodies) by clonal selection, mutation and network suppression. The prototypes summarize cell populations in the original marker units, and the same fitted model labels new cells. Optional modules drawn from immunology add somatic hypermutation strategies, germinal center selection, microenvironment-driven adaptation and more.
Performance-critical operations (affinity/distance matrices, clonal selection, network suppression, mutation) are implemented in C++ via RcppArmadillo, with parallelization support through BiocParallel.
SummarizedExperiment and SingleCellExperiment objectscolData(), and bHIVEParam() runs bHIVE through bluster::clusterRows() and bluster::clusterSweep()
bHIVE()) for quick use and R6 (AINet$new()) for full module compositionhoneycombHIVE() for hierarchical prototype refinement across layersswarmbHIVE() with grid search and BiocParallelrefineB() post-processing with 5 optimizers and several classification-aware loss functionsbHIVEmodel and honeycombHIVEmodel for cross-validation workflowsbHIVE is submitted to Bioconductor. Once accepted, install it with:
if (!requireNamespace("BiocManager", quietly = TRUE))
install.packages("BiocManager")
BiocManager::install("bHIVE")
The development version is available from GitHub:
BiocManager::install("BorchLab/bHIVE")
The simplest way to use bHIVE. Works like any R modeling function:
library(bHIVE)
data(iris)
X <- as.matrix(iris[, 1:4])
# Clustering
res <- bHIVE(X, task = "clustering", nAntibodies = 30, maxIter = 20)
table(res$assignments)
# Classification
res <- bHIVE(X, y = iris$Species, task = "classification",
nAntibodies = 30, maxIter = 20)
table(Predicted = res$assignments, Actual = iris$Species)
bHIVE() clusters the cells (columns) of a SingleCellExperiment using an assay or a reducedDim() embedding, and stores the labels in colData(). bHIVEParam() plugs bHIVE into bluster:
library(SingleCellExperiment)
sce <- SingleCellExperiment(assays = list(logcounts = t(X)))
reducedDim(sce, "PCA") <- prcomp(X)$x[, 1:3]
sce <- bHIVE(sce, use.dimred = "PCA", targetK = 3, verbose = FALSE)
table(sce$bHIVE, iris$Species)
colLabels(sce) <- bluster::clusterRows(
reducedDim(sce, "PCA"),
bHIVEParam(targetK = 3, affinityParams = list(alpha = "auto"))
)
See vignette("bHIVE") for a full analysis of mass cytometry data, including a comparison with FlowSOM and graph-based clustering.
For full control, compose an AINet with any combination of immune modules. Each module is optional and slots into the fit loop at the appropriate biological stage:
# Adaptive mutation + germinal center selection
model <- AINet$new(
nAntibodies = 20,
maxIter = 30,
shm = SHMEngine$new(method = "adaptive", base_rate = 0.1),
germinalCenter = GerminalCenter$new(nTfh = 20, selectionPressure = 0.2),
verbose = FALSE
)
model$fit(X, iris$Species, task = "classification")
table(model$result$assignments)
# Predict on new data
preds <- model$predict(X[1:10, ])
A richer composition uses microenvironment-aware exploration, Tfh-mediated quality selection, density-driven isotype switching, and a persistent memory pool:
me <- Microenvironment$new() # zone classification
cs <- ClassSwitcher$new(alpha_IgM = 0.1, alpha_IgG = 5) # zone -> kernel width
gc <- GerminalCenter$new(nTfh = 8, selectionPressure = 0.6)
mp <- MemoryPool$new(archive_threshold = 0.05) # persists across fits
model <- AINet$new(
nAntibodies = 30, maxIter = 20,
shm = SHMEngine$new(method = "hotspot"),
microenvironment = me,
classSwitcher = cs, # requires microenvironment
germinalCenter = gc,
memory = mp,
verbose = FALSE
)
model$fit(X, iris$Species, task = "classification")
# Memory persists -- a second fit will recall relevant cells (clustering only)
# and continue archiving high-affinity antibodies.
mp$size()
bHIVE evolves a population of antibody vectors to represent structure in data. Each iteration runs a subset of the following stages — modules attach to specific stages and are skipped when absent:
VDJLibrary. If a MemoryPool carries cells from a prior fit, relevant memory is recalled and merged into the starting repertoire (clustering only).ActivationGate sets aside antibodies in over-dense neighborhoods or below an affinity floor so clonal selection runs on the sparse subset; gated antibodies rejoin after.SHMEngine (uniform, airs, hotspot, energy, adaptive); the adaptive strategy threads per-antibody Adam-style moment matrices across iterations.GerminalCenter runs Tfh-mediated quality selection; survivors weighted by clustering compactness or classification purity.Microenvironment classifies each antibody into stable / explore / boundary zones and applies density-dependent jitter. ClassSwitcher binds each zone to an isotype (IgM/IgG/IgA) and sets the next iteration's kernel width.IdiotypicNetwork runs bell-shaped Ab-Ab dynamics that cull both over-clumped and isolated antibodies in small, tight repertoires. The rule acts on each antibody pair, so in large or spread-out repertoires it removes every antibody; AINet then keeps the top 10% by population and reports it. See ?IdiotypicNetwork.MemoryPool archives high-affinity survivors back into the pool.
Each module is an R6 class that can be injected into AINet via its constructor. All modules are optional -- use only what you need.
| Module | Biological Basis | What It Does |
|---|---|---|
SHMEngine |
Somatic hypermutation | 5 mutation strategies: uniform, airs, hotspot, energy, adaptive |
IdiotypicNetwork |
Ab-Ab network regulation | Bell-shaped activation dynamics replacing epsilon-threshold suppression (experimental) |
GerminalCenter |
Tfh-B cell interaction | Task-aware quality selection with resource competition |
Microenvironment |
Tissue microenvironment cues | Density-dependent zone classification and mutation rate modulation |
VDJLibrary |
V(D)J recombination | Combinatorial gene library initialization (PCA, cluster, random partition) |
ActivationGate |
Two-signal activation | Costimulatory filtering (density, danger signal, or label entropy) |
MemoryPool |
Immunological memory | Archive high-affinity antibodies and recall on distribution shift |
ClassSwitcher |
Isotype class switching | IgM (broad) / IgG (specific) / IgA (boundary) kernel width modulation |
ConvergentSelector |
Public clonotypes | Cross-repertoire consensus for ensemble methods |
# honeycombHIVE: hierarchical prototype refinement
res <- honeycombHIVE(X, y = iris$Species, task = "classification",
layers = 3, nAntibodies = 30,
refine = TRUE, refineOptimizer = "adam")
# swarmbHIVE: hyperparameter grid search (parallelizable)
grid <- expand.grid(nAntibodies = c(15, 30), beta = c(3, 5), epsilon = c(0.01, 0.1))
best <- swarmbHIVE(X, y = iris$Species, task = "classification",
grid = grid, metric = "accuracy", maxIter = 20)
best$best_params
Fine-tune antibody positions after training with refineB():
res <- bHIVE(X, y = iris$Species, task = "classification",
nAntibodies = 20, maxIter = 20)
# Adam-based refinement with cross-entropy loss. antibody_index gives the
# antibody (row of res$antibodies) that labeled each sample.
A_refined <- refineB(res$antibodies, X, y = iris$Species,
assignments = res$antibody_index,
task = "classification",
loss = "categorical_crossentropy",
optimizer = "adam", steps = 10, lr = 0.01)
| Affinity | Formula | Use Case |
|---|---|---|
gaussian |
exp(-alpha ||x - a||^2) | General purpose (default) |
laplace |
exp(-alpha ||x - a||) | Heavier tails than Gaussian |
polynomial |
(x . a + c)^p | Non-Euclidean similarity |
cosine |
(x . a) / (||x|| ||a||) | Direction-based similarity |
hamming |
1 - (mismatches / d) | Categorical/binary features |
| Distance | Notes |
|---|---|
euclidean |
Default; L2 norm |
manhattan |
L1 norm |
minkowski |
Generalized Lp (parameter p) |
cosine |
1 - cosine similarity |
mahalanobis |
Accounts for feature covariance (requires Sigma) |
hamming |
Count of differing features |
If you run into any issues or bugs please submit a GitHub issue with details of the issue. If possible please include a reproducible example. Any requests for new features or enhancements can also be submitted as GitHub issues.
We welcome contributions to the bHIVE project! To contribute:
git checkout -b feature-branch).git commit -m "Add new feature").git push origin feature-branch).