Repository navigation
smooth_expression: cell_mask to mask cells out (NaN) instead of evaluating them [DO NOT MERGE] - #36
settylab-dotto-bot[bot] wants to merge 4 commits into
Conversation
…valuating them smooth_expression fits on the selected cells but evaluates the model on every cell. Cells that have no place in the representation (e.g. removed by a quality gate before the diffusion map, with NaN coordinates) then get NaN by accident or an unrequested extrapolation. cell_mask (boolean obs column or array; True keeps a cell): masked-out cells are excluded from fitting, never evaluated (their obsm rows are never read), and NaN in every per-cell output (smoothed, std, obs/sample variance). With groupby/condition the fit uses condition AND mask; kept cells are evaluated as before. Kept cells with non-finite coordinates raise. cell_mask=None (default) is unchanged. Tests: 13 new in tests/test_anndata_smooth.py.
|
@settylab-dotto-bot the anndata interface should take an |
…e it in the CLI Maintainer review on #36: - smooth_expression's cell_mask is the name of a boolean adata.obs column (no missing values); the unreleased array form is removed. A missing column, a non-boolean or partly missing column, an all-False column and a non-string argument are refused with a clear error. - Run info: params["cell_mask"] (column), params["n_cells_masked_out"], params["masked_cells"] (states that masked cells are excluded and NaN); the field descriptions of every output layer say "NaN for the N cells masked out by obs['<column>']". - CLI: kompot smooth --cell-mask COLUMN, documented in --help; config template key cell_mask. - Tests: kept rows bitwise equal to groupby=<column>, condition=True (same fit); nullable-boolean column bitwise equal to numpy bool; run-info fields; refusals; CLI --help, CLI round-trip bitwise equal to the Python API, CLI refusals.
… fields; CLI option
|
Done, on this PR (commits 4d1ddf7 and 4a79a5e; still DO NOT MERGE).
Run info.
Each output layer's description in CLI. Tests (synthetic fixtures; 22 for the mask: 18 anndata + 4 CLI):
Full suite, this repo's CI on head 4a79a5e, 2,261 tests each, 0 failed:
The PR description is updated to match. |
|
@settylab-dotto-bot reconsider this. The predict and std functions should predict all cells independently. So, cells with invalid coordinates should have NaN values returned. Is |
…s are excluded from fitting and NaN Maintainer review on #36: prediction is per cell, so a cell mask is not needed. Measured: ExpressionModel.predict and .std are row-independent (mellon LandmarksConditional: mean = K(x, landmarks) @ weights; the variance is solved against the fixed landmark Cholesky factor). With NaN rows planted, those rows come back NaN and every other row is bitwise equal to evaluating without them, at batch sizes 7, 50 and 1000, with and without the variance terms. What failed on main is the FIT: cells with NaN coordinates reached landmark selection (KMeans), which refuses NaN. Now cells whose coordinates are not all finite are excluded from fitting only; they are still evaluated and come out NaN. The run info records n_cells_nonfinite and nonfinite_cells, and each output layer's description gives the NaN count. cell_mask, the CLI option and its config key are removed (reverted to main). Tests: non-finite rows NaN; other rows bitwise equal to the same fit; equal to smoothing the valid subset; partial-NaN and inf rows; all-finite control; run info; condition, variance layers and gene subset; no valid cell raises; CLI round trip bitwise equal to the Python API.
|
Answer: you are right. No mask is needed, and Is it pure JAX and per cell? Yes, for the paths
Measured (synthetic: 400 cells, 5 dims, 6 genes, 40 landmarks; NaN coordinates planted in 7 cells; fit on the valid cells):
All of it holds with and without the variance terms ( What fails on
The change (
Tests (synthetic):
|
DO NOT MERGE — for the maintainer's review.
What
smooth_expressionnow handles cells whose cell-state coordinates are not all finite (NaN or inf, e.g. cells left out of a diffusion map). They are excluded from fitting and come out NaN in every output layer. No argument is needed. Every other cell's values are unchanged.The run info records
params["n_cells_nonfinite"]andparams["nonfinite_cells"], and each output layer's description gives the NaN count. With all coordinates finite, nothing changes.Why
On
main(915b411), a NaN coordinate makes the fit fail:kompot/anndata/smooth.pyL190-191 put every selected cell into the training set;kompot/differential/expression_model.pyL233-239 run landmark selection (melloncompute_landmarks→k_means), which refuses NaN.Prediction, by contrast, is per cell (mellon
LandmarksConditional: meanK(x, landmarks) @ weights; the variance is solved against the fixed landmark Cholesky factor). So excluding these cells from the fit is the whole fix, and their rows come out NaN on their own. Measured: every other row ofpredictandstdis bitwise equal to evaluating without the NaN rows, at batch sizes 7, 50 and 1000.(An earlier revision of this PR added a
cell_maskargument; it was removed on review.)Tests
tests/test_anndata_smooth.py::TestNonFiniteCoordinates, 10 tests, including a bitwise comparison against the same fit.tests/test_cli_smooth.py::TestCLISmoothNonFinite: a CLI round trip bitwise equal to the Python API.