amrpredict 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. amrpredict-0.3.0/.gitignore +8 -0
  2. amrpredict-0.3.0/LICENSE +21 -0
  3. amrpredict-0.3.0/PKG-INFO +304 -0
  4. amrpredict-0.3.0/README.md +253 -0
  5. amrpredict-0.3.0/docs/api-reference.md +287 -0
  6. amrpredict-0.3.0/docs/cli.md +182 -0
  7. amrpredict-0.3.0/docs/known-issues.md +139 -0
  8. amrpredict-0.3.0/docs/quickstart.md +135 -0
  9. amrpredict-0.3.0/pyproject.toml +58 -0
  10. amrpredict-0.3.0/src/amrpredict/__init__.py +259 -0
  11. amrpredict-0.3.0/src/amrpredict/_paths.py +11 -0
  12. amrpredict-0.3.0/src/amrpredict/amr_constants.py +202 -0
  13. amrpredict-0.3.0/src/amrpredict/cli.py +125 -0
  14. amrpredict-0.3.0/src/amrpredict/genome.py +496 -0
  15. amrpredict-0.3.0/src/amrpredict/lgbm.py +561 -0
  16. amrpredict-0.3.0/src/amrpredict/models/ab_rate_full.joblib +0 -0
  17. amrpredict-0.3.0/src/amrpredict/models/amr_lgbm_final_model.txt +10634 -0
  18. amrpredict-0.3.0/src/amrpredict/models/genome/feature_meta.json +536 -0
  19. amrpredict-0.3.0/src/amrpredict/models/genome/genome_metrics.json +52 -0
  20. amrpredict-0.3.0/src/amrpredict/models/genome/model.txt +10704 -0
  21. amrpredict-0.3.0/src/amrpredict/models/genome_genes/feature_meta.json +811 -0
  22. amrpredict-0.3.0/src/amrpredict/models/genome_genes/genome_metrics.json +52 -0
  23. amrpredict-0.3.0/src/amrpredict/models/genome_genes/model.txt +10961 -0
  24. amrpredict-0.3.0/src/amrpredict/models/genome_genes/species_profiles.npz +0 -0
  25. amrpredict-0.3.0/src/amrpredict/models/genus_ab_rate_full.joblib +0 -0
  26. amrpredict-0.3.0/src/amrpredict/models/lgbm_meta.joblib +0 -0
  27. amrpredict-0.3.0/src/amrpredict/models/lgbm_metrics.json +97 -0
  28. amrpredict-0.3.0/src/amrpredict/models/rl_agent/policy.npz +0 -0
  29. amrpredict-0.3.0/src/amrpredict/models/rl_agent/rl_agent.json +22 -0
  30. amrpredict-0.3.0/src/amrpredict/models/taxon_ab_rate_full.joblib +0 -0
  31. amrpredict-0.3.0/src/amrpredict/models/taxon_species.csv +13059 -0
  32. amrpredict-0.3.0/src/amrpredict/models/timeline_calibration.json +21 -0
  33. amrpredict-0.3.0/src/amrpredict/models/timeline_ml/model.txt +1683 -0
  34. amrpredict-0.3.0/src/amrpredict/models/timeline_ml/timeline_metrics.json +145 -0
  35. amrpredict-0.3.0/src/amrpredict/models/timeline_ml/timeline_ml.json +1 -0
  36. amrpredict-0.3.0/src/amrpredict/registry.py +67 -0
  37. amrpredict-0.3.0/src/amrpredict/rl_agent.py +177 -0
  38. amrpredict-0.3.0/src/amrpredict/timeline.py +275 -0
  39. amrpredict-0.3.0/src/amrpredict/timeline_ml.py +174 -0
  40. amrpredict-0.3.0/tests/test_api.py +116 -0
  41. amrpredict-0.3.0/tests/test_fasta.py +159 -0
  42. amrpredict-0.3.0/tests/test_models.py +123 -0
