Skip to content

Commit e1fd263

Browse files
ilan-goldIntron7flying-sheep
authored
fix int for shortcut (#3461) (#3640)
* fix int for shortcut * add release note * add order to astype * (fix): sparse bug + tests --------- (cherry picked from commit def4f23) Co-authored-by: Severin Dicks <37635888+Intron7@users.noreply.github.com> Co-authored-by: Philipp A. <flying-sheep@web.de>
1 parent c5ffedc commit e1fd263

3 files changed

Lines changed: 22 additions & 4 deletions

File tree

docs/release-notes/3461.bugfix.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fixes an error where `regress_out` would fail to work with `integer` types {smaller}`S Dicks`

src/scanpy/preprocessing/_simple.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,14 @@ def regress_out(
755755
# if the regressors are not categorical and the matrix is not singular
756756
# use the shortcut numpy_regress_out
757757
if not variable_is_categorical and np.linalg.det(regressors.T @ regressors) != 0:
758+
# Because we update `X` in `numpy_regress_out`, it needs to be floating point to match
759+
# the incoming values.
760+
if np.issubdtype(X.dtype, np.integer):
761+
target_dtype = np.float32 if X.dtype.itemsize <= 4 else np.float64
762+
kwargs = {}
763+
if isinstance(X, np.ndarray):
764+
kwargs["order"] = "C"
765+
X = X.astype(target_dtype, **kwargs)
758766
X = _to_dense(X, order="C") if isinstance(X, CSBase) else X
759767
res = numpy_regress_out(X, regressors)
760768

tests/test_preprocessing.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -402,13 +402,22 @@ def test_regress_out_ordinal():
402402
np.testing.assert_array_equal(single.X, multi.X)
403403

404404

405-
def test_regress_out_layer():
405+
@pytest.mark.parametrize("dtype", [np.int64, np.float64, np.int32])
406+
def test_regress_out_layer(dtype):
406407
from scipy.sparse import random
407408

408-
adata = AnnData(random(1000, 100, density=0.6, format="csr"))
409+
adata = AnnData(
410+
random(1000, 100, density=0.6, format="csr", dtype=np.uint16).astype(dtype)
411+
)
409412
adata.obs["percent_mito"] = np.random.rand(adata.X.shape[0])
410413
adata.obs["n_counts"] = adata.X.sum(axis=1)
411-
adata.layers["counts"] = adata.X.copy()
414+
if dtype == np.float64:
415+
dtype_cast = dtype
416+
if dtype == np.int64:
417+
dtype_cast = np.float64
418+
if dtype == np.int32:
419+
dtype_cast = np.float32
420+
adata.layers["counts"] = adata.X.copy().astype(dtype_cast)
412421

413422
single = sc.pp.regress_out(
414423
adata, keys=["n_counts", "percent_mito"], n_jobs=1, copy=True
@@ -419,7 +428,7 @@ def test_regress_out_layer():
419428
adata, layer="counts", keys=["n_counts", "percent_mito"], n_jobs=1, copy=True
420429
)
421430

422-
np.testing.assert_array_equal(single.X, layer.layers["counts"])
431+
np.testing.assert_allclose(single.X, layer.layers["counts"])
423432

424433

425434
def test_regress_out_view():

0 commit comments

Comments
 (0)