Skill Tracer
Skills › Scientific Agent Skills › relsa-severity-assessment › thresholds-and-zones.md

thresholds-and-zones.md

81 lines · skills/relsa-severity-assessment/references/thresholds-and-zones.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Candidate RELSA zones from a score density
2
3The [primary foRcast paper](https://doi.org/10.3389/fphys.2026.1869563) explores local minima
4of a Gaussian KDE over longitudinal RELSA scores. These valleys describe the **sampled score
5distribution**. They do not establish transitions between normal welfare and distress.
6The legacy output names `normal`, `attention`, `danger` are descriptive labels only.
7

Candidate RELSA zones from a score density

The primary foRcast paper explores local minima of a Gaussian KDE over longitudinal RELSA scores. These valleys describe the sampled score distribution. They do not establish transitions between normal welfare and distress. The legacy output names normal, attention, danger are descriptive labels only.

Raw lines 1 to 7
8## Kernel, bandwidth and implementation differences
9
10`bw_nrd0()` uses R's rule `0.9 * min(sd, IQR/1.349) * n^(-1/5)` with the zero-spread fallback.
11The [official R density documentation](https://stat.ethz.ch/R-manual/R-devel/library/stats/html/density.html)
12uses a Gaussian default, 512 grid points and an extent of three bandwidths beyond the data.
13R performs an FFT-based approximation and its `old.coords` compatibility option changes
14historical behavior. The Python helper evaluates SciPy's Gaussian KDE directly, with an
15analytic Gaussian for constant samples. It matches the bandwidth convention, not bitwise
16R density output or the paper's exact thresholds. SciPy's named `silverman` bandwidth factor
17is a different convention and must not be substituted silently.
19Input scores must be nonnegative. Missing scores are omitted. Fewer than two finite scores
20cannot define a KDE. Constant samples produce no usable interior threshold. A bandwidth must
21be finite and positive. `n_thresholds` is a maximum count, not a demand to invent boundaries.
22The default `min_zone_fraction=0.02` removes minima isolating fewer than 2% of observations;
23this is a local heuristic, not a published or welfare-validated cutoff. Set it to zero to
24inspect raw minima. Zone assignment includes equality in the higher zone; threshold JSON
25preserves full precision so its decisions agree with CSV labels.
27The paper gives sepsis thresholds 0.337/0.643 in Results/Figure 3 but 0.337/0.647 in the
28abstract. These are historical model-specific observations, not transferable clinical limits.
29Earlier skill notes included full-cohort reproduction and bandwidth-sweep numbers; those
30analyses are not repeated by this refresh and are not presented as current execution evidence.

Kernel, bandwidth and implementation differences

bw_nrd0() uses R's rule 0.9 * min(sd, IQR/1.349) * n^(-1/5) with the zero-spread fallback. The official R density documentation uses a Gaussian default, 512 grid points and an extent of three bandwidths beyond the data. R performs an FFT-based approximation and its old.coords compatibility option changes historical behavior. The Python helper evaluates SciPy's Gaussian KDE directly, with an analytic Gaussian for constant samples. It matches the bandwidth convention, not bitwise R density output or the paper's exact thresholds. SciPy's named silverman bandwidth factor is a different convention and must not be substituted silently.

Input scores must be nonnegative. Missing scores are omitted. Fewer than two finite scores cannot define a KDE. Constant samples produce no usable interior threshold. A bandwidth must be finite and positive. n_thresholds is a maximum count, not a demand to invent boundaries. The default min_zone_fraction=0.02 removes minima isolating fewer than 2% of observations; this is a local heuristic, not a published or welfare-validated cutoff. Set it to zero to inspect raw minima. Zone assignment includes equality in the higher zone; threshold JSON preserves full precision so its decisions agree with CSV labels.

The paper gives sepsis thresholds 0.337/0.643 in Results/Figure 3 but 0.337/0.647 in the abstract. These are historical model-specific observations, not transferable clinical limits. Earlier skill notes included full-cohort reproduction and bandwidth-sweep numbers; those analyses are not repeated by this refresh and are not presented as current execution evidence.

Raw lines 8 to 31
32## Population and sampling are part of the model
34Use a development population that represents the intended comparison: endpoint animals,
35survivors and controls where scientifically appropriate. Explain exclusions, baseline-row
36inclusion, measurement cadence, variable panel and reference scale. More frequent observations
37and longer-lived animals contribute more KDE mass. Endpoint-related truncation changes that
38mixture; 239 measurements from seven animals are not 239 independent animals.
40Sensitivity analyses should vary bandwidth, sampling/aggregation and baseline inclusion;
41assess threshold stability with animal-level resampling or held-out cohorts. Pool only
42measurements sharing one calibration and measurement interpretation. Select thresholds on
43development data and freeze them before evaluation. Candidate zones cannot be tuned until
44held-out endpoint classification looks favorable.

Population and sampling are part of the model

Use a development population that represents the intended comparison: endpoint animals, survivors and controls where scientifically appropriate. Explain exclusions, baseline-row inclusion, measurement cadence, variable panel and reference scale. More frequent observations and longer-lived animals contribute more KDE mass. Endpoint-related truncation changes that mixture; 239 measurements from seven animals are not 239 independent animals.

Sensitivity analyses should vary bandwidth, sampling/aggregation and baseline inclusion; assess threshold stability with animal-level resampling or held-out cohorts. Pool only measurements sharing one calibration and measurement interpretation. Select thresholds on development data and freeze them before evaluation. Candidate zones cannot be tuned until held-out endpoint classification looks favorable.

Raw lines 32 to 45
46## Runnable synthetic workflow
48After the scoring command in `SKILL.md`, run from the skill directory:
50```bash
51python scripts/kde_thresholds.py relsa_scores.csv --n-thresholds 2 \
52 --plot zones.png --json zones.json --label-out zoned.csv
54for f in 0.8 0.9 1.0 1.1 1.2; do
55 python - "$f" <<'PY'
56import sys, pandas as pd
57sys.path.insert(0, "scripts")
58from kde_thresholds import find_thresholds, bw_nrd0
59v = pd.read_csv("relsa_scores.csv")["relsa"].dropna()
60bw = bw_nrd0(v.to_numpy()) * float(sys.argv[1])
61print(sys.argv[1], [round(t, 3) for t in find_thresholds(v, bandwidth=bw).thresholds])
62PY
63done
64```
66An empty result is legitimate. Do not keep shrinking bandwidth until minima appear. A
67stable minimum still needs independent welfare relevance; a bimodal sampling mixture alone
68can create it. The official R `relsa_levels` path was source-reviewed but not executed here, so it is
69not a tested fallback. Animal-level RELSA maxima used in the original
70paper's clustering are a different quantity from all-time-point KDE inputs.

Runnable synthetic workflow

After the scoring command in SKILL.md, run from the skill directory:

python scripts/kde_thresholds.py relsa_scores.csv --n-thresholds 2 \
  --plot zones.png --json zones.json --label-out zoned.csv

for f in 0.8 0.9 1.0 1.1 1.2; do
  python - "$f" <<'PY'
import sys, pandas as pd
sys.path.insert(0, "scripts")
from kde_thresholds import find_thresholds, bw_nrd0
v = pd.read_csv("relsa_scores.csv")["relsa"].dropna()
bw = bw_nrd0(v.to_numpy()) * float(sys.argv[1])
print(sys.argv[1], [round(t, 3) for t in find_thresholds(v, bandwidth=bw).thresholds])
PY
done

An empty result is legitimate. Do not keep shrinking bandwidth until minima appear. A stable minimum still needs independent welfare relevance; a bimodal sampling mixture alone can create it. The official R relsa_levels path was source-reviewed but not executed here, so it is not a tested fallback. Animal-level RELSA maxima used in the original paper's clustering are a different quantity from all-time-point KDE inputs.

Raw lines 46 to 71
Runs code python scripts/kde_thresholds.py :51
72## Welfare and regulatory interpretation
74The [European Commission severity assessment framework](https://environment.ec.europa.eu/topics/chemicals/animals-science_en)
75addresses prospective classification, monitoring during procedures and actual experienced
76severity. The [Directive](https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A32010L0063)
77uses non-recovery, mild, moderate and severe categories with procedure-specific assessment.
78No reviewed official guidance maps a RELSA value or KDE zone directly to these categories.
79A KDE output cannot replace the approved humane endpoint criteria or assessment by responsible
80personnel. No low score, empty threshold list or reassuring forecast establishes permission
81to wait when observed welfare signs require action. Record that distinction in reports.

Welfare and regulatory interpretation

The European Commission severity assessment framework addresses prospective classification, monitoring during procedures and actual experienced severity. The Directive uses non-recovery, mild, moderate and severe categories with procedure-specific assessment. No reviewed official guidance maps a RELSA value or KDE zone directly to these categories. A KDE output cannot replace the approved humane endpoint criteria or assessment by responsible personnel. No low score, empty threshold list or reassuring forecast establishes permission to wait when observed welfare signs require action. Record that distinction in reports.

Raw lines 72 to 81