Case Study: Atrial Fibrillation Ablation Outcomes
This case study demonstrates how to use CDT to build a research cohort for studying stroke and TIA outcomes in patients with atrial fibrillation, comparing those who underwent catheter ablation versus medical management alone.
Research Question
"Is the incidence of stroke or transient ischemic attack (TIA) different between atrial fibrillation patients who underwent pulmonary vein isolation versus those managed medically?"
Extraction Strategy
To answer this question, we need to extract three concept types from clinical notes:
| Step | Concept Type | Purpose |
|---|---|---|
| 1. Cohort Selection | Atrial fibrillation | Identify eligible patients |
| 2. Subcohort Assignment | Pulmonary vein isolation / catheter ablation | Divide into PVI vs no-PVI groups |
| 3. Outcome Event | Stroke / TIA | Identify outcome events |
SNOMED CT Codes
Atrial Fibrillation (Cohort Selection)
| SNOMED CT Code | Term |
|---|---|
| 49436004 | Atrial fibrillation |
| 282825002 | Paroxysmal atrial fibrillation |
| 440028005 | Permanent atrial fibrillation |
| 440059007 | Persistent atrial fibrillation |
| 706923002 | Longstanding persistent atrial fibrillation |
Note
This list may not be exhaustive.
Ablation Procedure (Subcohort Assignment)
| SNOMED CT Code | Term |
|---|---|
| 18286008 | Catheter ablation of tissue of heart |
| 431626004 | Endocardial ablation of pulmonary vein using fluoroscopic guidance with contrast |
| 1366473002 | Thoracoscopic bilateral video-assisted pulmonary vein isolation with excision of left atrial appendage |
| 1332525002 | Cardiac ablation for atrial fibrillation |
| 1363214008 | Radiofrequency ablation operation on left atrium for arrhythmia |
Note
This list may not be exhaustive.
Outcome Events (TIA / Stroke)
| SNOMED CT Code | Term |
|---|---|
| 266257000 | Transient ischemic attack |
| 230690007 | Cerebrovascular accident |
| 422504002 | Ischemic stroke |
| 432504007 | Cerebral infarction |
Note
This list may not be exhaustive.
Example Clinical Notes
Below are three example clinical letters from different patients. In a real study, you would process hundreds or thousands of such notes.
Patient A - AF with ablation, subsequent TIA
Cardiology Follow-up - 15 March 2025
67-year-old male with history of paroxysmal atrial fibrillation diagnosed in
2021, hypertension, and hyperlipidemia. Patient underwent pulmonary vein
isolation via catheter ablation in September 2023. Post-procedure, he remained
in sinus rhythm for 14 months on flecainide.
Presenting today after episode of right-sided weakness and slurred speech
lasting approximately 45 minutes yesterday, now fully resolved. MRI brain
shows no acute infarct. Assessment: Transient ischemic attack, likely
cardioembolic. Recommend resuming anticoagulation with apixaban.
Patient B - AF with ablation, no events
Electrophysiology Clinic - 20 March 2025
54-year-old female with persistent atrial fibrillation, status post catheter
ablation with pulmonary vein isolation in June 2024. She reports no
palpitations or symptoms of arrhythmia recurrence. Holter monitor shows
sinus rhythm throughout. No thromboembolic events.
Impression: Successful ablation outcome. Continue rate control medications.
Discontinue anticoagulation given CHA2DS2-VASc score of 1. Follow-up in
12 months.
Patient C - AF without ablation (medical management)
Cardiology Outpatient Letter - 10 March 2025
71-year-old female with long-standing persistent atrial fibrillation managed
with rate control strategy. Comorbidities include heart failure with preserved
ejection fraction, type 2 diabetes, and chronic kidney disease stage 3.
Patient declined catheter ablation due to procedural concerns.
Currently on metoprolol for rate control and rivaroxaban for stroke
prevention. Remains in atrial fibrillation with controlled ventricular rate.
No history of stroke or TIA. Continue current management.
Processing Notes with CDT
Submit each clinical note to the API:
curl -X POST "https://cdt-beta.healthsage.ai/generate" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"note": "67-year-old male with history of paroxysmal atrial fibrillation...",
"specialty": "Cardiology",
"letter_date": "2025-03-15"
}'
Response:
Retrieve results once processing completes:
curl "https://cdt-beta.healthsage.ai/tasks/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
-H "X-API-Key: YOUR_API_KEY"
Example API Response (Patient A)
{
"task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "SUCCESS",
"letter_date": "2025-03-15",
"patient_dob": null,
"json_data": {
"extractions": [
{
"id": "f1a2b3c4-d5e6-7890-abcd-111111111111",
"snomed_ct_code": "282825002",
"snomed_ct_term": "Paroxysmal atrial fibrillation (disorder)",
"concept_type": "disorder",
"status": "confirmed",
"date": "2021",
"source": "paroxysmal atrial fibrillation diagnosed in 2021"
},
{
"id": "f1a2b3c4-d5e6-7890-abcd-222222222222",
"snomed_ct_code": "38341003",
"snomed_ct_term": "Hypertensive disorder (disorder)",
"concept_type": "disorder",
"status": "confirmed",
"source": "hypertension"
},
{
"id": "f1a2b3c4-d5e6-7890-abcd-333333333333",
"snomed_ct_code": "55822004",
"snomed_ct_term": "Hyperlipidemia (disorder)",
"concept_type": "disorder",
"status": "confirmed",
"source": "hyperlipidemia"
},
{
"id": "f1a2b3c4-d5e6-7890-abcd-444444444444",
"snomed_ct_code": "18286008",
"snomed_ct_term": "Catheter ablation of heart (procedure)",
"concept_type": "procedure",
"status": "confirmed",
"date": "2023-09",
"source": "catheter ablation in September 2023"
},
{
"id": "f1a2b3c4-d5e6-7890-abcd-555555555555",
"snomed_ct_code": "266257000",
"snomed_ct_term": "Transient ischemic attack (disorder)",
"concept_type": "disorder",
"status": "confirmed",
"date": "2025-03",
"source": "Transient ischemic attack"
}
],
"specialty": "Cardiology",
"snomed_ct_version": "2026-01-01"
}
}
Building the Research Dataset
After processing all clinical notes, aggregate the extracted concepts into a structured dataset:
| Patient | Has AF | Subcohort | PVI Date | Has TIA/Stroke | Event Date | Time to Event |
|---|---|---|---|---|---|---|
| A | Yes | PVI | 2023-09 | Yes | 2025-03 | 18 months |
| B | Yes | PVI | 2024-06 | No | - | - |
| C | Yes | No PVI | - | No | - | - |
Processing API Responses
Extract relevant concepts from each API response:
# SNOMED CT codes for our study
AF_CODES = [
"49436004", # Atrial fibrillation
"282825002", # Paroxysmal atrial fibrillation
"440028005", # Permanent atrial fibrillation
"440059007", # Persistent atrial fibrillation
"706923002", # Longstanding persistent atrial fibrillation
]
ABLATION_CODES = [
"18286008", # Catheter ablation of tissue of heart
"431626004", # Endocardial ablation of pulmonary vein
"1366473002", # Thoracoscopic bilateral video-assisted PVI
"1332525002", # Cardiac ablation for atrial fibrillation
"1363214008", # Radiofrequency ablation on left atrium
]
OUTCOME_CODES = [
"266257000", # Transient ischemic attack
"230690007", # Cerebrovascular accident
"422504002", # Ischemic stroke
"432504007", # Cerebral infarction
]
def process_patient_response(response: dict) -> dict:
"""Extract study-relevant data from a CDT API response."""
extractions = response["json_data"]["extractions"]
# Check for AF diagnosis (cohort inclusion)
has_af = any(
e["snomed_ct_code"] in AF_CODES
for e in extractions
)
# Find ablation procedure and date (subcohort assignment)
ablation = next(
(e for e in extractions if e["snomed_ct_code"] in ABLATION_CODES),
None
)
# Check for TIA or stroke outcome
outcome = next(
(e for e in extractions if e["snomed_ct_code"] in OUTCOME_CODES),
None
)
return {
"has_af": has_af,
"has_pvi": ablation is not None,
"pvi_date": ablation["date"] if ablation else None,
"has_outcome": outcome is not None,
"outcome_date": outcome["date"] if outcome else None
}
Filtering Logic
After aggregating all patient data, apply filters to identify study cohorts:
import pandas as pd
# Load aggregated results
df = pd.read_csv("cdt_extraction_results.csv")
# Filter 1: Include only patients with confirmed AF (study cohort)
af_cohort = df[df["has_af"] == True]
# Filter 2: Divide into PVI vs no-PVI subcohorts
pvi_group = af_cohort[af_cohort["has_pvi"] == True]
no_pvi_group = af_cohort[af_cohort["has_pvi"] == False]
# Filter 3: Identify outcome events in each subcohort
pvi_with_event = pvi_group[pvi_group["has_outcome"] == True]
no_pvi_with_event = no_pvi_group[no_pvi_group["has_outcome"] == True]
# Calculate and compare event rates
pvi_rate = len(pvi_with_event) / len(pvi_group) * 100 if len(pvi_group) > 0 else 0
no_pvi_rate = len(no_pvi_with_event) / len(no_pvi_group) * 100 if len(no_pvi_group) > 0 else 0
print(f"PVI Group: {len(pvi_group)} patients")
print(f" - TIA/Stroke events: {len(pvi_with_event)} ({pvi_rate:.1f}%)")
print(f"No PVI Group: {len(no_pvi_group)} patients")
print(f" - TIA/Stroke events: {len(no_pvi_with_event)} ({no_pvi_rate:.1f}%)")
Study Cohort Summary
| Cohort | Description | Filter Criteria |
|---|---|---|
| AF Cohort | All patients with atrial fibrillation | has_af |
| PVI Subcohort | AF patients who underwent PVI/ablation | has_af AND has_pvi |
| No PVI Subcohort | AF patients without PVI (medical management) | has_af AND NOT has_pvi |
| PVI + Outcome | PVI patients with TIA/stroke | has_af AND has_pvi AND has_outcome |
| No PVI + Outcome | Medical management patients with TIA/stroke | has_af AND NOT has_pvi AND has_outcome |
These cohorts can be used to calculate incidence rates, time-to-event analyses, and compare outcomes between treatment and control groups.