Skip to main content

quiq

Convert MIMIC-IV clinical data into QUIQ (Quality Intelligence Unified Query) long-format table. Use when transforming MIMIC-IV tables to QUIQ format for data quality assessment, when applying QUIQ Mapping_info rules to MIMIC-IV variables, or when building a standardized long-format dataset from MIMIC-IV for quality management programs.

Jump to install

Source facts

Repository
28sungmin/m4-add-skills
Last source activity
July 9, 2026 at 10:57
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
3 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
quiq
description
Convert MIMIC-IV clinical data into QUIQ (Quality Intelligence Unified Query) long-format table. Use when transforming MIMIC-IV tables to QUIQ format for data quality assessment, when applying QUIQ Mapping_info rules to MIMIC-IV variables, or when building a standardized long-format dataset from MIMIC-IV for quality management programs.
tier
community
category
lydus
parameters
{"bq_project":{"description":"BigQuery project ID where MIMIC-IV data is stored. Varies by institution — PhysioNet public access uses 'physionet-data'; institutions with their own copy use their own project ID (e.g. 'cmi-lab').","default":"physionet-data","type":"string"}}
# MIMIC-IV → QUIQ Format Conversion Converts all MIMIC-IV tables (hosp, icu, ed schemas) into the QUIQ long-format table used by the LYDUS quality management program. Each original row becomes one or more QUIQ rows depending on table type (wide, code, or event). ## When to Use This Skill - User asks to convert MIMIC-IV data to QUIQ format - User wants to apply QUIQ Mapping_info rules to MIMIC-IV variables - User needs a standardized long-format output for data quality assessment - User references 가이드라인 제4권 §1.5 or QUIQ table structure ## QUIQ Table Schema | Column | Description | |--------|-------------| | `Primary_key` | Row identifier (shared across rows from same original record) | | `Variable_ID` | itemid for event tables, empty otherwise | | `Original_table_name` | Source table (e.g., `ADMISSIONS`, `LABEVENTS`) | | `Variable_name` | Column name or d_items/d_labitems label | | `Event_date` | Measurement timestamp (NULL for non-event variables) | | `Value` | String representation of the value | | `Unit` | Unit of measurement — **only** from an explicit unit/uom field in the source (e.g. `valueuom`, `amountuom`, d_items `unitname`). Empty (`''`) when the source has no unit field. **Never** infer from the variable name, the value, or clinical knowledge. | | `Variable_type` | `timestamp` / `numeric` / `string` / `` (empty) | | `Is_categorical` | `'1'` if categorical, `'0'` otherwise | | `Recorder` | (empty in MIMIC) | | `Recorder_position` | (empty in MIMIC) | | `Recorder_affiliation` | (empty in MIMIC) | | `Patient_id` | `subject_id` as STRING | | `Admission_id` | `hadm_id` as STRING (empty for tables without hadm_id) | | `Ground_truth` | (empty) | | `Mapping_info_1` | Primary mapping category (see Mapping Rules) | | `Mapping_info_2` | Secondary mapping subcategory | ## Mapping Rules (가이드라인 §1.5.2) | Rule | Condition | Mapping_info_1 | Mapping_info_2 | |------|-----------|----------------|----------------| | 3 | Medical codes (ICD, NDC, GSN, HCPCS, DRG) | `medical_code` | NULL | | 4 | Lab events | `event` | `lab_event` | | 4 | Chart/vital events | `event` | `chart_event` | | 4 | I&O events (input/output/ingredient) | `event` | NULL | | 5 | Date/time columns | `date` | NULL | | 6 | Diagnosis names (icd_title, chiefcomplaint) | `diagnosis` | NULL | | 7 | Drug names (medication, drug, name) | `prescription` | `drug` | | 7 | Prescription info (dose, route, frequency) | `prescription` | `prescription_info` | | 8 | Procedure events (procedureevents) | `procedure` | NULL | | — | Clinical notes (discharge summaries) | `note_clinical` | `DIS` / `ADM` / `EME` / `SUR` / NULL | | — | Radiology reports | `note_rad` | `CXR` / `AXR` / `SXR` / `CCT` / `ACT` / `BCT` / `SCT` / `ECH` / NULL | | — | All others | NULL | NULL | ## Conversion Strategy by Table Type ### ① Wide Tables (UNPIVOT) Single row → multiple QUIQ rows (one per column). `Event_date = NULL`. - **ADMISSIONS**: admittime/dischtime/deathtime → `date` - **PATIENTS**: dod → `date` - **TRANSFERS**: intime/outtime → `date` - **EMAR**: medication → `prescription/drug` - **PHARMACY**: medication → `prescription/drug`; route/frequency/dose → `prescription/prescription_info` - **PRESCRIPTIONS**: drug → `prescription/drug`; gsn/ndc/formulary_drug_cd → `medical_code` - **DIAGNOSES_ICD**: icd_code → `medical_code` - **HCPCSEVENTS**: hcpcs_cd → `medical_code`; short_description → `procedure` ### ④ Note Tables (MIMIC_IV_NOTE, base + all CTE pattern) One original note row → 4 QUIQ rows sharing the same Primary_key. | Table | Variable_name | Event_date | Mapping_info_1 | Variable_ID | |-------|--------------|------------|----------------|-------------| | DISCHARGE | `text` | charttime | `note_clinical` (note_type=`DS`) | '' | | DISCHARGE | `storetime` | NULL | `date` | '' | | DISCHARGE | `note_type` | NULL | NULL | '' | | DISCHARGE | `note_seq` | NULL | NULL | '' | | RADIOLOGY | `text` | charttime | `note_rad` (note_type=`RR`/`AR`) | '' | | RADIOLOGY | `storetime` | NULL | `date` | '' | | RADIOLOGY | `note_type` | NULL | NULL | '' | | RADIOLOGY | `note_seq` | NULL | NULL | '' | | DISCHARGE_DETAIL | field_name | NULL | `note_clinical` | '' | | RADIOLOGY_DETAIL | field_name | NULL | `note_rad` | '' | `discharge_detail` / `radiology_detail` are JOIN-ed to their parent table on `note_id` to obtain `hadm_id`. ### ② Event Tables (base + all CTE pattern) One original row → multiple QUIQ rows sharing the same Primary_key. ``` q_XXX_base: JOIN d_items/d_labitems → build all columns q_XXX_all: UNION ALL with _rtype ordering ① main value → _m1, _m2 (lab/chart/event/procedure) ② date cols → _m1='date', _m2=NULL ③ extra cols → NULL, NULL ``` | Table | Main value column | _m1 | _m2 | |-------|-------------------|-----|-----| | LABEVENTS | value/valuenum | `event` | `lab_event` | | CHARTEVENTS | value/valuenum | `event` | `chart_event` | | DATETIMEEVENTS | value | `event` | `chart_event` | | INGREDIENTEVENTS | amount | `event` | NULL | | INPUTEVENTS | amount | `event` | NULL | | OUTPUTEVENTS | value | `event` | NULL | | PROCEDUREEVENTS | value | `procedure` | NULL | ### Event_date Assignment - `Event_date = charttime or starttime` for the main measurement row - `Event_date = NULL` for date columns written as rows (storetime, endtime, etc.) - `Event_date = _ev` for secondary measurements tied to the same time (valuenum, warning, flag) ## BigQuery Implementation The complete BigQuery SQL is in `scripts/bigquery.sql`. Key BigQuery differences from DuckDB: | Feature | DuckDB (v5) | BigQuery | |---------|-------------|---------| | Functions | `CREATE MACRO` | `CREATE TEMP FUNCTION` | | Type detection | `TRY_STRPTIME`, `TRY_CAST AS DOUBLE` | `SAFE.PARSE_TIMESTAMP`, `SAFE_CAST AS FLOAT64` | | String type | `VARCHAR` | `STRING` | | UNPIVOT | `INTO NAME k VALUE v` | `FOR k IN (cols)` | | Reserved words | `"value"`, `"name"` | `` `value` ``, `` `name` `` | | Table names | `hosp.admissions` | `mimiciv_hosp.admissions` | | Output | `COPY (...) TO 'file.csv'` | Plain `SELECT` | ### How to run with M4 MCP ```python import os from google.cloud import bigquery # NOTE: m4.execute_query blocks multi-statement SQL (SecurityError). # This SQL uses CREATE TEMP FUNCTION → must use google.cloud.bigquery directly. skill_dir = os.path.dirname(os.path.abspath(__file__)) with open(os.path.join(skill_dir, "scripts/bigquery.sql")) as f: sql = f.read() # parameters.bq_project: BigQuery project ID where MIMIC-IV data is stored # Change to your institution's project ID if you host your own copy of MIMIC-IV bq_project = "physionet-data" # e.g. "cmi-lab" for CMI lab bq_billing_project = bq_project + "-492906" # billing project (may differ) sql = sql.replace("{bq_project}", bq_project) # Institution-specific dataset name overrides (if needed) # e.g. cmi-lab uses MIMIC_IV_ED instead of mimiciv_ed # sql = sql.replace("mimiciv_ed.", "MIMIC_IV_ED.") # Optional: filter by patient cohort (subject_id list) # Wraps each source table in a subquery — avoids full table scans # PIDS = "(10000032, 10000068, 10001217)" # comma-separated subject_ids # wide_tables = [ # "mimiciv_3_1_hosp.admissions", "mimiciv_3_1_hosp.patients", # "mimiciv_3_1_hosp.transfers", "mimiciv_3_1_hosp.omr", # "mimiciv_3_1_hosp.drgcodes", "mimiciv_3_1_hosp.emar", # "mimiciv_3_1_hosp.emar_detail", "mimiciv_3_1_hosp.hcpcsevents", # "mimiciv_3_1_hosp.microbiologyevents", "mimiciv_3_1_hosp.pharmacy", # "mimiciv_3_1_hosp.poe", "mimiciv_3_1_hosp.poe_detail", # "mimiciv_3_1_hosp.prescriptions", "mimiciv_3_1_hosp.services", # "mimiciv_3_1_hosp.diagnoses_icd", "mimiciv_3_1_hosp.procedures_icd", # "mimiciv_3_1_icu.icustays", # "MIMIC_IV_ED.diagnosis", "MIMIC_IV_ED.edstays", # "MIMIC_IV_ED.medrecon", "MIMIC_IV_ED.pyxis", # "MIMIC_IV_ED.triage", "MIMIC_IV_ED.vitalsign", # ] # for tbl in wide_tables: # sql = sql.replace( # f" FROM `{bq_project}`.{tbl}\n", # f" FROM (SELECT * FROM `{bq_project}`.{tbl} WHERE subject_id IN {PIDS})\n" # ) # for tbl, alias in [ # ("mimiciv_3_1_hosp.labevents", "le"), # ("mimiciv_3_1_icu.chartevents", "ce"), # ("mimiciv_3_1_icu.datetimeevents", "de"), # ("mimiciv_3_1_icu.ingredientevents", "ie"), # ("mimiciv_3_1_icu.inputevents", "ie"), # ("mimiciv_3_1_icu.outputevents", "oe"), # ("mimiciv_3_1_icu.procedureevents", "pe"), # ]: # sql = sql.replace( # f" FROM `{bq_project}`.{tbl} {alias}\n", # f" FROM (SELECT * FROM `{bq_project}`.{tbl} WHERE subject_id IN {PIDS}) {alias}\n" # ) client = bigquery.Client(project=bq_billing_project) df = client.query(sql).to_dataframe() # Returns pd.DataFrame with all QUIQ columns # Save to CSV output_path = "quiq_output.csv" df.to_csv(output_path, index=False, encoding="utf-8-sig") print(f"Saved {len(df):,} rows → {output_path}") ``` > **Note**: The SQL uses `CREATE TEMP FUNCTION` (multi-statement). `m4.execute_query()` blocks multi-statement SQL with SecurityError — use `google.cloud.bigquery.Client` directly instead. ## Critical Implementation Notes 1. **Primary_key is NOT globally unique** — it is unique only within each source table's CTE. The combination of `(Original_table_name, Primary_key)` uniquely identifies a source record. 2. **Event_date is selective** — Only clinically meaningful timestamps appear as `Event_date`. Administrative dates (admittime, storetime as standalone rows) use `Event_date = NULL` per §1.5.5. 3. **Empty string vs NULL** — `Value = ''` means the original field was NULL. Used as a filter: `WHERE raw_val IS NOT NULL` removes these in UNPIVOT-based tables. 4. **d_items JOIN** — ICU event tables use `COALESCE(di.label, CAST(itemid AS STRING))` so the Variable_name always has a human-readable label even if d_items has no matching row.
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub