Anomaly watch
Σειρές: anomaly.weekly_deaths.expected, anomaly.weekly_deaths.z
Code: obs/modules/anomaly.py. Agent: anomaly-watch. It probes daily at 12:30 and computes only when Eurostat's updated stamp on demo_r_mwk_ts moves. API: /v1/anomalies. Page: /en/anomalies.
Weekly deaths: EuroMOMO-style z-scores
Input. Eurostat demo_r_mwk_ts (deaths by week and sex, Cyprus, both sexes). demo_r_mwk_05 (by 5-year age group) is loaded for age-specific runs.
Baseline. For each target week, an ordinary least-squares fit is made on the 2/3-power of deaths:
y^(2/3) = b0 + b1·t + b2·sin(2πw/52.18) + b3·cos(2πw/52.18)
- t is time in years and w the ISO week.
- The fit uses the five years before the target week, ending three weeks before it.
- Like EuroMOMO, it keeps only spring and autumn weeks (ISO weeks 15-26 and 36-45). Winter and summer excesses therefore do not raise the baseline.
- The 2/3-power transformation stabilises the variance of Poisson-like counts.
- At least 40 baseline weeks are required.
z-score. z = (y^(2/3) − ŷ^(2/3)) / s, where s is the residual standard deviation of the fit (degrees of freedom n − 4). Expected deaths are ŷ back-transformed: (ŷ^(2/3))^(3/2).
Thresholds.
| z | Classification | Action |
|---|---|---|
| ≥ 4 | substantial | one anomaly event with observed, expected, z and method; never twice for the same week |
| 2 to 4 | elevated | flag shown, no event |
Expected deaths and z are stored as derived observations: anomaly.weekly_deaths.expected and anomaly.weekly_deaths.z, with quality_flag derived and the method in notes.
Differences from EuroMOMO. This is "EuroMOMO-style", not EuroMOMO. EuroMOMO uses an overdispersed Poisson GLM with similar baseline exclusions and publishes pooled European estimates. Here the model is a transparent least-squares fit on the 2/3-power scale. The results are indicative and should be checked against EuroMOMO where available.
Acceptance test. tests/test_screening_anomaly.py::test_weekly_z_flags_exactly_one_excess_week uses eight years of synthetic weekly deaths, in the test database only, with seasonality and noise and one week at 1.8 times baseline. The test expects exactly one event, for that week, and none on a re-run.
Monthly deaths by cause
Input: Eurostat hlth_cd_mro (both sexes, all ages, residents) for each ICD-10 group. Each month is compared with the same month in the previous five years (at least three needed): z = (observed − mean) / SD. A group-month with z ≥ 3 and at least 10 deaths is an elevated flag with no event, because small numbers make single causes noisy.
Hospital discharges against trend
Inputs are CYSTAT-DB 2100012E (in-patient discharges from GHS-contracted hospitals, total) and Eurostat hlth_co_inpagg (curative-care discharges). The latest year is compared with a linear trend fitted on the earlier years: residual / residual SD. With fewer than four years no trend is computed; this applies to the CYSTAT series, which begins in 2021.
Notifiable diseases: gap
The Epidemiological Surveillance Unit's bulletin is published on moh.gov.cy, whose robots.txt disallows all user agents. The comparison of notifiable-disease counts with the same weeks of prior years is therefore not made, and a gap line records why. The ECDC Surveillance Atlas has no documented public API (gap line in registry/gaps/stats.yaml).