scverse / scverse/scanpy

Reproducibility with normalize_total

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

Nobody has claimed this yet.

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

Description

Hi,

We have encountered a bug regarding the reproducibility of the normalize_total in the latest version of scanpy==1.6.11. We also found this bug with scanpy==1.4.4.post1. This bug appears with an in-house dataset (containing 10x data and SMART-seq2 scaled data) and interestingly does not appear with the internal scanpy 10x 3k PBMC dataset.

Minimal code sample
def check_equal_adata_X(adata1, adata2):
    print((adata1.X!=adata2.X).nnz==0)
    tmp1 = adata1.X.todense()
    tmp2 = adata2.X.todense()
    print(np.array_equal(tmp1, tmp2))
    print((tmp1 == tmp2).all())

adata_run1_concat = sc.read_h5ad("adata1.h5ad")
adata_run2_concat = sc.read_h5ad("adata2.h5ad")
check_equal_adata_X(adata_run1_concat, adata_run2_concat)
sc.pp.normalize_total(adata_run1_concat)
sc.pp.normalize_total(adata_run2_concat)
check_equal_adata_X(adata_run1_concat, adata_run2_concat)

Output:

True
True
True
False
False
False

Here is the code that fixes this bug.

adata_run1_concat = sc.read_h5ad("adata1.h5ad")
adata_run2_concat = sc.read_h5ad("adata2.h5ad")
check_equal_adata_X(adata_run1_concat, adata_run2_concat)
adata_run1_concat.X = adata_run1_concat.X.astype(np.float64)
adata_run2_concat.X = adata_run2_concat.X.astype(np.float64)
sc.pp.normalize_total(adata_run1_concat)
sc.pp.normalize_total(adata_run2_concat)
check_equal_adata_X(adata_run1_concat, adata_run2_concat)

Output:

True
True
True
True
True
True

Like I said, we tested also the "internal" scanpy 10x 3k PBMC dataset

sc.datasets.pbmc3k()
pbmc3k_1 = sc.read_h5ad("data/pbmc3k_raw.h5ad")
pbmc3k_2 = sc.read_h5ad("data/pbmc3k_raw.h5ad")
check_equal_adata_X(pbmc3k_1, pbmc3k_2)
sc.pp.normalize_total(pbmc3k_1)
sc.pp.normalize_total(pbmc3k_2)
check_equal_adata_X(pbmc3k_1, pbmc3k_2)
True
True
True
True
True
True
Versions

anndata 0.7.5
scanpy 1.6.1
sinfo 0.3.1

anndata 0.7.5
backcall 0.1.0
cycler 0.10.0
cython_runtime NA
dateutil 2.8.1
decorator 4.4.2
get_version 2.1
h5py 2.10.0
importlib_metadata 1.6.0
ipykernel 5.2.1
ipython_genutils 0.2.0
ipywidgets 7.5.1
jedi 0.17.0
joblib 0.14.1
kiwisolver 1.2.0
legacy_api_wrap 1.2
llvmlite 0.31.0
matplotlib 3.2.1
mpl_toolkits NA
natsort 7.0.1
numba 0.48.0
numexpr 2.7.1
numpy 1.18.2
packaging 20.3
pandas 1.0.3
parso 0.7.0
pexpect 4.8.0
pickleshare 0.7.5
pkg_resources NA
prompt_toolkit 3.0.5
ptyprocess 0.6.0
pygments 2.6.1
pyparsing 2.4.7
pytz 2019.3
scanpy 1.6.1
scipy 1.4.1
setuptools_scm NA
sinfo 0.3.1
six 1.14.0
sklearn 0.22.2.post1
storemagic NA
tables 3.6.1
tornado 6.0.4
tqdm 4.45.0
traitlets 4.3.3
wcwidth NA
zipp NA
zmq 19.0.0

IPython 7.13.0
jupyter_client 6.1.3
jupyter_core 4.6.3
notebook 6.0.3

Python 3.7.6 | packaged by conda-forge | (default, Mar 23 2020, 23:03:20) [GCC 7.3.0]
Linux-3.10.0-1127.18.2.el7.x86_64-x86_64-with-centos-7.8.2003-Core
36 logical CPU cores

Session information updated at 2021-01-27 17:16

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 minimal reproducible example and trace the sc.pp.normalize_total entry point, comparing inputs with the differing dtypes described in the issue. Check how the operation handles the provided sparse or mixed data, then run the reproduction to verify that equivalent inputs produce identical X values without manual float64 conversion.

Written by the indexing model from the issue text.

Assessment

Tech stack
numpy, python
Domain
bioinformatics
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.