Skip to content

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
706923002 Longstanding persistent atrial fibrillation
282825002 Paroxysmal atrial fibrillation
440028005 Permanent atrial fibrillation
440059007 Persistent atrial fibrillation

Note

This list may not be exhaustive.

Ablation Procedure (Subcohort Assignment)

SNOMED CT Code Term
1332525002 Cardiac ablation for atrial fibrillation
473229000 Catheter ablation of arrhythmogenic focus
18286008 Catheter ablation of tissue of heart
431626004 Endocardial ablation of pulmonary vein using fluoroscopic guidance with contrast
707831001 Percutaneous transluminal ablation of pulmonary vein to left atrium conducting system
1363214008 Radiofrequency ablation operation on left atrium for arrhythmia
1366473002 Thoracoscopic bilateral video-assisted pulmonary vein isolation with excision of left atrial appendage

Note

This list may not be exhaustive.

Outcome Events (TIA / Stroke)

SNOMED CT Code Term
432504007 Cerebral infarction
230690007 Cerebrovascular accident
422504002 Ischemic stroke
266257000 Transient ischemic attack

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 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:

{
  "task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "PENDING"
}

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": "44a6ceb4-953b-4dbf-a317-784d4c9203e9",
                "snomed_ct_code": "282825002",
                "snomed_ct_term": "Paroxysmal atrial fibrillation (disorder)",
                "concept_type": "disorder",
                "status": "confirmed",
                "date": "2021",
                "end_date": null,
                "location": null,
                "source": "paroxysmal atrial fibrillation",
                "start": 71,
                "end": 101
            },
            {
                "id": "be5a3e72-1944-4a0b-8023-21d3ba28c119",
                "snomed_ct_code": "38341003",
                "snomed_ct_term": "Hypertensive disorder, systemic arterial (disorder)",
                "concept_type": "disorder",
                "status": "confirmed",
                "date": null,
                "end_date": null,
                "location": null,
                "source": "hypertension",
                "start": 121,
                "end": 133
            },
            {
                "id": "5341d36c-453b-46f4-bc90-0bef69295dcb",
                "snomed_ct_code": "55822004",
                "snomed_ct_term": "Hyperlipidaemia",
                "concept_type": "disorder",
                "status": "confirmed",
                "date": null,
                "end_date": null,
                "location": null,
                "source": "hyperlipidemia",
                "start": 139,
                "end": 153
            },
            {
                "id": "a78d1d1f-f6a2-45ba-8cd0-4ff933745630",
                "snomed_ct_code": "707831001",
                "snomed_ct_term": "Percutaneous transluminal ablation of pulmonary vein to left atrium conducting system",
                "concept_type": "procedure",
                "status": "confirmed",
                "date": "2023-09",
                "end_date": null,
                "location": null,
                "source": "pulmonary vein\nisolation",
                "start": 173,
                "end": 197
            },
            {
                "id": "c3459bbb-d70f-4f33-9252-a668787ceea1",
                "snomed_ct_code": "278286009",
                "snomed_ct_term": "Right hemiparesis (disorder)",
                "concept_type": "disorder",
                "status": "confirmed",
                "date": "2025-03-14",
                "end_date": "2025-03-14",
                "location": "right",
                "source": "right-sided weakness",
                "start": 325,
                "end": 345
            },
            {
                "id": "b8b044d0-71ad-41da-90c1-737504725825",
                "snomed_ct_code": "289195008",
                "snomed_ct_term": "Slurred speech (finding)",
                "concept_type": "finding",
                "status": "confirmed",
                "date": "2025-03-14",
                "end_date": "2025-03-14",
                "location": null,
                "source": "slurred speech",
                "start": 350,
                "end": 364,
            },
            {
                "id": "ffa08d7d-011e-481e-acd0-54b223f1ab33",
                "snomed_ct_code": "816077007",
                "snomed_ct_term": "MRI of brain",
                "concept_type": "procedure",
                "status": "confirmed",
                "date": "2025-03-15",
                "end_date": null,
                "location": null,
                "source": "MRI brain",
                "start": 451,
                "end": 460
            },
            {
                "id": "0a3d4630-03eb-4ed3-8a28-505f1b56be0d",
                "snomed_ct_code": "266257000",
                "snomed_ct_term": "Transient ischemic attack (disorder)",
                "concept_type": "disorder",
                "status": "confirmed",
                "date": "2025-03-14",
                "end_date": "2025-03-14",
                "location": "right",
                "source": "Transient ischemic attack",
                "start": 475,
                "end": 500,
            },
            {
                "id": "7ee71ddc-2bb8-4df0-9a0d-4e78c5653c37",
                "snomed_ct_code": "1251566005",
                "snomed_ct_term": "Embolism from heart",
                "concept_type": "disorder",
                "status": "provisional",
                "date": "2025-03-14",
                "end_date": null,
                "location": null,
                "source": "cardioembolic",
                "start": 509,
                "end": 522,
            }
        ],
        "specialty": "Cardiology",
        "snomed_ct_version": "2026-01-01"
    },
    // ...
}

Processing API Responses

To process the API responses, we can extract the relevant concept and format them as follows:

from typing import Any
from pydantic import BaseModel

AF_CODES = [
    "49436004",   # Atrial fibrillation
    "706923002",  # Longstanding persistent atrial fibrillation
    "282825002",  # Paroxysmal atrial fibrillation
    "440028005",  # Permanent atrial fibrillation
    "440059007",  # Persistent atrial fibrillation
]

ABLATION_CODES = [
    "1332525002",  # Cardiac ablation for atrial fibrillation
    "473229000",   # Catheter ablation of arrhythmogenic focus
    "18286008",    # Catheter ablation of tissue of heart
    "431626004",   # Endocardial ablation of pulmonary vein
    "707831001",   # Percutaneous transluminal ablation of pulmonary vein
    "1363214008",  # Radiofrequency ablation on left atrium
    "1366473002",  # Thoracoscopic bilateral video-assisted PVI
]

OUTCOME_CODES = [
    "432504007",  # Cerebral infarction
    "230690007",  # Cerebrovascular accident
    "422504002",  # Ischemic stroke
    "266257000",  # Transient ischemic attack
]

class PatientData(BaseModel):
    patient_id: str
    has_af: bool
    has_pvi: bool
    pvi_date: str | None
    has_outcome: bool
    outcome_date: str | None

def process_patient_response(patient_id: str, response: dict[str, Any]) -> PatientData:
    """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 PatientData(
        patient_id=patient_id,
        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
    )

patient_A_data = process_patient_response("A", patient_A_response)
patient_B_data = process_patient_response("B", patient_B_response)
patient_C_data = process_patient_response("C", patient_C_response)
records = [patient_A_data.model_dump(), patient_B_data.model_dump(), patient_C_data.model_dump()]
df = pd.DataFrame(records)

This will produce something of the form:

patient_id has_af has_pvi pvi_date has_outcome outcome_date
A True True 2023-09 True 2025-03-14
B True True 2024-06 False N/A
C True False N/A False N/A

Suggested Analyses

With a sufficiently large cohort, the structured table above enables several analyses:

  • Incidence comparison: Compare the proportion of stroke/TIA events (has_outcome) between the PVI group (has_pvi = True) and the medical management group (has_pvi = False).
  • Time-to-event analysis: Using pvi_date and outcome_date, compute time from ablation to outcome and construct Kaplan-Meier survival curves with a log-rank test comparing the two groups.
  • Cox proportional hazards model: Model the hazard of stroke/TIA as a function of PVI status, adjusting for covariates that could be extracted from additional CDT fields (e.g., comorbidities).