@@ -0,0 +1,8 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .testenv/
4
+ .venv/
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+ .pytest_cache/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hamza
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,304 @@
1
+ Metadata-Version: 2.5
2
+ Name: amrpredict
3
+ Version: 0.3.0
4
+ Summary: Antimicrobial resistance prediction from bacterial genomes and MIC metadata
5
+ Project-URL: Homepage, https://amrpredict.live
6
+ Project-URL: Source, https://github.com/hhammza/FYP1
7
+ Project-URL: Issues, https://github.com/hhammza/FYP1/issues
8
+ Author: Hamza
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 Hamza
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: amr,antimicrobial-resistance,bioinformatics,genomics,lightgbm,machine-learning
32
+ Classifier: Development Status :: 3 - Alpha
33
+ Classifier: Intended Audience :: Science/Research
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3.9
37
+ Classifier: Programming Language :: Python :: 3.10
38
+ Classifier: Programming Language :: Python :: 3.11
39
+ Classifier: Programming Language :: Python :: 3.12
40
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
41
+ Requires-Python: >=3.9
42
+ Requires-Dist: joblib>=1.3
43
+ Requires-Dist: lightgbm>=4.0
44
+ Requires-Dist: numpy>=1.24
45
+ Requires-Dist: pandas>=2.0
46
+ Provides-Extra: dev
47
+ Requires-Dist: build>=1.0; extra == 'dev'
48
+ Requires-Dist: pytest>=7.0; extra == 'dev'
49
+ Requires-Dist: twine>=4.0; extra == 'dev'
50
+ Description-Content-Type: text/markdown
51
+
52
+ # amrpredict
53
+
54
+ Antimicrobial resistance prediction from bacterial genomes and MIC metadata.
55
+
56
+ The models of the AMR Intelligence Platform (a final-year project) behind one
57
+ flat Python API and a command-line tool: the same models, and the same answers,
58
+ as the project's web app. The trained artifacts ship inside the package, so
59
+ there is nothing to download and it works offline.
60
+
61
+ ```python
62
+ import amrpredict
63
+
64
+ amrpredict.forecast('ciprofloxacin', taxon_id=562, mic_value=4)
65
+ # {'prediction': 'Resistant', 'probability': 0.7055, 'confidence': 70.6,
66
+ # 'drug_class': 'fluoroquinolone', 'model_run': 'D3_forecaster_deploy_v7', ...}
67
+ ```
68
+
69
+ ## Install
70
+
71
+ ```bash
72
+ pip install amrpredict
73
+ ```
74
+
75
+ Requires Python 3.9+. Dependencies: LightGBM, pandas, NumPy, joblib. The
76
+ download is about 6 MB because the model artifacts are bundled.
77
+
78
+ For the gene model (the most accurate genome model), also install NCBI
79
+ [AMRFinderPlus](https://github.com/ncbi/amr) so the `amrfinder` program is on
80
+ your PATH (e.g. `conda install -c bioconda ncbi-amrfinderplus`). Without it,
81
+ `predict_fasta()` uses the k-mer model.
82
+
83
+ From a checkout:
84
+
85
+ ```bash
86
+ pip install -e ".[dev]"
87
+ ```
88
+
89
+ ## The models
90
+
91
+ | Function | Model | Input | Measured on data it never saw |
92
+ |---|---|---|---|
93
+ | `forecast()` | LightGBM, calibrated | Antibiotic + organism + MIC | AUC 0.774 (lab-confirmed rows 0.908) |
94
+ | `predict_fasta()` | Gene model: LightGBM on AMRFinderPlus genes and mutations | Complete genome FASTA | Lab AUC 0.977 [0.975–0.979] |
95
+ | `predict_fasta()` without AMRFinderPlus | k-mer model: LightGBM on 4-mer frequencies | Complete genome FASTA | Lab AUC 0.935 [0.931–0.939] |
96
+ | `forecast_trend()` | Timeline ML model: LightGBM on yearly resistant shares | Genus + antibiotic | 13.98 percentage points mean error on 2017–2022 |
97
+ | `plan_treatment()` | RL agent (PPO), trained on the simulation | One of 3 antibiotics | Beats every fixed schedule in the simulation |
98
+ | `simulate_timeline()` | Biological simulation | Genome FASTA + antibiotic | **Not a trained model** |
99
+
100
+ Every trained model was tested on genomes (or years) it never saw in training.
101
+ `simulate_timeline()` is a deterministic simulation, not a learned model: it
102
+ has no accuracy score, and its output is illustrative rather than predictive.
103
+ `status()` reports `trained: False` for it, deliberately.
104
+
105
+ ## Usage
106
+
107
+ ### Resistance from metadata and an MIC
108
+
109
+ ```python
110
+ r = amrpredict.forecast(
111
+ 'ciprofloxacin',
112
+ taxon_id=562, # NCBI taxonomy ID — 562 is E. coli
113
+ mic_value=4, # mg/L
114
+ mic_sign='=', # '=', '>', '<=' ...
115
+ genus='Escherichia',
116
+ species='coli',
117
+ # threshold=None: the model's own (0.15, chosen to keep very major
118
+ # errors <= 10% on validation genomes); pass a number to override
119
+ )
120
+
121
+ print(r['prediction']) # 'Resistant'
122
+ print(r['probability']) # calibrated
123
+ print(r['evidence']['label']) # which inputs counted
124
+ ```
125
+
126
+ On 1,569,432 test rows from genomes it never saw: AUC 0.774 [0.772–0.775],
127
+ recall 91.4%, very major error 8.6%, major error 60.8% at that threshold
128
+ (`status()['lgbm_forecasting']['metrics']` has the full set). Every argument
129
+ except `antibiotic` is optional; with fewer inputs the model falls back to
130
+ population-level resistance rates.
131
+
132
+ ### Resistance from a complete genome
133
+
134
+ ```python
135
+ with open('genome.fna') as fh:
136
+ fasta = fh.read()
137
+
138
+ r = amrpredict.predict_fasta(fasta, 'ciprofloxacin')
139
+
140
+ print(r['prediction'], r['probability'])
141
+ print(r['model_used']) # 'LightGBM on AMRFinderPlus resistance genes (G_genes_deploy)'
142
+ print(r['genes_found'][:3]) # gene model: the resistance genes and mutations found
143
+ print(r['species_detected']) # gene model: the species, from the genome
144
+ print(r.get('top_kmers')) # k-mer model: the most frequent 4-mers
145
+ ```
146
+
147
+ - Upload a **complete assembly** (at least 100,000 bp); every contig is read.
148
+ - `use_genes=None` (default) picks the gene model when AMRFinderPlus is
149
+ installed, else the k-mer model; `use_genes=False` always uses the k-mer
150
+ model; `use_genes=True` requires the gene model. If AMRFinderPlus fails on
151
+ one genome, the k-mer model answers and the result has a `warning`.
152
+ - `threshold=None` uses each model's own threshold, chosen on validation
153
+ genomes for very major error near 10%.
154
+ - Bad input (too short, empty) returns a dict with `error`; it never raises.
155
+
156
+ ```python
157
+ amrpredict.identify_species(fasta)
158
+ # {'species': 'Pseudomonas aeruginosa', 'genus': 'Pseudomonas', 'distance': 0.00028}
159
+ ```
160
+
161
+ ### Yearly resistance trend and its forecast
162
+
163
+ ```python
164
+ r = amrpredict.forecast_trend('Salmonella', 'ciprofloxacin', years_ahead=5)
165
+
166
+ for h in r['history']: # observed: BV-BRC laboratory results per year
167
+ print(h['year'], h['resistant_pct'], h['n'])
168
+ for f in r['forecast']: # the model's forecast with an 80% band
169
+ print(f['year'], f['resistant_pct'], f['lo'], f['hi'])
170
+ print(r['metrics']) # its held-out error against simple baselines
171
+
172
+ amrpredict.trend_series() # {genus: [antibiotics]} with enough history
173
+ ```
174
+
175
+ Trained on 553,223 dated laboratory results (2000–2022; a year counts with at
176
+ least 20 results), it predicts each year from the years before it and was
177
+ tested on 2017–2022: mean absolute error 13.98 percentage points, against
178
+ 14.33 for "same as last year", 16.75 for a linear trend and 17.25 for the
179
+ average. The forecast is made one year at a time; the band widens with each.
180
+
181
+ ### Which drug to give each week
182
+
183
+ ```python
184
+ r = amrpredict.plan_treatment('ciprofloxacin', n_weeks=52)
185
+
186
+ print(r['best']) # the policy that keeps drugs working longest
187
+ for p in r['policies']: # the RL agent, then fixed schedules
188
+ print(p['label'], p['failure_week'], p['total_reward'])
189
+ print(r['policies'][0]['policy'][:8]) # the agent's drug for weeks 1-8
190
+ ```
191
+
192
+ A PPO agent chooses ciprofloxacin, gentamicin or imipenem each week in the
193
+ project's cycling simulation; the policies are compared on the same simulated
194
+ episode. It learned from simulated episodes only, not patient data: use it to
195
+ explore cycling strategies, not to treat patients.
196
+
197
+ ### Week-by-week simulation (not a trained model)
198
+
199
+ ```python
200
+ r = amrpredict.simulate_timeline(fasta, 'ciprofloxacin', n_weeks=8)
201
+
202
+ for week in r['timeline']:
203
+ print(week['week'], week['resistant_fraction'], week['mic_fold_change'])
204
+ print(r['failure_week'])
205
+ ```
206
+
207
+ `n_weeks=8` returns **9** entries — week 0 is the untreated baseline. Despite
208
+ the name, `resistant_fraction` and its siblings are **percentages (0–100)**.
209
+ See [Known issues](docs/known-issues.md).
210
+
211
+ ### Inspect what loaded
212
+
213
+ ```python
214
+ amrpredict.status()
215
+ # {'version': '0.3.0',
216
+ # 'lgbm_forecasting': {'trained': True, 'run_id': 'D3_forecaster_deploy_v7', 'metrics': {...}},
217
+ # 'genome_resistance': {'trained': True, 'run_id': 'G_kmer_deploy', 'searches_genes': False, ...},
218
+ # 'trend_forecast': {'trained': True, 'run_id': 'TL_timeline_ml', ...},
219
+ # 'rl_agent': {'trained': True, 'drugs': ['ciprofloxacin', 'gentamicin', 'imipenem'], ...},
220
+ # 'mutation_timeline': {'trained': False, ...}}
221
+
222
+ amrpredict.antibiotics() # the genome models' 111 antibiotics
223
+ amrpredict.antibiotics('forecast') # also 'trend' and 'rl'
224
+ ```
225
+
226
+ ## Command line
227
+
228
+ ```bash
229
+ amrpredict forecast ciprofloxacin --taxon-id 562 --mic-value 4
230
+ amrpredict predict genome.fna ciprofloxacin # --kmers or --genes to choose
231
+ amrpredict species genome.fna
232
+ amrpredict trend Salmonella ciprofloxacin --years 5
233
+ amrpredict plan ciprofloxacin --weeks 52
234
+ amrpredict timeline genome.fna ciprofloxacin --weeks 12
235
+ amrpredict antibiotics --model trend
236
+ amrpredict status
237
+ ```
238
+
239
+ Output is JSON on stdout, so it composes. Unusable input (a short FASTA, a
240
+ drug the RL agent does not know) exits 0 with an `error` key, as the Python
241
+ API returns it:
242
+
243
+ ```bash
244
+ amrpredict --compact forecast meropenem --taxon-id 287 | jq -r .prediction
245
+ cat genome.fna | amrpredict predict - ciprofloxacin
246
+ ```
247
+
248
+ Diagnostics go through `logging` to stderr, never stdout. To see them:
249
+
250
+ ```python
251
+ import logging
252
+ logging.basicConfig(level=logging.INFO)
253
+ ```
254
+
255
+ ## Using your own models
256
+
257
+ Every entry point takes `model_dir`, a folder laid out like the bundled one
258
+ (`amrpredict.default_model_dir()`): the forecaster's files at the top
259
+ (`amr_lgbm_final_model.txt`, the `*.joblib` rate tables, `lgbm_metrics.json`),
260
+ and the folders `genome/`, `genome_genes/`, `timeline_ml/` and `rl_agent/`.
261
+ They are produced by the main project's `experiments/promote.py`.
262
+
263
+ ```python
264
+ amrpredict.forecast('ciprofloxacin', taxon_id=562, model_dir='/path/to/models')
265
+ ```
266
+
267
+ ## Performance notes
268
+
269
+ Models load lazily on first use and are cached process-wide, so the first call
270
+ pays about 1–2 s and later calls are fast. A complete genome takes about a
271
+ second with the k-mer model; the gene model adds AMRFinderPlus's 10–45 s.
272
+ To release the memory: `amrpredict.registry.reset()`.
273
+
274
+ ## Changes in 0.3.0
275
+
276
+ - `predict_fasta()` uses the web app's genome models: the gene model (lab AUC
277
+ 0.977) with AMRFinderPlus, else the k-mer LightGBM (0.935). The July k-mer
278
+ RandomForest (0.695 on genomes it never saw) is removed, and with it the
279
+ scikit-learn dependency. `predict_fasta()` now needs a complete genome
280
+ (100,000 bp or more) and reads all of it.
281
+ - New: `forecast_trend()` and `trend_series()` (timeline ML model),
282
+ `plan_treatment()` (RL agent), `identify_species()`; CLI commands `trend`,
283
+ `plan` and `species`.
284
+ - `status()` reports `genome_resistance`, `trend_forecast` and `rl_agent`
285
+ (`kmer_resistance` is gone); `antibiotics()` takes the model to ask.
286
+
287
+ ## Development
288
+
289
+ ```bash
290
+ pip install -e ".[dev]"
291
+ pytest
292
+ python -m build && twine check dist/*
293
+ ```
294
+
295
+ ## Documentation
296
+
297
+ - [Quickstart](docs/quickstart.md)
298
+ - [API reference](docs/api-reference.md)
299
+ - [CLI reference](docs/cli.md)
300
+ - [Known issues](docs/known-issues.md)
301
+
302
+ ## License
303
+
304
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,253 @@
1
+ # amrpredict
2
+
3
+ Antimicrobial resistance prediction from bacterial genomes and MIC metadata.
4
+
5
+ The models of the AMR Intelligence Platform (a final-year project) behind one
6
+ flat Python API and a command-line tool: the same models, and the same answers,
7
+ as the project's web app. The trained artifacts ship inside the package, so
8
+ there is nothing to download and it works offline.
9
+
10
+ ```python
11
+ import amrpredict
12
+
13
+ amrpredict.forecast('ciprofloxacin', taxon_id=562, mic_value=4)
14
+ # {'prediction': 'Resistant', 'probability': 0.7055, 'confidence': 70.6,
15
+ # 'drug_class': 'fluoroquinolone', 'model_run': 'D3_forecaster_deploy_v7', ...}
16
+ ```
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ pip install amrpredict
22
+ ```
23
+
24
+ Requires Python 3.9+. Dependencies: LightGBM, pandas, NumPy, joblib. The
25
+ download is about 6 MB because the model artifacts are bundled.
26
+
27
+ For the gene model (the most accurate genome model), also install NCBI
28
+ [AMRFinderPlus](https://github.com/ncbi/amr) so the `amrfinder` program is on
29
+ your PATH (e.g. `conda install -c bioconda ncbi-amrfinderplus`). Without it,
30
+ `predict_fasta()` uses the k-mer model.
31
+
32
+ From a checkout:
33
+
34
+ ```bash
35
+ pip install -e ".[dev]"
36
+ ```
37
+
38
+ ## The models
39
+
40
+ | Function | Model | Input | Measured on data it never saw |
41
+ |---|---|---|---|
42
+ | `forecast()` | LightGBM, calibrated | Antibiotic + organism + MIC | AUC 0.774 (lab-confirmed rows 0.908) |
43
+ | `predict_fasta()` | Gene model: LightGBM on AMRFinderPlus genes and mutations | Complete genome FASTA | Lab AUC 0.977 [0.975–0.979] |
44
+ | `predict_fasta()` without AMRFinderPlus | k-mer model: LightGBM on 4-mer frequencies | Complete genome FASTA | Lab AUC 0.935 [0.931–0.939] |
45
+ | `forecast_trend()` | Timeline ML model: LightGBM on yearly resistant shares | Genus + antibiotic | 13.98 percentage points mean error on 2017–2022 |
46
+ | `plan_treatment()` | RL agent (PPO), trained on the simulation | One of 3 antibiotics | Beats every fixed schedule in the simulation |
47
+ | `simulate_timeline()` | Biological simulation | Genome FASTA + antibiotic | **Not a trained model** |
48
+
49
+ Every trained model was tested on genomes (or years) it never saw in training.
50
+ `simulate_timeline()` is a deterministic simulation, not a learned model: it
51
+ has no accuracy score, and its output is illustrative rather than predictive.
52
+ `status()` reports `trained: False` for it, deliberately.
53
+
54
+ ## Usage
55
+
56
+ ### Resistance from metadata and an MIC
57
+
58
+ ```python
59
+ r = amrpredict.forecast(
60
+ 'ciprofloxacin',
61
+ taxon_id=562, # NCBI taxonomy ID — 562 is E. coli
62
+ mic_value=4, # mg/L
63
+ mic_sign='=', # '=', '>', '<=' ...
64
+ genus='Escherichia',
65
+ species='coli',
66
+ # threshold=None: the model's own (0.15, chosen to keep very major
67
+ # errors <= 10% on validation genomes); pass a number to override
68
+ )
69
+
70
+ print(r['prediction']) # 'Resistant'
71
+ print(r['probability']) # calibrated
72
+ print(r['evidence']['label']) # which inputs counted
73
+ ```
74
+
75
+ On 1,569,432 test rows from genomes it never saw: AUC 0.774 [0.772–0.775],
76
+ recall 91.4%, very major error 8.6%, major error 60.8% at that threshold
77
+ (`status()['lgbm_forecasting']['metrics']` has the full set). Every argument
78
+ except `antibiotic` is optional; with fewer inputs the model falls back to
79
+ population-level resistance rates.
80
+
81
+ ### Resistance from a complete genome
82
+
83
+ ```python
84
+ with open('genome.fna') as fh:
85
+ fasta = fh.read()
86
+
87
+ r = amrpredict.predict_fasta(fasta, 'ciprofloxacin')
88
+
89
+ print(r['prediction'], r['probability'])
90
+ print(r['model_used']) # 'LightGBM on AMRFinderPlus resistance genes (G_genes_deploy)'
91
+ print(r['genes_found'][:3]) # gene model: the resistance genes and mutations found
92
+ print(r['species_detected']) # gene model: the species, from the genome
93
+ print(r.get('top_kmers')) # k-mer model: the most frequent 4-mers
94
+ ```
95
+
96
+ - Upload a **complete assembly** (at least 100,000 bp); every contig is read.
97
+ - `use_genes=None` (default) picks the gene model when AMRFinderPlus is
98
+ installed, else the k-mer model; `use_genes=False` always uses the k-mer
99
+ model; `use_genes=True` requires the gene model. If AMRFinderPlus fails on
100
+ one genome, the k-mer model answers and the result has a `warning`.
101
+ - `threshold=None` uses each model's own threshold, chosen on validation
102
+ genomes for very major error near 10%.
103
+ - Bad input (too short, empty) returns a dict with `error`; it never raises.
104
+
105
+ ```python
106
+ amrpredict.identify_species(fasta)
107
+ # {'species': 'Pseudomonas aeruginosa', 'genus': 'Pseudomonas', 'distance': 0.00028}
108
+ ```
109
+
110
+ ### Yearly resistance trend and its forecast
111
+
112
+ ```python
113
+ r = amrpredict.forecast_trend('Salmonella', 'ciprofloxacin', years_ahead=5)
114
+
115
+ for h in r['history']: # observed: BV-BRC laboratory results per year
116
+ print(h['year'], h['resistant_pct'], h['n'])
117
+ for f in r['forecast']: # the model's forecast with an 80% band
118
+ print(f['year'], f['resistant_pct'], f['lo'], f['hi'])
119
+ print(r['metrics']) # its held-out error against simple baselines
120
+
121
+ amrpredict.trend_series() # {genus: [antibiotics]} with enough history
122
+ ```
123
+
124
+ Trained on 553,223 dated laboratory results (2000–2022; a year counts with at
125
+ least 20 results), it predicts each year from the years before it and was
126
+ tested on 2017–2022: mean absolute error 13.98 percentage points, against
127
+ 14.33 for "same as last year", 16.75 for a linear trend and 17.25 for the
128
+ average. The forecast is made one year at a time; the band widens with each.
129
+
130
+ ### Which drug to give each week
131
+
132
+ ```python
133
+ r = amrpredict.plan_treatment('ciprofloxacin', n_weeks=52)
134
+
135
+ print(r['best']) # the policy that keeps drugs working longest
136
+ for p in r['policies']: # the RL agent, then fixed schedules
137
+ print(p['label'], p['failure_week'], p['total_reward'])
138
+ print(r['policies'][0]['policy'][:8]) # the agent's drug for weeks 1-8
139
+ ```
140
+
141
+ A PPO agent chooses ciprofloxacin, gentamicin or imipenem each week in the
142
+ project's cycling simulation; the policies are compared on the same simulated
143
+ episode. It learned from simulated episodes only, not patient data: use it to
144
+ explore cycling strategies, not to treat patients.
145
+
146
+ ### Week-by-week simulation (not a trained model)
147
+
148
+ ```python
149
+ r = amrpredict.simulate_timeline(fasta, 'ciprofloxacin', n_weeks=8)
150
+
151
+ for week in r['timeline']:
152
+ print(week['week'], week['resistant_fraction'], week['mic_fold_change'])
153
+ print(r['failure_week'])
154
+ ```
155
+
156
+ `n_weeks=8` returns **9** entries — week 0 is the untreated baseline. Despite
157
+ the name, `resistant_fraction` and its siblings are **percentages (0–100)**.
158
+ See [Known issues](docs/known-issues.md).
159
+
160
+ ### Inspect what loaded
161
+
162
+ ```python
163
+ amrpredict.status()
164
+ # {'version': '0.3.0',
165
+ # 'lgbm_forecasting': {'trained': True, 'run_id': 'D3_forecaster_deploy_v7', 'metrics': {...}},
166
+ # 'genome_resistance': {'trained': True, 'run_id': 'G_kmer_deploy', 'searches_genes': False, ...},
167
+ # 'trend_forecast': {'trained': True, 'run_id': 'TL_timeline_ml', ...},
168
+ # 'rl_agent': {'trained': True, 'drugs': ['ciprofloxacin', 'gentamicin', 'imipenem'], ...},
169
+ # 'mutation_timeline': {'trained': False, ...}}
170
+
171
+ amrpredict.antibiotics() # the genome models' 111 antibiotics
172
+ amrpredict.antibiotics('forecast') # also 'trend' and 'rl'
173
+ ```
174
+
175
+ ## Command line
176
+
177
+ ```bash
178
+ amrpredict forecast ciprofloxacin --taxon-id 562 --mic-value 4
179
+ amrpredict predict genome.fna ciprofloxacin # --kmers or --genes to choose
180
+ amrpredict species genome.fna
181
+ amrpredict trend Salmonella ciprofloxacin --years 5
182
+ amrpredict plan ciprofloxacin --weeks 52
183
+ amrpredict timeline genome.fna ciprofloxacin --weeks 12
184
+ amrpredict antibiotics --model trend
185
+ amrpredict status
186
+ ```
187
+
188
+ Output is JSON on stdout, so it composes. Unusable input (a short FASTA, a
189
+ drug the RL agent does not know) exits 0 with an `error` key, as the Python
190
+ API returns it:
191
+
192
+ ```bash
193
+ amrpredict --compact forecast meropenem --taxon-id 287 | jq -r .prediction
194
+ cat genome.fna | amrpredict predict - ciprofloxacin
195
+ ```
196
+
197
+ Diagnostics go through `logging` to stderr, never stdout. To see them:
198
+
199
+ ```python
200
+ import logging
201
+ logging.basicConfig(level=logging.INFO)
202
+ ```
203
+
204
+ ## Using your own models
205
+
206
+ Every entry point takes `model_dir`, a folder laid out like the bundled one
207
+ (`amrpredict.default_model_dir()`): the forecaster's files at the top
208
+ (`amr_lgbm_final_model.txt`, the `*.joblib` rate tables, `lgbm_metrics.json`),
209
+ and the folders `genome/`, `genome_genes/`, `timeline_ml/` and `rl_agent/`.
210
+ They are produced by the main project's `experiments/promote.py`.
211
+
212
+ ```python
213
+ amrpredict.forecast('ciprofloxacin', taxon_id=562, model_dir='/path/to/models')
214
+ ```
215
+
216
+ ## Performance notes
217
+
218
+ Models load lazily on first use and are cached process-wide, so the first call
219
+ pays about 1–2 s and later calls are fast. A complete genome takes about a
220
+ second with the k-mer model; the gene model adds AMRFinderPlus's 10–45 s.
221
+ To release the memory: `amrpredict.registry.reset()`.
222
+
223
+ ## Changes in 0.3.0
224
+
225
+ - `predict_fasta()` uses the web app's genome models: the gene model (lab AUC
226
+ 0.977) with AMRFinderPlus, else the k-mer LightGBM (0.935). The July k-mer
227
+ RandomForest (0.695 on genomes it never saw) is removed, and with it the
228
+ scikit-learn dependency. `predict_fasta()` now needs a complete genome
229
+ (100,000 bp or more) and reads all of it.
230
+ - New: `forecast_trend()` and `trend_series()` (timeline ML model),
231
+ `plan_treatment()` (RL agent), `identify_species()`; CLI commands `trend`,
232
+ `plan` and `species`.
233
+ - `status()` reports `genome_resistance`, `trend_forecast` and `rl_agent`
234
+ (`kmer_resistance` is gone); `antibiotics()` takes the model to ask.
235
+
236
+ ## Development
237
+
238
+ ```bash
239
+ pip install -e ".[dev]"
240
+ pytest
241
+ python -m build && twine check dist/*
242
+ ```
243
+
244
+ ## Documentation
245
+
246
+ - [Quickstart](docs/quickstart.md)
247
+ - [API reference](docs/api-reference.md)
248
+ - [CLI reference](docs/cli.md)
249
+ - [Known issues](docs/known-issues.md)
250
+
251
+ ## License
252
+
253
+ MIT — see [LICENSE](LICENSE).