| """Tests for evaluation orchestration in prepare_combined.py.""" |
|
|
| import numpy as np |
| import pytest |
|
|
| from rhaister.prepare_combined import evaluate, make_evaluator |
|
|
| |
| |
| |
|
|
|
|
| class TestEvaluate: |
| def test_all_metric_keys_present(self): |
| """evaluate() with all inputs should return all expected metric keys.""" |
| rng = np.random.default_rng(42) |
| n, g = 20, 50 |
| Y = rng.normal(size=(n, g)) |
| P = rng.uniform(0, 1, size=(n, g)) |
| D = rng.normal(size=(n, g)) |
| F = rng.uniform(0, 1, size=(n, g)) |
| cells = np.array([f"C{i}" for i in range(n)]) |
| treats = np.array([f"T{i}" for i in range(n)]) |
| genes = [f"gene_{j}" for j in range(g)] |
|
|
| result = evaluate( |
| Y_true=Y, |
| Y_pred=Y, |
| P_true=P, |
| P_pred=P, |
| D_true=D, |
| D_pred=D, |
| F_true=F, |
| F_pred=F, |
| test_cells=cells, |
| test_treatments=treats, |
| gene_cols=genes, |
| ) |
|
|
| assert "pdex_static/pearson_delta_mean" in result |
| assert "n_samples" in result |
| assert result["n_samples"] == n |
| assert "state/pearson_delta_mean" in result |
| assert "state/pr_auc_mean" in result |
| assert "state/de_overlap_mean" in result |
| assert "state/de_spearman_sig" in result |
| assert "state/spearman_lfc_sig_mean" in result |
|
|
| def test_perfect_fc_pearson(self): |
| """When Y_pred == Y_true, legacy FC pearson should be ~1.0.""" |
| rng = np.random.default_rng(42) |
| n, g = 15, 40 |
| Y = rng.normal(size=(n, g)) |
| result = evaluate(Y_true=Y, Y_pred=Y) |
| assert result["pdex_static/pearson_delta_mean"] > 0.999 |
|
|
| def test_fc_only(self): |
| """evaluate() with only FC arrays (no p-values, no deltas) should still work.""" |
| rng = np.random.default_rng(42) |
| Y = rng.normal(size=(10, 30)) |
| result = evaluate(Y_true=Y, Y_pred=Y) |
| assert "pdex_static/pearson_delta_mean" in result |
| assert "state/pr_auc_mean" not in result |
|
|
| def test_pvalue_auprc(self): |
| """When P_pred == P_true, AUPRC should be high.""" |
| rng = np.random.default_rng(42) |
| n, g = 20, 100 |
| Y = rng.normal(size=(n, g)) |
| P = rng.uniform(0, 1, size=(n, g)) |
| result = evaluate(Y_true=Y, Y_pred=Y, P_true=P, P_pred=P) |
| assert "pdex_static/auprc_p05" in result |
| assert result["pdex_static/auprc_p05"] > 0.9 |
|
|
|
|
| |
| |
| |
|
|
|
|
| class TestMakeEvaluator: |
| def test_first_call_succeeds(self): |
| rng = np.random.default_rng(42) |
| n, g = 10, 20 |
| Y_test = rng.normal(size=(n, g)) |
| P_test = rng.uniform(0, 1, size=(n, g)) |
| D_test = rng.normal(size=(n, g)) |
| F_test = rng.uniform(0, 1, size=(n, g)) |
| cells = np.array([f"C{i}" for i in range(n)]) |
| treats = np.array([f"T{i}" for i in range(n)]) |
| genes = [f"gene_{j}" for j in range(g)] |
|
|
| eval_fn = make_evaluator(Y_test, P_test, D_test, F_test, cells, treats, genes) |
| Y_pred = rng.normal(size=(n, g)) |
| result = eval_fn(Y_pred) |
| assert isinstance(result, dict) |
| assert "pdex_static/pearson_delta_mean" in result |
|
|
| def test_second_call_raises(self): |
| rng = np.random.default_rng(42) |
| n, g = 10, 20 |
| Y_test = rng.normal(size=(n, g)) |
| P_test = rng.uniform(0, 1, size=(n, g)) |
| D_test = rng.normal(size=(n, g)) |
| F_test = rng.uniform(0, 1, size=(n, g)) |
| cells = np.array([f"C{i}" for i in range(n)]) |
| treats = np.array([f"T{i}" for i in range(n)]) |
| genes = [f"gene_{j}" for j in range(g)] |
|
|
| eval_fn = make_evaluator(Y_test, P_test, D_test, F_test, cells, treats, genes) |
| Y_pred = rng.normal(size=(n, g)) |
| eval_fn(Y_pred) |
| with pytest.raises(RuntimeError, match="already called"): |
| eval_fn(Y_pred) |
|
|