scverse / scverse/scanpy

Problem at reproducibility of UMAP / leiden

Open
#1,009 3 comments 4 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
2.6k
Forks
779
Avg merge
1d 4h
Merged PRs (30d)
27

Description

Hi,

I am working on a project with a labmate and we are using the same dataset. We have found that, when running the same pipeline on the same adata the neighbors / bbknn + UMAP + leiden results, even with the same seed, the clustering solution and UMAP are considerably different. This renders the analysis unreproducible and makes the downstream analysis far more difficult to do, since I have to map my clustering solutions and UMAP plots with hers using markers, and it is quite impractical.

We have the same versions of scanpy, leiden, umap, and bbknn on the two computers:

  • scanpy==1.4.5.post2
  • umap-learn==0.3.10
  • leidenalg==0.7.0
  • bbknn==1.3.6

To try to reproduce the issue, we have created a random matrix with the same seed (10), and create one annData with sc.pp.neighbours, and another one with bbknn. We have made the adatas to have two batches, so that we can use bbknn.

seed = 10
np.random.seed(seed)
a = np.random.rand(100, 100)
b = np.random.rand(100, 100)
print(np.sum(a), np.sum(b))

adata = sc.AnnData.concatenate(sc.AnnData(X=a), sc.AnnData(X=b), batch_categories=['a', 'b'])
sc.tl.pca(adata)
sce.pp.bbknn(adata, metric='angular')
sc.tl.umap(adata, random_state=seed)
sc.tl.leiden(adata, resolution=0.5, random_state=seed)
sc.pl.umap(adata, color=['batch', 'leiden'], alpha=0.3)
print(adata.uns['neighbors']['connectivities'].sum())

adata_neigh = adata.copy()
sc.pp.neighbors(adata_neigh, metric='cosine', random_state=seed)
sc.tl.umap(adata_neigh, random_state=seed)
sc.tl.leiden(adata_neigh, resolution=0.6, random_state=seed)
sc.pl.umap(adata_neigh, color=['batch', 'leiden'], alpha=0.3)
print(adata_neigh.uns['neighbors']['connectivities'].sum())

Our matrices are the same (the sums are 4918.370372081173 and 5005.088472351332), so the random generation works, but then the UMAPs and clustering solutions are different.

For the adata run with sc.pp.neighbors (left are batches and right are leiden cluster labels):
Mine
image

Hers
image

For the adata run with sce.pp.bbknn:
Mine
image

Hers
image

Our PCA decomposition has the same coordinates, so we discard the PCA as the source of variability. Also, since both UMAP and leiden look different, we think the source might come from the neighbor calculation.

When running adata.uns['neighbors']['connectivities'].sum() I get 801.5580058219996 and 1204.5274490986717 for adata and adata_neigh. I don't have her values now, but the values using the real dataset were in the order of 5000, and they were of by less than 0.001; so we are confused that with such a small difference on the sum, the results can be so different.

I attach the adatas for you to inspect them if you need more info.

adatas.zip

Thanks for the help!

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the reproduction script in the issue and the attached adatas.zip, using the listed scanpy, umap-learn, leidenalg, and bbknn versions. Compare the neighbor connectivities and subsequent UMAP and leiden outputs between environments; done would require identifying why identical inputs and seeds diverge and documenting a reproducible resolution.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
bioinformatics, machine-learning
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.