Topics

Topic fitting, coherence, assignment summaries and result containers.

rustscenic.topics

Topic modeling (pycisTopic LDA replacement).

Online variational Bayes LDA (Hoffman-Blei-Bach 2010) for scATAC peak-topic modeling. Converges in tens of passes vs Gibbs's thousands of iterations.

rustscenic.topics.fit(adata_or_sparse, n_topics=50) -> TopicsResult

Output is a TopicsResult dataclass with: cell_topic: (cells x topics) probability matrix (each row sums to 1) topic_peak: (topics x peaks) probability matrix (each row sums to 1)

Both pycisTopic (Mallet Gibbs) and rustscenic (online VB) are probabilistic - topic labels are permutation-free. Validation metric is topic assignment ARI.

RustBackendArray

Bases: ndarray

ndarray subclass carrying exact Rust backend provenance.

rust_backend instance-attribute

rust_backend: dict

TopicsResult dataclass

TopicsResult(
    cell_topic: DataFrame,
    topic_peak: DataFrame,
    n_topics: int,
    backend_execution: dict | None = None,
)

Fitted topic weights and backend provenance.

Attributes:

Name Type Description
cell_topic DataFrame

Cells-by-topics probability DataFrame, indexed by cell name.

topic_peak DataFrame

Topics-by-peaks probability DataFrame, with peak names as columns.

n_topics int

Number of topics requested for the fit.

backend_execution dict | None

Optional dictionary describing the Rust backend symbols used.

cell_topic instance-attribute

cell_topic: DataFrame

topic_peak instance-attribute

topic_peak: DataFrame

n_topics instance-attribute

n_topics: int

backend_execution class-attribute instance-attribute

backend_execution: dict | None

cell_assignment

cell_assignment() -> pd.Series

Argmax topic per cell.

top_peaks_per_topic

top_peaks_per_topic(n: int = 20) -> CandidateEnhancers

Select the highest-weight peaks for each fitted topic.

Parameters:

Name Type Description Default
n int

Maximum number of peaks retained per topic from topic_peak.

20

Returns:

Type Description
CandidateEnhancers

Topic names mapped to their top peak names, with Rust backend provenance attached.

assignment_summary

assignment_summary(cell_topic: DataFrame) -> dict[str, int]

Summarise topic usage with the Rust assignment kernel.

Returns active argmax-topic and empty-cell counts without materialising a Python boolean mask over the cells-by-topics matrix.

Parameters:

Name Type Description Default
cell_topic DataFrame

Cells-by-topics weight DataFrame.

required

Returns:

Type Description
dict[str, int]

Counts named active_argmax_topics and empty_cells.

fit

fit(
    expression,
    *,
    n_topics: int = 50,
    alpha: float | None = None,
    eta: float | None = None,
    tau0: float = 64.0,
    kappa: float = 0.7,
    batch_size: int = 256,
    n_passes: int = 10,
    seed: int = 42,
    verbose: bool = True,
) -> TopicsResult

Fit LDA on a (cells × peaks) count / binarized matrix.

Parameters:

Name Type Description Default
expression

AnnData, pandas DataFrame, or (sparse-csr, cell_names, peak_names) tuple. For scATAC use binarized accessibility (1 if peak accessible in cell).

required
n_topics int

Number of latent topics K. pycisTopic typical range: 50–200.

50
alpha float | None

Dirichlet priors. Default 1/K, matches pycisTopic.

None
eta float | None

Dirichlet priors. Default 1/K, matches pycisTopic.

None
tau0 float

Learning-rate schedule (Hoffman 2010).

64.0
kappa float

Learning-rate schedule (Hoffman 2010).

64.0
batch_size int

Minibatch SGD controls.

256
n_passes int

Minibatch SGD controls.

256
seed int

Random seed passed to the online-VB backend.

42
verbose bool

Print fitting progress and timing to standard error.

True

Returns:

Type Description
TopicsResult

fit_gibbs

fit_gibbs(
    expression,
    *,
    n_topics: int = 50,
    alpha: float | None = None,
    eta: float | None = None,
    n_iters: int = 200,
    seed: int = 42,
    n_threads: int = 1,
    verbose: bool = True,
) -> TopicsResult

Fit collapsed-Gibbs LDA on a (cells × peaks) count / binarized matrix.

The Mallet-class topic model - better topic-coherence (NPMI) on sparse scATAC at K ≥ 30 than the default online-VB :func:fit, at the cost of thousands of iterations instead of tens of passes. Use this when topic quality matters more than wall-clock, typically for small-to-medium samples where you can afford the Gibbs sampling time.

Parameters:

Name Type Description Default
expression

AnnData, pandas DataFrame, or (sparse-csr, cell_names, peak_names) tuple.

required
n_topics int

Number of latent topics K. Mallet typical range: 30–100.

50
alpha float | None

Dirichlet priors. Default 0.1 / 0.01 - Griffiths & Steyvers 2004's "good defaults" for LDA, slightly less concentrated than the 1/K we use for online VB.

None
eta float | None

Dirichlet priors. Default 0.1 / 0.01 - Griffiths & Steyvers 2004's "good defaults" for LDA, slightly less concentrated than the 1/K we use for online VB.

None
n_iters int

Number of Gibbs sweeps over the corpus. 200 is a reasonable default for convergence on small samples; bump to 500–1000 for higher-quality posterior estimates.

200
seed int

Random seed. Topics are stochastic - bit-identical under same seed (single-threaded), reproducible across runs at fixed n_threads for the parallel path.

42
n_threads int

1 (default): bit-deterministic serial sampler. >1: AD-LDA (Newman et al. 2009) parallel sampler - partitions docs across threads. Results are reproducible at fixed seed and n_threads. Changing the thread count changes the partition and stochastic trajectory and may reach a different posterior mode, so keep it fixed when comparing biological outputs. Speedup is workload dependent and often saturates once topic-word reads become memory-bandwidth bound.

1
verbose bool

Print fitting progress and timing to standard error.

True

Returns:

Type Description
TopicsResult - same shape as :func:`fit`, columns are
``Topic_0 .. Topic_{K-1}``.

coherence_npmi

coherence_npmi(result: TopicsResult, corpus, *, top_n: int = 10) -> np.ndarray

Per-topic NPMI coherence for a fitted topic model.

Parameters:

Name Type Description Default
result TopicsResult

:class:TopicsResult from :func:fit or :func:fit_gibbs.

required
corpus

Corpus to score against (AnnData / DataFrame / sparse-tuple, same shape conventions as :func:fit). Should have the same peak/word vocabulary as result - column order must match result.topic_peak.columns.

required
top_n int

Top-N peaks per topic to evaluate pairwise NPMI over. 10 is standard for LDA topic-coherence.

10

Returns:

Type Description
np.ndarray of shape (n_topics,) - mean pairwise NPMI per topic.
Higher is better; positive values mean top-words co-occur more
than independence would predict.

Reexported helpers

These names are also available from this module. They share the underlying implementation and source documentation of their original definitions.

rustscenic.topics.CandidateEnhancers

Bases: dict

dict subclass carrying backend provenance for ranked topic peaks.

rust_backend instance-attribute

rust_backend: dict