Tutorial 4 — Inspecting NMF convergence#
This tutorial shows how to use the convergence diagnostics returned by multi_sample_nmf to assess whether the chosen rank range and number of initialisations are sufficient.
Dataset — Peter Sims lab DMSO vs. panobinostat scRNA-seq cohort.
0 · Imports and data preparation#
[ ]:
import kaleidocell
import scanpy as sc
import matplotlib.pyplot as plt
adata = sc.read_h5ad('../data/petersims_example.h5ad')
print(adata)
1 · Run NMF and capture the convergence object#
multi_sample_nmf returns a tuple (results_nmf, nmf_convergence). The second element is a dict mapping each sample to a DataFrame with one row per rank containing the best Frobenius reconstruction error across all initialisations.
[ ]:
results_nmf, nmf_convergence = kaleidocell.multi_sample_nmf(
adata,
batch_key='Patients',
test_ranks=[4, 5, 6, 7, 8, 9],
n_initializations=10,
seed=42,
)
# nmf_convergence is a dict {sample_name: DataFrame(rank, error)}
list(nmf_convergence.keys())
2 · Inspect reconstruction error per rank#
A large drop in error between consecutive ranks suggests that the higher rank captures a genuinely new signal. An elbow in the curve is a common heuristic for rank selection.
[ ]:
fig, axes = plt.subplots(1, len(nmf_convergence), figsize=(4 * len(nmf_convergence), 3), sharey=False)
for ax, (sample, df) in zip(axes, nmf_convergence.items()):
ax.plot(df['rank'], df['error'], marker='o')
ax.set_title(sample)
ax.set_xlabel('Rank')
ax.set_ylabel('Frobenius error')
plt.tight_layout()
plt.show()
3 · Derive meta-programs and inspect quality metrics#
After selecting a rank based on the elbow above, proceed with derive_nmf_metaprograms and review the per-MP quality metrics to confirm the consensus is stable.
[ ]:
results_mp = kaleidocell.derive_nmf_metaprograms(results_nmf)
# Quality metrics: sampleCoverage, silhouette, meanSimilarity, nPrograms, nGenes
results_mp['metrics']