acs-triage-ai
A gradient boosting decision support package for four-class triage of suspected acute coronary syndrome: NonACS, UAP (unstable angina), NSTEMI, and STEMI.
Built from a de-identified clinical dataset collected at RSUPN Dr. Cipto Mangunkusumo (RSCM), Jakarta, 2024 (n = 8,296 patients). Given a patient's demographics, vital signs, history, presenting symptoms, ECG findings, laboratory results, and standard risk scores (TIMI, GRACE, HEART), the model returns a probability distribution across the four diagnostic categories.
Status and intended use
This is a preliminary research tool and clinical decision support system. It is not a certified or regulatory-approved diagnostic device.
- It is meant to support, not replace, clinical judgment and standard diagnostic workup.
- Predictions should be reviewed by a qualified clinician alongside the full clinical picture.
- Performance figures below come from a single-center dataset and a held-out internal test split. They have not been validated on an external cohort, so they describe how the model performs on data similar to what it was trained on, not a general guarantee.
- This package accompanies an ongoing manuscript describing the model's development and validation. Cite the manuscript (see Citation below) when using this package in academic work.
What's in the box
acs_triage_ai/
├── schema.py # the exact clinical fields the model expects
├── preprocessing.py # CSV loading and feature preparation
├── model.py # ACSTriageModel: fit, predict, save, load
├── interpret.py # turns probabilities into a readable triage flag
├── train.py # command-line training script
└── predict.py # command-line scoring script
The design goal is that each piece works on its own. You can use ACSTriageModel directly in your own pipeline, or run train.py / predict.py from the command line without writing any code.
Installation
Once published:
pip install acs-triage-ai
For local development, from the project root:
pip install -e ".[dev]"
Quick start
from acs_triage_ai import ACSTriageModel, load_raw_csv, prepare_training_data
# Load a raw clinical CSV export (semicolon-delimited, comma-decimal,
# with a title row, matching the RSCM export format)
df = load_raw_csv("Dataset_SKA_RSCM_2024.csv")
X, y = prepare_training_data(df)
model = ACSTriageModel()
report = model.fit(X, y)
print(report.summary())
model.save("acs_triage_model.joblib")
Scoring new patients:
from acs_triage_ai import ACSTriageModel, prepare_features
from acs_triage_ai.interpret import interpret_batch
model = ACSTriageModel.load("acs_triage_model.joblib")
X_new = prepare_features(new_patients_df)
probabilities = model.predict_proba(X_new)
for result in interpret_batch(probabilities):
print(result)
Example output for a single patient:
Predicted class: NSTEMI
Class probabilities: NSTEMI: 99.4%, NonACS: 0.1%, STEMI: 0.3%, UAP: 0.2%
High-risk (NSTEMI/STEMI) probability: 99.6%
Flag: HIGH ATTENTION: strong model signal toward NSTEMI/STEMI. Recommend urgent clinical correlation.
Command line
# Train a model from a CSV file
acs-triage-train --data Dataset_SKA_RSCM_2024.csv --output model.joblib
# Score new patients
acs-triage-predict --model model.joblib --data new_patients.csv --output predictions.csv
Input schema
The model expects 70 clinical fields across seven groups: demographics, vitals, history, symptoms, ECG findings, labs, and risk scores. Run python -c "from acs_triage_ai import describe_schema; print(describe_schema())" to print the full breakdown, or read schema.py directly, which is the single source of truth for field names.
If your input data is missing a required column, prepare_features raises a ValueError naming exactly which column is missing, rather than failing silently or filling in a guess.
Verified performance (internal held-out split)
Trained on the full RSCM 2024 cohort (n = 8,296), stratified 80/20 split, 300-estimator gradient boosting classifier:
| Metric | Value |
|---|---|
| Accuracy | 0.937 |
| Macro F1 | 0.936 |
| Class | Precision | Recall | F1 |
|---|---|---|---|
| NonACS | 0.92 | 0.91 | 0.92 |
| UAP | 0.90 | 0.92 | 0.91 |
| NSTEMI | 0.95 | 0.97 | 0.96 |
| STEMI | 0.97 | 0.95 | 0.96 |
Top predictive features by importance: initial troponin T, ECG ST-elevation, HEART score, serial troponin T, TIMI score. This ranking is clinically consistent with how ACS is worked up in practice, which is a useful sanity check on the model, not just a numbers exercise.
These numbers come from one train/test split on one dataset. Re-run train.py on your own data or a different split to check stability before relying on them.
A note on scikit-learn versions
The bundled pretrained model is a serialized scikit-learn pipeline, and scikit-learn's pickle format is not always compatible across versions. This package pins scikit-learn>=1.9,<1.10 for that reason. If you retrain your own model with a different scikit-learn version and plan to distribute the resulting .joblib file, pin your dependency to match, or you will get a ModuleNotFoundError or InconsistentVersionWarning on someone else's machine, confirmed during testing of this package.
Extending the package
- Swap the algorithm.
ACSTriageModelwraps a scikit-learnPipeline. Replace theGradientBoostingClassifierinmodel.pywith any other scikit-learn-compatible classifier without touching the rest of the package. - Add features. Add new field names to the appropriate group in
schema.py.preprocessing.pyandmodel.pyboth read from that single list, so there is only one place to update. - Different institutions, different formats.
load_raw_csvassumes the RSCM export format (semicolon delimiter, comma decimal, title row). If your data comes from a different export, load it with plainpandas.read_csvyourself and pass the resulting DataFrame straight intoprepare_featuresorprepare_training_data. - New target granularity. If you want to collapse to a binary ACS vs. NonACS problem, or split STEMI by territory, that is a change to the
yyou pass into.fit(), not a change to the package internals.
Authors and credits
This package accompanies the manuscript:
A Four-Class Machine Learning Framework for Emergency Department Differentiation of Acute Chest Pain in a Resource-Constrained Setting
- Lies Dina Liastuti¹ ² † — corresponding author
- Averina Geffanie Suwana¹ †
- Muhammad Allam Rafi¹ — package maintainer
- Adyatma Wijaksara Aryaputra Nugraha Yudha³
- Muhammad Hannan Hunafa³
- Wisnu Jatmiko³
¹ Faculty of Medicine, Universitas Indonesia, Jakarta, Indonesia ² Department of Cardiovascular Medicine, Cipto Mangunkusumo National Referral Hospital, Jakarta, Indonesia ³ Faculty of Computer Science, Universitas Indonesia, Jakarta, Indonesia
† These authors contributed equally to this work and share co-first authorship.
Corresponding author: Lies Dina Liastuti, MD, PhD; Department of Cardiovascular Medicine, Cipto Mangunkusumo National Referral Hospital, Jl. Diponegoro No. 71, Jakarta 10430, Indonesia. Email: lies.dina11@ui.ac.id
Citation
Liastuti LD*, Suwana AG*, Rafi MA, Yudha AWAN, Hunafa MH, Jatmiko W.
A Four-Class Machine Learning Framework for Emergency Department Differentiation
of Acute Chest Pain in a Resource-Constrained Setting. [Journal/Conference, year — pending].
*These authors contributed equally and share co-first authorship.
Preliminary decision support model for acute coronary syndrome triage,
developed and validated on a single-center cohort (RSUPN Dr. Cipto Mangunkusumo, 2024).
Update the journal, volume, and page numbers once the manuscript is accepted.
Publishing this package to PyPI
- Revoke any API token that has ever been pasted into a chat, a script, or a public place. A token that has been seen outside your own machine should be treated as compromised, full stop.
- Generate a fresh token from https://pypi.org/manage/account/token/ (or https://test.pypi.org for a test upload) and store it only in a local, private
~/.pypircor as an environment variable. Never commit it or paste it into a conversation. - Build the distribution:
pip install build twine python -m build
- Upload:
twine upload dist/*
or, for a test run first:twine upload --repository testpypi dist/*
- Confirm the package name
acs-triage-aiis actually available before your first upload. PyPI names are first-come, first-served and cannot be reused once claimed by someone else; check at https://pypi.org/project/acs-triage-ai/ and rename inpyproject.tomlif it is taken.
License
MIT. See LICENSE.
Release files for acs-triage-ai 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| acs_triage_ai-0.1.2.tar.gz | 460.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| acs_triage_ai-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 928.7 kB
Release files / acs_triage_ai-0.1.2.tar.gz
| Download URL | acs_triage_ai-0.1.2.tar.gz |
|---|---|
| Size | 460.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f8b7524b98477e75ae9c2d6f41c55dfc538391a43a075cd6b4e04be7582a0f3c
|
|
BLAKE2b-256 checksum How to use checksums |
51e08ea0234aca0a712808ec45679c43803f87bacaf72e16b1820c1f4b57eb31
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.10
|
Release files / acs_triage_ai-0.1.2-py3-none-any.whl
| Download URL | acs_triage_ai-0.1.2-py3-none-any.whl |
|---|---|
| Size | 468.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
592b657f9720bcb933f6f1759ec85106daad5ffdd08da385e879aa6c20742b8f
|
|
BLAKE2b-256 checksum How to use checksums |
b681770e6425732de5c3674d1af922317251971a88199d9427eb990c11fca5b0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.10
|