count_split
count_split reproducibly allocates observed count molecules into statistically
independent analysis folds. It is a Python implementation inspired by Neufeld
et al.'s count-splitting approach for avoiding double use of the same counts in
single-cell clustering and differential-expression analysis.
- Paper: Inference after latent variable estimation for single-cell RNA sequencing data
- Reference R package and methodology: countsplit
Please cite the original methodology when using this package.
Allocation contract
For every observed molecule, the implementation draws one uniform random value
and assigns that molecule to exactly one requested fold. Multi-fold allocation
is simultaneous: [0.325, 0.325, 0.35] means those final probabilities, not a
sequence of percentages applied to a shrinking remainder.
The implementation guarantees:
- element-wise count conservation across all output folds;
- deterministic results for the same seed and canonically ordered matrix;
- identical seeded allocation for equivalent dense, CSR, and CSC inputs;
- no sparse-to-dense conversion;
- preservation of integer input dtypes on output (CSC for every sparse input format); and
- explicit rejection of negative, non-finite, fractional, boolean, complex, or out-of-range counts.
Installation
From a checkout:
python -m pip install .
For development:
python -m pip install -e .
python -m pytest
Python 3.10 or newer is required.
Usage
The legacy API expects variables in rows and samples in columns. For a single-cell matrix, that means genes × cells.
import numpy as np
from count_split.count_split import multi_split
counts = np.random.default_rng(7).negative_binomial(
2,
0.4,
size=(1_000, 500),
)
train, validation, test = multi_split(
counts,
percent_vect=[0.325, 0.325, 0.35],
seed=123456,
)
assert np.array_equal(train + validation + test, counts)
Weights are normalized, so [1, 1, 2] is equivalent to
[0.25, 0.25, 0.5]. A zero-weight fold is retained as an all-zero result.
multi_split continues to return a list for backward compatibility.
Sparse matrices
CSR, CSC, and other SciPy sparse inputs are accepted. Duplicate sparse
coordinates are summed once in safe int64 scratch space. All sparse outputs
are canonical CSC matrices and preserve the input integer dtype when it can
represent the canonicalized logical counts.
from scipy import sparse
from count_split.count_split import multi_split
counts_csr = sparse.csr_matrix(counts)
train, validation, test = multi_split(
counts_csr,
percent_vect=[0.325, 0.325, 0.35],
seed=123456,
)
assert ((train + validation + test) != counts_csr).nnz == 0
AnnData
AnnData normally stores cells in rows and genes in columns, so transpose X
for this legacy API:
train, validation, test = multi_split(
adata.X.T,
percent_vect=[0.325, 0.325, 0.35],
seed=123456,
)
The returned matrices are genes × cells. Downstream code that expects the AnnData orientation should transpose each result back.
Two-fold APIs
The original pairwise functions and argument order remain available. The new
seed parameter is appended, so existing positional calls remain valid.
from count_split.count_split import split_mat_counts, split_sparse
dense_a, dense_b = split_mat_counts(counts, percent_1=0.4, seed=17)
sparse_a, sparse_b = split_sparse(counts_csr, percent_1=0.4, seed=17)
Calling seed_rng(value) before a call that omits seed remains supported for
legacy integrations. New code should use the explicit seed argument. Valid
explicit seeds are integers from 0 through 4,294,967,295.
Dense HDF5
split_mat_counts_h5 preserves the original two-output file interface and
copies all non-target HDF5 content into both outputs. Only the selected dense,
two-dimensional dataset is replaced with split counts.
from count_split.count_split import split_mat_counts_h5
split_mat_counts_h5(
"input.h5",
"fold_a.h5",
"fold_b.h5",
percent_1=0.5,
bin_size=5_000,
key="infile",
seed=17,
)
Memory and reproducibility notes
All cumulative offsets and total-molecule bookkeeping use int64 internally,
but this does not force int64 storage on output. Each output entry is bounded
by its corresponding canonicalized input count. Integral real-valued inputs are
accepted for legacy compatibility but return integer (int64) folds.
The chosen non-parametric algorithm explicitly materializes one uniform value and one fold index per observed molecule, plus a folds × nonzero-entry re-collation buffer. Its peak memory therefore scales with the total molecule count, not only matrix dimensions or sparse nonzeros. This is deliberate and should be capacity-planned for very deep matrices.
For ordinary dense and sparse calls, bin_size is accepted only for signature
compatibility and does not change matrix-wide allocation. The HDF5 function
uses bin_size to process contiguous column chunks while maintaining one RNG
stream; seeded output is invariant to that chunk size.
Reproducibility requires the same package/runtime stack, input values, matrix shape, row/column order, fold weights, and seed. Equivalent dense, CSR, and CSC representations are canonicalized to the same column-major allocation order.
Compatibility
Version 1.0.0 retains the original public function names, existing positional
arguments, HDF5 behavior, CSC sparse return convention, and list return from
multi_split. Correctness-related behavior changes are documented in
CHANGELOG.md.
License and contact
Licensed under the GNU Affero General Public License v3.0; see LICENSE.
Source: github.com/scottyler89/count_split
Repository owner: scottyler89@gmail.com
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file count_split-1.0.1.tar.gz.
File metadata
- Download URL: count_split-1.0.1.tar.gz
- Upload date:
- Size: 27.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f380c754e29fd55df86bad1ce0e21ad272b28b6ef0844c9ff5bd343abcebb875
|
|
| MD5 |
63087e464bffbe18918ebb8932b57684
|
|
| BLAKE2b-256 |
c7af865927bbff8269fd02fd2349d81e4186567047c5d0d7b0c0e00f8df78701
|
Provenance
The following attestation bundles were made for count_split-1.0.1.tar.gz:
Publisher:
release.yml on scottyler89/count_split
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
count_split-1.0.1.tar.gz -
Subject digest:
f380c754e29fd55df86bad1ce0e21ad272b28b6ef0844c9ff5bd343abcebb875 - Sigstore transparency entry: 2305731724
- Sigstore integration time:
-
Permalink:
scottyler89/count_split@4cfa16edf98911dbf901b6f0ed3e29fed647e5c6 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/scottyler89
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4cfa16edf98911dbf901b6f0ed3e29fed647e5c6 -
Trigger Event:
release
-
Statement type:
File details
Details for the file count_split-1.0.1-py3-none-any.whl.
File metadata
- Download URL: count_split-1.0.1-py3-none-any.whl
- Upload date:
- Size: 20.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b7e1a323d9a4d298368b026dbb6dc551a741b0d60672e715c5b43044b8b84acf
|
|
| MD5 |
5c813400f5abb66a4b3530bf0952f41c
|
|
| BLAKE2b-256 |
edf737538be518c2662be7a51772751cc3189f25fea0c81ddae4fbeff91e191d
|
Provenance
The following attestation bundles were made for count_split-1.0.1-py3-none-any.whl:
Publisher:
release.yml on scottyler89/count_split
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
count_split-1.0.1-py3-none-any.whl -
Subject digest:
b7e1a323d9a4d298368b026dbb6dc551a741b0d60672e715c5b43044b8b84acf - Sigstore transparency entry: 2305731787
- Sigstore integration time:
-
Permalink:
scottyler89/count_split@4cfa16edf98911dbf901b6f0ed3e29fed647e5c6 -
Branch / Tag:
refs/tags/v1.0.1 - Owner: https://github.com/scottyler89
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4cfa16edf98911dbf901b6f0ed3e29fed647e5c6 -
Trigger Event:
release
-
Statement type: