Clinical DataFrame Operations
fyron.dataframe provides small, explicit helpers for deriving clinical columns from ordinary pandas DataFrames. Use it when you need ICD-10 disease-group indicators, German OPS procedure categories, stable one-hot indicators for delimited code strings, or reusable date/time interval columns before cohort construction, phenotyping, preprocessing, survival analysis, or machine learning.
This module is not a replacement for pandas and it is not a validated terminology ontology. It gives researchers transparent, reviewable feature derivations that can be saved, inspected, and challenged in a study protocol.
Install
uv add fyronImports
from fyron import dataframe as fdfAPI Contract
| Topic | Contract |
|---|---|
| Input shape | One-row-per-patient or one-row-per-event DataFrames with code or date columns. Scalar helpers also accept single code strings. |
| Required columns | Code columns named in the call, date columns for interval helpers, and optional ID columns kept by the caller for audit. |
| Return shape | DataFrame copies with derived columns, prevalence summary DataFrames, exploded long code tables, or pandas.Series interval outputs. |
| Saved artifacts | Save the enriched cohort table, code prevalence tables, date interval definitions, and the original raw code columns. |
| Failure modes | Missing columns, invalid time units, negative intervals when disallowed, malformed code strings, or overly broad categories requiring clinical review. |
When To Use It
| Task | Helper |
|---|---|
| Convert ICD-10 strings into broad comorbidity features | add_icd10_disease_groups |
| Summarize ICD-10 disease-group prevalence | icd10_group_prevalence |
| Convert German OPS strings into broad procedure categories | add_ops_categories |
| Summarize OPS category prevalence | ops_category_prevalence |
| Parse semicolon-separated code columns | split_code_string, explode_code_column |
| Add stable indicators for selected codes | add_code_indicators |
| Compute days, weeks, months, or years between dates | date_difference, add_date_difference |
| Compute age at baseline or scan date | age_at_date |
| Flag events inside an index-relative window | add_time_window_flag |
Study Pattern
In most projects this module is used early, right after extraction and before statistical modeling:
from fyron import dataframe as fdf
cohort = fdf.add_icd10_disease_groups(cohort, icd_col="icd10_codes")
cohort = fdf.add_ops_categories(cohort, ops_col="ops_codes")
cohort = fdf.age_at_date(
cohort,
birth_date_col="birth_date",
reference_date_col="index_date",
output_col="age_at_index",
)
code_qc = fdf.icd10_group_prevalence(cohort)Save both cohort and code_qc. The enriched cohort becomes the modeling table; the prevalence table becomes a lightweight audit artifact for the methods supplement or internal review.
ICD-10 Disease Groups
ICD-10 helpers use broad pragmatic chapter-style groups such as cancer, cardiovascular, respiratory, gastrointestinal, renal/urologic, trauma, external cause, and healthcare encounter. These are useful for quick cohort description and feature engineering, but they should not replace a study-specific phenotype definition or validated comorbidity score.
cohort = fdf.add_icd10_disease_groups(
cohort,
icd_col="diagnosis_codes",
sep=";",
prefix="icd10_group_",
)
prevalence = fdf.icd10_group_prevalence(cohort)The output keeps the original diagnosis_codes column and adds binary columns such as icd10_group_cancer, icd10_group_cardiovascular, plus icd10_groups and n_icd10_groups.
Built-In ICD-10 Groups
| Group | Typical ICD-10 chapter signal |
|---|---|
| Cancer | C* |
| Benign / In Situ Neoplasm | D00-D48 |
| Hematologic / Immune | D50-D89 |
| Infectious | A*, B* |
| Endocrine / Metabolic | E* |
| Mental Health | F* |
| Neurological | G* |
| Cardiovascular | I* |
| Respiratory | J* |
| Gastrointestinal | K* |
| Dermatologic | L* |
| Musculoskeletal / Autoimmune | M* |
| Renal / Urologic | N* |
| Obstetric / Perinatal | O*, P* |
| Congenital | Q* |
| Symptoms / Findings | R* |
| Trauma | S*, T* |
| Healthcare Encounter | Z* |
| External Cause | V*, W*, X*, Y* |
| Other | malformed or uncategorized non-empty codes |
OPS Procedure Categories
German OPS codes are grouped into broad procedure categories: diagnostic procedures, imaging, surgery, medication/therapy, radiation/nuclear medicine, intensive care, rehabilitation, and other. OPS coding can be site-specific, so treat these as transparent research features that still need clinical review.
cohort = fdf.add_ops_categories(
cohort,
ops_col="ops_codes",
sep=";",
prefix="ops_category_",
)
ops_summary = fdf.ops_category_prevalence(cohort)Use the summary table in supplements or QC notebooks to check whether procedure features match clinical expectations.
Built-In OPS Categories
| Category | Typical OPS chapter signal |
|---|---|
| Diagnostic Procedures | 1-*, 2-* |
| Imaging | 3-* |
| Surgery | 5-* |
| Medication / Therapy | 6-*, most 8-* therapy codes |
| Radiation / Nuclear Medicine | 7-* |
| Intensive Care | 8-98* |
| Rehabilitation | 9-* |
| Other | malformed or uncategorized non-empty codes |
Generic Code Columns
Use the generic helpers for medication codes, local registry fields, procedure codes, or any delimited string column where exact code membership matters.
long_codes = fdf.explode_code_column(
cohort,
code_col="medication_codes",
output_col="medication_code",
)
cohort = fdf.add_code_indicators(
cohort,
code_col="medication_codes",
codes=["L01XA01", "L01XA02"],
prefix="atc_",
)By default, codes are uppercased and spaces are removed. Dots are preserved unless you pass remove_dots=True through normalize_code directly. Preserve the raw source column alongside derived indicators so reviewers can trace the feature.
For multiple local definitions, pass a mapping. This gives stable, readable output names without repeating code lists across notebooks.
cohort = fdf.add_code_indicators(
cohort,
code_col="procedure_codes",
codes={
"has_biopsy": ["1-440", "1-444"],
"has_resection": ["5-324", "5-325"],
},
prefix="proc_",
)Date And Time Features
Date helpers use the same clinical time-unit convention as cohort endpoint helpers: months are 30.4375 days and years are 365.25 days.
cohort = fdf.add_date_difference(
cohort,
start_col="baseline_ct_date",
end_col="surgery_date",
output_col="days_ct_to_surgery",
unit="days",
allow_negative=False,
)
cohort = fdf.age_at_date(
cohort,
birth_date_col="birth_date",
reference_date_col="baseline_ct_date",
output_col="age_at_ct",
)
cohort = fdf.add_time_window_flag(
cohort,
date_col="biopsy_date",
index_date_col="baseline_ct_date",
output_col="biopsy_within_30d",
before=30,
after=30,
)add_time_window_flag computes the event date relative to the index date. Negative values are before the index, positive values are after the index.
Function Guide
| Function | Purpose | Returns |
|---|---|---|
normalize_code | Normalize one clinical code string. | string or None |
split_code_string | Parse one delimited code cell. | list of codes |
explode_code_column | Convert a wide delimited code column to one row per code. | DataFrame |
add_code_indicators | Add exact-code binary indicators. | DataFrame copy |
classify_icd10 | Classify one ICD-10 code into a broad disease group. | group name or None |
classify_icd10_string | Classify all ICD-10 codes in one delimited cell. | set of group names |
add_icd10_disease_groups | Add ICD-10 disease-group indicator columns. | DataFrame copy |
icd10_group_prevalence | Summarize ICD-10 group indicator columns. | prevalence DataFrame |
classify_ops | Classify one German OPS code into a broad procedure category. | category name or None |
classify_ops_string | Classify all OPS codes in one delimited cell. | set of category names |
add_ops_categories | Add OPS category indicator columns. | DataFrame copy |
ops_category_prevalence | Summarize OPS category indicator columns. | prevalence DataFrame |
date_difference | Compute interval between two date arrays/scalars. | Series |
add_date_difference | Add an interval column to a DataFrame. | DataFrame copy |
age_at_date | Add age in years at a reference date. | DataFrame copy |
add_time_window_flag | Flag whether a date falls inside an index-relative window. | DataFrame copy |
Common Pitfalls
- Broad ICD-10 and OPS groups are feature-engineering assumptions, not validated disease ontologies.
- Keep raw code columns and code-system metadata whenever possible.
- Use prefixed indicator columns to avoid spaces and slashes in downstream ML formulas.
- Check whether repeated codes should count once per patient or once per event before exploding.
- Define the index date before creating time-window flags.
- Use
allow_negative=Falsewhen a negative interval indicates a data error for the study.
Related Modules
- FHIR REST extracts source resources that often contain ICD, OPS, medication, and observation codes.
- Phenotyping builds explicit rule-based patient flags from code, lab, and medication tables.
- Cohort Tables joins derived features with endpoints and validates cohort shape.
- Preprocessing QC handles imputation, train/test encoding, and leakage checks after feature derivation.
- Machine Learning trains and evaluates models once a cohort table and feature matrix are ready.