bgns provides biweight midcorrelation
(bicor) and exact bicor-based k-nearest-neighbor graph
construction for high-dimensional numeric matrices. Its C++17 backend
supports dense, sparse, and mixed-input computation, with panelized
similarity evaluation and bounded top-k retention for KNN output.
Biweight midcorrelation uses robust location and scale estimates to reduce the influence of outlying observations. The package was developed for correlation-based analyses of gene expression, single-cell and metacell data, and other biological measurements, but its input is not restricted to biological matrices.
bgns provides two core functions: bicor()
computes correlation matrices or edge tables, and
bicor_knn() constructs directed KNN graphs. These outputs
can be used for downstream clustering, visualization, and biological
annotation with other packages.
The implementation separates similarity evaluation from retention of the results. Dense kernels use BLAS-backed computation where applicable; sparse and mixed-input paths handle compressed sparse matrices and finite-observation overlap. Panelization limits the size of intermediate calculations, while adaptive overlap strategies include index intersections and bitsets. SIMD kernels and OpenMP parallelism are used where supported by the build and execution environment.
With the default direct_sparse = TRUE,
bicor_knn() evaluates candidate similarities in panels and
retains bounded top-k candidate sets rather than materializing the full
dense similarity matrix. For self-KNN on p items, the
returned graph contains at most p * knn edges, excluding
self-neighbors. This reduces similarity-storage requirements; it does
not make the search approximate or remove the quadratic number of
candidate pairs in self-KNN.
Dense correlation output still requires storage for the full result matrix. A correlation edge table can also grow quadratically when its threshold retains most pairs. The panel-memory setting guides temporary allocations; it is not a cap on total process memory, which also includes input, output, preprocessing, and library workspace.
Requires R 4.3.0 or later.
install.packages("remotes")
remotes::install_github("metaddict/bgns")GitHub installation builds the package from source. A C++17-capable toolchain and the libraries required by your R installation are therefore necessary. Use the matching Rtools on Windows or the recommended R for macOS build tools on macOS. OpenMP is optional; a build without it uses serial execution for BGNS’s own parallel regions.
Rows are observations and columns are the items being compared. For a
cell-cell graph, cells should be columns; for a gene-gene graph, genes
should be columns. Input normalization and feature selection are
determined by the analysis, not performed automatically by
bgns.
library(bgns)
set.seed(1)
x <- matrix(rnorm(100 * 8), nrow = 100, ncol = 8)
colnames(x) <- paste0("item_", seq_len(ncol(x)))
# Introduce a correlated pair and one missing observation.
x[, 2] <- 0.8 * x[, 1] + 0.2 * rnorm(nrow(x))
x[1, 3] <- NA_real_cm <- bicor(x, min_overlap = 3)
round(cm, 3)The result contains correlations between columns. With dense
x and y, bicor(x, y) returns a
matrix with ncol(x) rows and ncol(y) columns.
Dense matrix output requires dense inputs; use tidy = TRUE
for sparse inputs.
edges <- bicor(x, tidy = TRUE, threshold = 0.2)
head(edges)The returned data frame has columns col1,
col2, and cor. In this mode,
threshold is applied to the absolute score: the example
retains finite correlations with abs(cor) >= 0.2,
including sufficiently strong negative correlations.
kn <- bicor_knn(x, knn = 3, threshold = 0)
head(kn)The returned data frame has columns col1,
col2, val, and rank.
col1 identifies the target, col2 a selected
neighbor, val the bicor score, and rank the
neighbor’s position within that target’s results.
KNN selection ranks signed bicor scores in descending order. Unlike
the absolute cutoff in bicor(tidy = TRUE), the KNN cutoff
is strictly val > threshold. Thus,
threshold = 0 retains only positive correlations. The
default threshold = -Inf permits all finite scores,
including negative ones.
Each target has at most knn neighbors. Fewer are
returned when insufficient eligible candidates pass the cutoff.
Self-neighbors are excluded in self-KNN, and reciprocal edges are not
enforced.
Sparse inputs are handled through numeric double compressed-column
matrices of class dgCMatrix. Other supported numeric sparse
Matrix classes are converted to this representation. Users
do not need to densify the entire input, although internal computation
may use dense panels.
# Construct a sparse representation of the example data.
set.seed(2)
xs <- x
xs[sample.int(length(xs), size = floor(0.2 * length(xs)))] <- 0
xs <- Matrix::Matrix(xs, sparse = TRUE)
edges_sparse <- bicor(xs, tidy = TRUE, threshold = 0.2)
kn_sparse <- bicor_knn(xs, knn = 3, threshold = 0)Implicit sparse entries are numerical zeros, not missing observations. Sparse storage does not by itself guarantee that a column has a defined biweight scale; see the missing-data and degenerate-column conventions below.
With y supplied, neighbors are selected from columns of
x for each target column of y. The inputs must
have the same number of rows, representing the same observations in the
same order. Either input may be dense or sparse.
set.seed(3)
y <- matrix(rnorm(nrow(xs) * 4), nrow = nrow(xs), ncol = 4)
colnames(y) <- paste0("target_", seq_len(ncol(y)))
kn_xy <- bicor_knn(
x = xs,
y = y,
knn = 3,
bipartite_levels = "separate"
)
head(kn_xy)Here, col1 refers to targets in y, and
col2 refers to selected neighbors in x. Use
bipartite_levels = "separate" when the two inputs have
distinct column-name sets.
With pairwise.complete.obs = TRUE, candidate pairs are
evaluated on their shared finite observations. NA,
NaN, and infinite values are non-finite; zeros remain
observations. min_overlap defaults to 3 and also applies to
fully finite pairs.
Robust location and scale are estimated separately for each column
from its finite observations, not re-estimated on each pair’s overlap.
By default, use_intersection_denominator = FALSE uses
full-column sums of squared biweight-transformed values for
normalization. Setting it to TRUE restricts the denominator
to the shared finite observations as well. This changes normalization,
not the columnwise location and scale estimates.
With pairwise.complete.obs = FALSE, columns containing
non-finite values are ineligible. Affected correlations are
NA in dense output and omitted from edge and KNN
output.
Constant columns, all-missing columns, and columns with zero median
absolute deviation or otherwise undefined biweight normalization produce
undefined correlations. A nonconstant column can also have zero median
absolute deviation, particularly when many observations are identical,
as in zero-heavy data. Undefined pairs are omitted from edge and KNN
results. In dense self-correlation output, ineligible diagonal entries
remain NA.
Set environment controls before the first computation in an R session.
| Variable | Default | Purpose |
|---|---|---|
BGNS_MEM_MB |
256 |
Guides the scratch-memory budget used for panel sizing; not a total-memory limit. |
BGNS_NUM_THREADS |
At most 2 |
Limits BGNS OpenMP threads when OpenMP is available. |
BGNS_SIMD |
Build-dependent | Set to 0, false, or off to
disable the package’s compiled SIMD paths. |
BGNS_BITSET_BETA |
0.75 |
Controls the adaptive criterion for constructing finite-overlap bitsets. |
Sys.setenv(BGNS_MEM_MB = "256", BGNS_NUM_THREADS = "2")SIMD and OpenMP availability depend on the compiler target and
installed build. The BGNS thread setting does not control independent
BLAS threading. Use the exported min_overlap argument
rather than setting BGNS_MIN_OVERLAP directly.
help("bicor", package = "bgns")
help("bicor_knn", package = "bgns")The source vignette is available in vignettes/bgns.Rmd.
citation("bgns")bgns is distributed under the GNU General Public
License version 3.