Refactor DeepHealth indices around disease expression
This commit is contained in:
@@ -1,137 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
LABELS = Path("labels.csv")
|
||||
OUT = Path("icd10_organ_label_mapping.csv")
|
||||
|
||||
|
||||
ICD10_CHAPTERS = [
|
||||
("A00", "B99", "I", "Certain infectious and parasitic diseases", "infection_immune"),
|
||||
("C00", "D48", "II", "Neoplasms", "neoplasm"),
|
||||
("D50", "D89", "III", "Diseases of the blood and immune mechanism", "hematologic_immune"),
|
||||
("E00", "E90", "IV", "Endocrine, nutritional and metabolic diseases", "metabolic_endocrine"),
|
||||
("F00", "F99", "V", "Mental and behavioural disorders", "mental_behavioral"),
|
||||
("G00", "G99", "VI", "Diseases of the nervous system", "neurologic"),
|
||||
("H00", "H59", "VII", "Diseases of the eye and adnexa", "sensory_eye"),
|
||||
("H60", "H95", "VIII", "Diseases of the ear and mastoid process", "sensory_ear"),
|
||||
("I00", "I99", "IX", "Diseases of the circulatory system", "cardiovascular"),
|
||||
("J00", "J99", "X", "Diseases of the respiratory system", "respiratory"),
|
||||
("K00", "K93", "XI", "Diseases of the digestive system", "digestive_liver"),
|
||||
("L00", "L99", "XII", "Diseases of the skin and subcutaneous tissue", "skin_soft_tissue"),
|
||||
("M00", "M99", "XIII", "Diseases of the musculoskeletal system", "musculoskeletal"),
|
||||
("N00", "N99", "XIV", "Diseases of the genitourinary system", "genitourinary_renal"),
|
||||
("O00", "O99", "XV", "Pregnancy, childbirth and puerperium", "pregnancy_reproductive"),
|
||||
("P00", "P96", "XVI", "Certain conditions originating in the perinatal period", "perinatal"),
|
||||
("Q00", "Q99", "XVII", "Congenital malformations", "congenital"),
|
||||
("R00", "R99", "XVIII", "Symptoms, signs and abnormal findings", "symptoms_findings"),
|
||||
("S00", "T98", "XIX", "Injury, poisoning and external causes", "injury_poisoning"),
|
||||
("V01", "Y98", "XX", "External causes of morbidity and mortality", "external_causes"),
|
||||
("Z00", "Z99", "XXI", "Factors influencing health status", "health_status_factors"),
|
||||
("U00", "U99", "XXII", "Codes for special purposes", "special_purpose"),
|
||||
]
|
||||
|
||||
|
||||
ORGAN_OVERRIDES = [
|
||||
("I60", "I69", "brain_vascular"),
|
||||
("N17", "N19", "kidney"),
|
||||
("K70", "K77", "liver"),
|
||||
("E10", "E14", "diabetes_metabolic"),
|
||||
("F00", "F09", "cognition_neuropsychiatric"),
|
||||
("G30", "G32", "cognition_neurodegenerative"),
|
||||
("H53", "H54", "sensory_vision"),
|
||||
("H90", "H91", "sensory_hearing"),
|
||||
("J40", "J47", "chronic_respiratory"),
|
||||
("C00", "D48", "neoplasm"),
|
||||
]
|
||||
|
||||
|
||||
def _code_key(code: str) -> tuple[str, int, str]:
|
||||
code = code.strip().upper()
|
||||
match = re.match(r"^([A-Z])(\d{2})(?:\.?([A-Z0-9]+))?", code)
|
||||
if not match:
|
||||
raise ValueError(f"Invalid ICD-10 code: {code!r}")
|
||||
letter, number, suffix = match.groups()
|
||||
return letter, int(number), suffix or ""
|
||||
|
||||
|
||||
def _code_in_range(code: str, start: str, end: str) -> bool:
|
||||
c_letter, c_num, _ = _code_key(code)
|
||||
s_letter, s_num, _ = _code_key(start)
|
||||
e_letter, e_num, _ = _code_key(end)
|
||||
if s_letter == e_letter:
|
||||
return c_letter == s_letter and s_num <= c_num <= e_num
|
||||
return (s_letter < c_letter < e_letter) or (
|
||||
c_letter == s_letter and c_num >= s_num
|
||||
) or (c_letter == e_letter and c_num <= e_num)
|
||||
|
||||
|
||||
def _chapter_for_code(code: str) -> tuple[str, str, str]:
|
||||
if not re.match(r"^[A-Z]\d{2}", code.strip().upper()):
|
||||
return "", "", "unmapped"
|
||||
for start, end, chapter_id, chapter_name, default_system in ICD10_CHAPTERS:
|
||||
if _code_in_range(code, start, end):
|
||||
return chapter_id, chapter_name, default_system
|
||||
return "", "", "unmapped"
|
||||
|
||||
|
||||
def _organ_system_for_code(code: str, default_system: str) -> str:
|
||||
if default_system == "unmapped":
|
||||
return "unmapped"
|
||||
for start, end, organ_system in ORGAN_OVERRIDES:
|
||||
if _code_in_range(code, start, end):
|
||||
return organ_system
|
||||
return default_system
|
||||
|
||||
|
||||
def main() -> None:
|
||||
rows = []
|
||||
with LABELS.open(encoding="utf-8") as f:
|
||||
for i, line in enumerate(f):
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split(maxsplit=1)
|
||||
code = parts[0].strip().upper()
|
||||
name = parts[1].strip() if len(parts) > 1 else ""
|
||||
chapter_id, chapter_name, default_system = _chapter_for_code(code)
|
||||
organ_system = _organ_system_for_code(code, default_system)
|
||||
rows.append(
|
||||
{
|
||||
"token_id": i + 3,
|
||||
"label_code": code,
|
||||
"label_name": name,
|
||||
"icd10_chapter_id": chapter_id,
|
||||
"icd10_chapter_name": chapter_name,
|
||||
"organ_system": organ_system,
|
||||
"organ_weight": 1.0 if organ_system != "unmapped" else 0.0,
|
||||
"match_source": "icd10_chapter_range",
|
||||
}
|
||||
)
|
||||
|
||||
fieldnames = [
|
||||
"token_id",
|
||||
"label_code",
|
||||
"label_name",
|
||||
"icd10_chapter_id",
|
||||
"icd10_chapter_name",
|
||||
"organ_system",
|
||||
"organ_weight",
|
||||
"match_source",
|
||||
]
|
||||
with OUT.open("w", newline="", encoding="utf-8-sig") as f:
|
||||
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
||||
writer.writeheader()
|
||||
writer.writerows(rows)
|
||||
|
||||
print(f"labels: {len(rows)}")
|
||||
print(f"output: {OUT}")
|
||||
systems = sorted({row["organ_system"] for row in rows})
|
||||
print("organ_systems:", ", ".join(systems))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
157
build_organ_involvement_label_mapping.py
Normal file
157
build_organ_involvement_label_mapping.py
Normal file
@@ -0,0 +1,157 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
LABELS = Path("labels.csv")
|
||||
OUT = Path("organ_involvement_label_mapping.csv")
|
||||
|
||||
|
||||
ORGANS = [
|
||||
"brain_neurologic",
|
||||
"heart",
|
||||
"artery_vascular",
|
||||
"immune",
|
||||
"intestine_digestive",
|
||||
"kidney",
|
||||
"liver",
|
||||
"lung",
|
||||
"muscle_musculoskeletal",
|
||||
"pancreas_endocrine",
|
||||
"adipose_metabolic",
|
||||
"female_reproductive",
|
||||
"male_reproductive",
|
||||
"neoplasm",
|
||||
]
|
||||
|
||||
|
||||
def _code_key(code: str) -> tuple[str, int, str]:
|
||||
code = code.strip().upper()
|
||||
match = re.match(r"^([A-Z])(\d{2})(?:\.?([A-Z0-9]+))?", code)
|
||||
if not match:
|
||||
raise ValueError(f"Invalid ICD-10 code: {code!r}")
|
||||
letter, number, suffix = match.groups()
|
||||
return letter, int(number), suffix or ""
|
||||
|
||||
|
||||
def _in_range(code: str, start: str, end: str) -> bool:
|
||||
c_letter, c_num, _ = _code_key(code)
|
||||
s_letter, s_num, _ = _code_key(start)
|
||||
e_letter, e_num, _ = _code_key(end)
|
||||
if s_letter == e_letter:
|
||||
return c_letter == s_letter and s_num <= c_num <= e_num
|
||||
return (
|
||||
(s_letter < c_letter < e_letter)
|
||||
or (c_letter == s_letter and c_num >= s_num)
|
||||
or (c_letter == e_letter and c_num <= e_num)
|
||||
)
|
||||
|
||||
|
||||
def _matches_any(code: str, ranges: list[tuple[str, str]]) -> bool:
|
||||
return any(_in_range(code, start, end) for start, end in ranges)
|
||||
|
||||
|
||||
def organ_for_icd10(code: str) -> tuple[str, str]:
|
||||
code = code.strip().upper()
|
||||
if not re.match(r"^[A-Z]\d{2}", code):
|
||||
return "", "unmapped_non_icd10"
|
||||
|
||||
if _matches_any(code, [("C00", "D48")]):
|
||||
return "neoplasm", "neoplasm_c00_d48"
|
||||
|
||||
if _matches_any(code, [("F00", "F09"), ("G00", "G99"), ("I60", "I69")]):
|
||||
return "brain_neurologic", "f00_f09_g00_g99_i60_i69"
|
||||
|
||||
if _matches_any(code, [("I00", "I09"), ("I20", "I52")]):
|
||||
return "heart", "i00_i09_i20_i52"
|
||||
|
||||
if _matches_any(code, [("I10", "I15"), ("I70", "I89"), ("I95", "I99")]):
|
||||
return "artery_vascular", "i10_i15_i70_i89_i95_i99"
|
||||
|
||||
if _matches_any(code, [("A00", "B99"), ("D50", "D89")]):
|
||||
return "immune", "a00_b99_d50_d89"
|
||||
|
||||
if _matches_any(code, [("J00", "J99")]):
|
||||
return "lung", "j00_j99"
|
||||
|
||||
if _matches_any(code, [("K70", "K77")]):
|
||||
return "liver", "k70_k77"
|
||||
|
||||
if _matches_any(code, [("K85", "K86"), ("E10", "E16")]):
|
||||
return "pancreas_endocrine", "k85_k86_e10_e16"
|
||||
|
||||
if _matches_any(code, [("K00", "K69"), ("K78", "K84"), ("K87", "K93")]):
|
||||
return "intestine_digestive", "k00_k69_k78_k84_k87_k93"
|
||||
|
||||
if _matches_any(code, [("N00", "N39")]):
|
||||
return "kidney", "n00_n39"
|
||||
|
||||
if _matches_any(code, [("N70", "N98"), ("O00", "O99")]):
|
||||
return "female_reproductive", "n70_n98_o00_o99"
|
||||
|
||||
if _matches_any(code, [("N40", "N53")]):
|
||||
return "male_reproductive", "n40_n53"
|
||||
|
||||
if _matches_any(code, [("M00", "M99")]):
|
||||
return "muscle_musculoskeletal", "m00_m99"
|
||||
|
||||
if _matches_any(code, [("E00", "E09"), ("E17", "E90")]):
|
||||
return "adipose_metabolic", "e00_e09_e17_e90"
|
||||
|
||||
return "", "unmapped_no_organ_rule"
|
||||
|
||||
|
||||
def main() -> None:
|
||||
rows = []
|
||||
with LABELS.open(encoding="utf-8") as f:
|
||||
for i, line in enumerate(f):
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split(maxsplit=1)
|
||||
code = parts[0].strip().upper()
|
||||
name = parts[1].strip() if len(parts) > 1 else ""
|
||||
organ_id, match_source = organ_for_icd10(code)
|
||||
rows.append(
|
||||
{
|
||||
"token_id": i + 3,
|
||||
"label_code": code,
|
||||
"label_name": name,
|
||||
"organ_id": organ_id,
|
||||
"organ_label": organ_id,
|
||||
"organ_weight": 1.0 if organ_id else 0.0,
|
||||
"match_source": match_source,
|
||||
"mapping_source": (
|
||||
"organ-age-inspired clinical systems based on "
|
||||
"Oh et al. Nature 2023; single-label ICD-10 rules"
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
fieldnames = [
|
||||
"token_id",
|
||||
"label_code",
|
||||
"label_name",
|
||||
"organ_id",
|
||||
"organ_label",
|
||||
"organ_weight",
|
||||
"match_source",
|
||||
"mapping_source",
|
||||
]
|
||||
with OUT.open("w", newline="", encoding="utf-8-sig") as f:
|
||||
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
||||
writer.writeheader()
|
||||
writer.writerows(rows)
|
||||
|
||||
mapped = [row for row in rows if row["organ_id"]]
|
||||
print(f"labels: {len(rows)}")
|
||||
print(f"mapped_labels: {len(mapped)}")
|
||||
print(f"unmapped_labels: {len(rows) - len(mapped)}")
|
||||
print(f"organs: {', '.join(ORGANS)}")
|
||||
print(f"output: {OUT}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
215
build_uk_hfrs_label_mapping.py
Normal file
215
build_uk_hfrs_label_mapping.py
Normal file
@@ -0,0 +1,215 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
LABELS = Path("labels.csv")
|
||||
OUT = Path("uk_hfrs_label_mapping.csv")
|
||||
MISSING_OUT = Path("uk_hfrs_missing_label_codes.csv")
|
||||
|
||||
|
||||
# Source: Gilbert T, Neuburger J, Kraindler J, et al. Development and
|
||||
# validation of a Hospital Frailty Risk Score focusing on older people in
|
||||
# acute care settings using electronic hospital records. Lancet. 2018.
|
||||
# Supplementary appendix, Table A2.
|
||||
UK_HFRS_WEIGHTS = {
|
||||
"F00": 7.1,
|
||||
"G81": 4.4,
|
||||
"G30": 4.0,
|
||||
"I69": 3.7,
|
||||
"R29": 3.6,
|
||||
"N39": 3.2,
|
||||
"F05": 3.2,
|
||||
"W19": 3.2,
|
||||
"S00": 3.2,
|
||||
"R31": 3.0,
|
||||
"B96": 2.9,
|
||||
"R41": 2.7,
|
||||
"R26": 2.6,
|
||||
"I67": 2.6,
|
||||
"R56": 2.6,
|
||||
"R40": 2.5,
|
||||
"T83": 2.4,
|
||||
"S06": 2.4,
|
||||
"S42": 2.3,
|
||||
"E87": 2.3,
|
||||
"M25": 2.3,
|
||||
"E86": 2.3,
|
||||
"R54": 2.2,
|
||||
"Z50": 2.1,
|
||||
"F03": 2.1,
|
||||
"W18": 2.1,
|
||||
"Z75": 2.0,
|
||||
"F01": 2.0,
|
||||
"S80": 2.0,
|
||||
"L03": 2.0,
|
||||
"H54": 1.9,
|
||||
"E53": 1.9,
|
||||
"Z60": 1.8,
|
||||
"G20": 1.8,
|
||||
"R55": 1.8,
|
||||
"S22": 1.8,
|
||||
"K59": 1.8,
|
||||
"N17": 1.8,
|
||||
"L89": 1.7,
|
||||
"Z22": 1.7,
|
||||
"B95": 1.7,
|
||||
"L97": 1.6,
|
||||
"R44": 1.6,
|
||||
"K26": 1.6,
|
||||
"I95": 1.6,
|
||||
"N19": 1.6,
|
||||
"A41": 1.6,
|
||||
"Z87": 1.5,
|
||||
"J96": 1.5,
|
||||
"X59": 1.5,
|
||||
"M19": 1.5,
|
||||
"G40": 1.5,
|
||||
"M81": 1.4,
|
||||
"S72": 1.4,
|
||||
"S32": 1.4,
|
||||
"E16": 1.4,
|
||||
"R94": 1.4,
|
||||
"N18": 1.4,
|
||||
"R33": 1.3,
|
||||
"R69": 1.3,
|
||||
"N28": 1.3,
|
||||
"R32": 1.2,
|
||||
"G31": 1.2,
|
||||
"Y95": 1.2,
|
||||
"S09": 1.2,
|
||||
"R45": 1.2,
|
||||
"G45": 1.2,
|
||||
"Z74": 1.1,
|
||||
"M79": 1.1,
|
||||
"W06": 1.1,
|
||||
"S01": 1.1,
|
||||
"A04": 1.1,
|
||||
"A09": 1.1,
|
||||
"J18": 1.1,
|
||||
"J69": 1.0,
|
||||
"R47": 1.0,
|
||||
"E55": 1.0,
|
||||
"Z93": 1.0,
|
||||
"R02": 1.0,
|
||||
"R63": 0.9,
|
||||
"H91": 0.9,
|
||||
"W10": 0.9,
|
||||
"W01": 0.9,
|
||||
"E05": 0.9,
|
||||
"M41": 0.9,
|
||||
"R13": 0.8,
|
||||
"Z99": 0.8,
|
||||
"U80": 0.8,
|
||||
"M80": 0.8,
|
||||
"K92": 0.8,
|
||||
"I63": 0.8,
|
||||
"N20": 0.7,
|
||||
"F10": 0.7,
|
||||
"Y84": 0.7,
|
||||
"R00": 0.7,
|
||||
"J22": 0.7,
|
||||
"Z73": 0.6,
|
||||
"R79": 0.6,
|
||||
"Z91": 0.5,
|
||||
"S51": 0.5,
|
||||
"F32": 0.5,
|
||||
"M48": 0.5,
|
||||
"E83": 0.4,
|
||||
"M15": 0.4,
|
||||
"D64": 0.4,
|
||||
"L08": 0.4,
|
||||
"R11": 0.3,
|
||||
"K52": 0.3,
|
||||
"R50": 0.1,
|
||||
}
|
||||
|
||||
|
||||
def _read_labels(path: Path) -> list[dict[str, str | int]]:
|
||||
rows: list[dict[str, str | int]] = []
|
||||
with path.open(encoding="utf-8") as f:
|
||||
for i, line in enumerate(f):
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
parts = line.split(maxsplit=1)
|
||||
code = parts[0].strip().upper()
|
||||
name = parts[1].strip() if len(parts) > 1 else ""
|
||||
rows.append({"token_id": i + 3, "label_code": code, "label_name": name})
|
||||
return rows
|
||||
|
||||
|
||||
def main() -> None:
|
||||
labels = _read_labels(LABELS)
|
||||
label_codes = {str(row["label_code"]) for row in labels}
|
||||
missing = sorted(set(UK_HFRS_WEIGHTS) - label_codes)
|
||||
|
||||
rows = []
|
||||
for row in labels:
|
||||
code = str(row["label_code"])
|
||||
weight = float(UK_HFRS_WEIGHTS.get(code, 0.0))
|
||||
rows.append(
|
||||
{
|
||||
**row,
|
||||
"hfrs_dimension_id": "hfrs_weighted_disease_expression",
|
||||
"hfrs_dimension": "DeepHealth HFRS-weighted disease expression",
|
||||
"hfrs_key_area": "UK-HFRS",
|
||||
"hfrs_weight": weight,
|
||||
"hfrs_source": (
|
||||
"Gilbert et al. Lancet 2018 supplementary appendix Table A2"
|
||||
),
|
||||
"match_source": "exact_three_character_icd10" if weight else "not_in_hfrs",
|
||||
}
|
||||
)
|
||||
|
||||
fieldnames = [
|
||||
"token_id",
|
||||
"label_code",
|
||||
"label_name",
|
||||
"hfrs_dimension_id",
|
||||
"hfrs_dimension",
|
||||
"hfrs_key_area",
|
||||
"hfrs_weight",
|
||||
"hfrs_source",
|
||||
"match_source",
|
||||
]
|
||||
with OUT.open("w", newline="", encoding="utf-8-sig") as f:
|
||||
writer = csv.DictWriter(f, fieldnames=fieldnames)
|
||||
writer.writeheader()
|
||||
writer.writerows(rows)
|
||||
|
||||
with MISSING_OUT.open("w", newline="", encoding="utf-8-sig") as f:
|
||||
writer = csv.DictWriter(
|
||||
f,
|
||||
fieldnames=[
|
||||
"hfrs_source_code",
|
||||
"hfrs_weight",
|
||||
"missing_reason",
|
||||
"hfrs_source",
|
||||
],
|
||||
)
|
||||
writer.writeheader()
|
||||
for code in missing:
|
||||
writer.writerow(
|
||||
{
|
||||
"hfrs_source_code": code,
|
||||
"hfrs_weight": UK_HFRS_WEIGHTS[code],
|
||||
"missing_reason": "not_present_in_labels_csv",
|
||||
"hfrs_source": (
|
||||
"Gilbert et al. Lancet 2018 supplementary appendix Table A2"
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
nonzero = sum(1 for row in rows if float(row["hfrs_weight"]) != 0.0)
|
||||
print(f"labels: {len(rows)}")
|
||||
print(f"uk_hfrs_codes: {len(UK_HFRS_WEIGHTS)}")
|
||||
print(f"matched_nonzero_labels: {nonzero}")
|
||||
print(f"missing_hfrs_codes: {len(missing)}")
|
||||
print(f"output: {OUT}")
|
||||
print(f"missing_output: {MISSING_OUT}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
364
burden_index.py
364
burden_index.py
@@ -2,12 +2,13 @@ from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any, Literal, Sequence
|
||||
from typing import Any, Sequence
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
|
||||
from eval_data import load_sequence_eval_dataset
|
||||
from evaluate_auc_v2 import (
|
||||
build_model_from_dataset,
|
||||
load_checkpoint_state_dict,
|
||||
@@ -16,15 +17,11 @@ from evaluate_auc_v2 import (
|
||||
resolve_dist_mode_for_checkpoint,
|
||||
validate_dataset_metadata,
|
||||
)
|
||||
from eval_data import load_sequence_eval_dataset
|
||||
from targets import CHECKUP_IDX, NO_EVENT_IDX, PAD_IDX
|
||||
|
||||
|
||||
FormedBurdenMode = Literal["observed", "model_weighted"]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BurdenContext:
|
||||
class DeepHealthContext:
|
||||
model: torch.nn.Module
|
||||
dataset: Any
|
||||
cfg: dict[str, Any]
|
||||
@@ -34,33 +31,35 @@ class BurdenContext:
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DiseaseBurdenResult:
|
||||
disease_id: int
|
||||
formed: float
|
||||
future: float
|
||||
total: float
|
||||
formed_mode: str
|
||||
horizon: float
|
||||
class DiseaseExpressionResult:
|
||||
disease_ids: np.ndarray
|
||||
expression: np.ndarray
|
||||
t_query: float
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BurdenIndexResult:
|
||||
historical: np.ndarray
|
||||
future: np.ndarray
|
||||
total: np.ndarray
|
||||
class OrganInvolvementResult:
|
||||
organ_ids: list[str]
|
||||
involvement: np.ndarray
|
||||
disease_ids: np.ndarray
|
||||
formed: np.ndarray
|
||||
disease_future: np.ndarray
|
||||
disease_total: np.ndarray
|
||||
formed_mode: str
|
||||
horizon: float
|
||||
expression: np.ndarray
|
||||
t_query: float
|
||||
|
||||
|
||||
def load_burden_context(
|
||||
@dataclass(frozen=True)
|
||||
class FrailtyRiskResult:
|
||||
frailty_risk_index: float
|
||||
disease_ids: np.ndarray
|
||||
expression: np.ndarray
|
||||
weights: np.ndarray
|
||||
t_query: float
|
||||
|
||||
|
||||
def load_deephealth_context(
|
||||
run_path: str | Path,
|
||||
*,
|
||||
device: str | torch.device | None = None,
|
||||
) -> BurdenContext:
|
||||
) -> DeepHealthContext:
|
||||
run_path = Path(run_path)
|
||||
config_path = run_path / "train_config.json"
|
||||
model_ckpt_path = run_path / "best_model.pt"
|
||||
@@ -73,13 +72,13 @@ def load_burden_context(
|
||||
model_target_mode = str(cfg.get("model_target_mode", "next_token")).lower()
|
||||
if model_target_mode == "next_token":
|
||||
raise RuntimeError(
|
||||
"Burden Index computation requires an all_future checkpoint because "
|
||||
"it uses p_d(h, Delta). The provided run is model_target_mode='next_token'."
|
||||
"Disease expression indices require an all_future checkpoint because "
|
||||
"they use p_d(h, Delta). The provided run is model_target_mode='next_token'."
|
||||
)
|
||||
if model_target_mode != "all_future":
|
||||
raise ValueError(
|
||||
"train_config.json model_target_mode must be all_future for burden "
|
||||
f"computation, got {model_target_mode!r}."
|
||||
"train_config.json model_target_mode must be all_future, got "
|
||||
f"{model_target_mode!r}."
|
||||
)
|
||||
|
||||
device_obj = torch.device(
|
||||
@@ -88,20 +87,17 @@ def load_burden_context(
|
||||
if device_obj.type == "cuda" and not torch.cuda.is_available():
|
||||
raise RuntimeError(f"Requested device {device_obj}, but CUDA is not available.")
|
||||
|
||||
data_prefix = cfg.get("data_prefix", "ukb")
|
||||
labels_file = cfg.get("labels_file", "labels.csv")
|
||||
extra_info_types = cfg.get("extra_info_types", None)
|
||||
dataset = load_sequence_eval_dataset(
|
||||
model_target_mode="all_future",
|
||||
data_prefix=data_prefix,
|
||||
labels_file=labels_file,
|
||||
data_prefix=cfg.get("data_prefix", "ukb"),
|
||||
labels_file=cfg.get("labels_file", "labels.csv"),
|
||||
no_event_interval_years=float(cfg.get("no_event_interval_years", 5.0)),
|
||||
include_no_event_in_uts_target=bool(
|
||||
cfg.get("include_no_event_in_uts_target", False)
|
||||
),
|
||||
min_history_events=int(cfg.get("all_future_min_history_events", 1)),
|
||||
min_future_events=int(cfg.get("all_future_min_future_events", 1)),
|
||||
extra_info_types=extra_info_types,
|
||||
extra_info_types=cfg.get("extra_info_types", None),
|
||||
)
|
||||
validate_dataset_metadata(dataset, cfg)
|
||||
|
||||
@@ -115,12 +111,11 @@ def load_burden_context(
|
||||
|
||||
cfg_model = dict(cfg)
|
||||
cfg_model["dist_mode"] = dist_mode
|
||||
args = _ConfigNamespace()
|
||||
model = build_model_from_dataset(args, cfg_model, dataset)
|
||||
model = build_model_from_dataset(_ConfigNamespace(), cfg_model, dataset)
|
||||
load_model_state(model, state_dict)
|
||||
model.eval().to(device_obj)
|
||||
|
||||
return BurdenContext(
|
||||
return DeepHealthContext(
|
||||
model=model,
|
||||
dataset=dataset,
|
||||
cfg=cfg,
|
||||
@@ -131,56 +126,9 @@ def load_burden_context(
|
||||
|
||||
|
||||
@torch.inference_mode()
|
||||
def compute_disease_burden(
|
||||
def compute_disease_expression(
|
||||
*,
|
||||
run_path: str | Path,
|
||||
disease_id: int,
|
||||
event_seq: Sequence[int] | np.ndarray,
|
||||
time_seq: Sequence[float] | np.ndarray,
|
||||
sex: int,
|
||||
other_type: Sequence[int] | np.ndarray,
|
||||
other_value: Sequence[float] | np.ndarray,
|
||||
other_value_kind: Sequence[int] | np.ndarray,
|
||||
other_time: Sequence[float] | np.ndarray,
|
||||
t_query: float,
|
||||
horizon: float,
|
||||
formed_mode: FormedBurdenMode,
|
||||
device: str | torch.device | None = None,
|
||||
context: BurdenContext | None = None,
|
||||
) -> DiseaseBurdenResult:
|
||||
ctx = context or load_burden_context(run_path, device=device)
|
||||
disease_ids = np.asarray([int(disease_id)], dtype=np.int64)
|
||||
formed, future_prob = _compute_disease_components(
|
||||
ctx=ctx,
|
||||
disease_ids=disease_ids,
|
||||
event_seq=event_seq,
|
||||
time_seq=time_seq,
|
||||
sex=sex,
|
||||
other_type=other_type,
|
||||
other_value=other_value,
|
||||
other_value_kind=other_value_kind,
|
||||
other_time=other_time,
|
||||
t_query=float(t_query),
|
||||
horizon=float(horizon),
|
||||
formed_mode=formed_mode,
|
||||
)
|
||||
future = (1.0 - formed) * future_prob
|
||||
total = formed + future
|
||||
return DiseaseBurdenResult(
|
||||
disease_id=int(disease_id),
|
||||
formed=float(formed[0]),
|
||||
future=float(future[0]),
|
||||
total=float(total[0]),
|
||||
formed_mode=str(formed_mode),
|
||||
horizon=float(horizon),
|
||||
)
|
||||
|
||||
|
||||
@torch.inference_mode()
|
||||
def compute_burden_index(
|
||||
*,
|
||||
run_path: str | Path,
|
||||
burden_matrix: np.ndarray,
|
||||
disease_ids: Sequence[int] | np.ndarray,
|
||||
event_seq: Sequence[int] | np.ndarray,
|
||||
time_seq: Sequence[float] | np.ndarray,
|
||||
@@ -190,26 +138,12 @@ def compute_burden_index(
|
||||
other_value_kind: Sequence[int] | np.ndarray,
|
||||
other_time: Sequence[float] | np.ndarray,
|
||||
t_query: float,
|
||||
horizon: float,
|
||||
formed_mode: FormedBurdenMode,
|
||||
device: str | torch.device | None = None,
|
||||
context: BurdenContext | None = None,
|
||||
) -> BurdenIndexResult:
|
||||
ctx = context or load_burden_context(run_path, device=device)
|
||||
context: DeepHealthContext | None = None,
|
||||
) -> DiseaseExpressionResult:
|
||||
ctx = context or load_deephealth_context(run_path, device=device)
|
||||
disease_ids_arr = np.asarray(disease_ids, dtype=np.int64)
|
||||
if disease_ids_arr.ndim != 1 or disease_ids_arr.size == 0:
|
||||
raise ValueError("disease_ids must be a non-empty 1D sequence.")
|
||||
|
||||
A = np.asarray(burden_matrix, dtype=np.float64)
|
||||
if A.ndim != 2:
|
||||
raise ValueError(f"burden_matrix must be 2D, got shape {A.shape}")
|
||||
if A.shape[1] != disease_ids_arr.size:
|
||||
raise ValueError(
|
||||
"burden_matrix columns must match disease_ids length, got "
|
||||
f"{A.shape[1]} columns vs {disease_ids_arr.size} disease ids."
|
||||
)
|
||||
|
||||
formed, future_prob = _compute_disease_components(
|
||||
expression = model_implied_disease_expression(
|
||||
ctx=ctx,
|
||||
disease_ids=disease_ids_arr,
|
||||
event_seq=event_seq,
|
||||
@@ -220,36 +154,48 @@ def compute_burden_index(
|
||||
other_value_kind=other_value_kind,
|
||||
other_time=other_time,
|
||||
t_query=float(t_query),
|
||||
horizon=float(horizon),
|
||||
formed_mode=formed_mode,
|
||||
)
|
||||
disease_future = (1.0 - formed) * future_prob
|
||||
disease_total = formed + disease_future
|
||||
|
||||
historical = A @ formed
|
||||
future = A @ disease_future
|
||||
total = A @ disease_total
|
||||
return BurdenIndexResult(
|
||||
historical=historical,
|
||||
future=future,
|
||||
total=total,
|
||||
return DiseaseExpressionResult(
|
||||
disease_ids=disease_ids_arr.copy(),
|
||||
formed=formed,
|
||||
disease_future=disease_future,
|
||||
disease_total=disease_total,
|
||||
formed_mode=str(formed_mode),
|
||||
horizon=float(horizon),
|
||||
expression=expression,
|
||||
t_query=float(t_query),
|
||||
)
|
||||
|
||||
|
||||
class _ConfigNamespace:
|
||||
def __getattr__(self, _name: str) -> None:
|
||||
return None
|
||||
|
||||
|
||||
def _compute_disease_components(
|
||||
def compute_organ_involvement_from_expression(
|
||||
*,
|
||||
ctx: BurdenContext,
|
||||
expression: Sequence[float] | np.ndarray,
|
||||
organ_matrix: np.ndarray,
|
||||
) -> np.ndarray:
|
||||
z = np.asarray(expression, dtype=np.float64)
|
||||
A = np.asarray(organ_matrix, dtype=np.float64)
|
||||
if A.ndim != 2:
|
||||
raise ValueError(f"organ_matrix must be 2D, got shape {A.shape}")
|
||||
if z.ndim != 1 or A.shape[1] != z.size:
|
||||
raise ValueError(
|
||||
"expression must be 1D and match organ_matrix columns, got "
|
||||
f"{z.shape} and {A.shape}"
|
||||
)
|
||||
intensity = -np.log1p(-np.clip(z, 0.0, 1.0 - 1e-7))
|
||||
return -np.expm1(-(A @ intensity))
|
||||
|
||||
|
||||
def compute_frailty_risk_from_expression(
|
||||
*,
|
||||
expression: Sequence[float] | np.ndarray,
|
||||
hfrs_weights: Sequence[float] | np.ndarray,
|
||||
) -> float:
|
||||
z = np.asarray(expression, dtype=np.float64)
|
||||
w = np.asarray(hfrs_weights, dtype=np.float64)
|
||||
if z.shape != w.shape:
|
||||
raise ValueError(f"expression and hfrs_weights shape mismatch: {z.shape} vs {w.shape}")
|
||||
return float(np.dot(w, z))
|
||||
|
||||
|
||||
@torch.inference_mode()
|
||||
def model_implied_disease_expression(
|
||||
*,
|
||||
ctx: DeepHealthContext,
|
||||
disease_ids: np.ndarray,
|
||||
event_seq: Sequence[int] | np.ndarray,
|
||||
time_seq: Sequence[float] | np.ndarray,
|
||||
@@ -259,41 +205,30 @@ def _compute_disease_components(
|
||||
other_value_kind: Sequence[int] | np.ndarray,
|
||||
other_time: Sequence[float] | np.ndarray,
|
||||
t_query: float,
|
||||
horizon: float,
|
||||
formed_mode: FormedBurdenMode,
|
||||
) -> tuple[np.ndarray, np.ndarray]:
|
||||
formed_mode = _validate_formed_mode(formed_mode)
|
||||
) -> np.ndarray:
|
||||
disease_ids = np.asarray(disease_ids, dtype=np.int64)
|
||||
_validate_disease_ids(ctx, disease_ids)
|
||||
event_seq_arr, time_seq_arr = _validate_event_inputs(event_seq, time_seq)
|
||||
other_type_arr, other_value_arr, other_value_kind_arr, other_time_arr = (
|
||||
_validate_other_inputs(other_type, other_value, other_value_kind, other_time)
|
||||
)
|
||||
if horizon < 0:
|
||||
raise ValueError(f"horizon must be non-negative, got {horizon}")
|
||||
grid = build_readout_grid(
|
||||
event_seq=event_seq_arr,
|
||||
time_seq=time_seq_arr,
|
||||
other_type=other_type_arr,
|
||||
other_time=other_time_arr,
|
||||
t_query=float(t_query),
|
||||
)
|
||||
if grid.size == 0:
|
||||
return np.zeros(disease_ids.size, dtype=np.float64)
|
||||
|
||||
if formed_mode == "observed":
|
||||
formed = _observed_formed_burden(
|
||||
disease_ids=disease_ids,
|
||||
event_seq=event_seq_arr,
|
||||
time_seq=time_seq_arr,
|
||||
t_query=t_query,
|
||||
)
|
||||
else:
|
||||
formed = _model_weighted_formed_burden(
|
||||
ctx=ctx,
|
||||
disease_ids=disease_ids,
|
||||
event_seq=event_seq_arr,
|
||||
time_seq=time_seq_arr,
|
||||
sex=sex,
|
||||
other_type=other_type_arr,
|
||||
other_value=other_value_arr,
|
||||
other_value_kind=other_value_kind_arr,
|
||||
other_time=other_time_arr,
|
||||
t_query=t_query,
|
||||
)
|
||||
end_times = np.concatenate([grid[1:], np.asarray([t_query], dtype=np.float32)])
|
||||
deltas = np.maximum(end_times - grid, 0.0).astype(np.float32)
|
||||
valid = deltas > 0
|
||||
if not np.any(valid):
|
||||
return np.zeros(disease_ids.size, dtype=np.float64)
|
||||
|
||||
hidden_query = _query_hidden(
|
||||
hidden = query_hidden(
|
||||
ctx=ctx,
|
||||
event_seq=event_seq_arr,
|
||||
time_seq=time_seq_arr,
|
||||
@@ -302,84 +237,19 @@ def _compute_disease_components(
|
||||
other_value=other_value_arr,
|
||||
other_value_kind=other_value_kind_arr,
|
||||
other_time=other_time_arr,
|
||||
query_times=np.asarray([t_query], dtype=np.float32),
|
||||
query_times=grid[valid].astype(np.float32),
|
||||
)
|
||||
future_prob = _probabilities_from_hidden(
|
||||
ctx=ctx,
|
||||
hidden=hidden_query,
|
||||
disease_ids=disease_ids,
|
||||
deltas=np.asarray([horizon], dtype=np.float32),
|
||||
)[0]
|
||||
return formed.astype(np.float64), future_prob.astype(np.float64)
|
||||
|
||||
|
||||
def _model_weighted_formed_burden(
|
||||
*,
|
||||
ctx: BurdenContext,
|
||||
disease_ids: np.ndarray,
|
||||
event_seq: np.ndarray,
|
||||
time_seq: np.ndarray,
|
||||
sex: int,
|
||||
other_type: np.ndarray,
|
||||
other_value: np.ndarray,
|
||||
other_value_kind: np.ndarray,
|
||||
other_time: np.ndarray,
|
||||
t_query: float,
|
||||
) -> np.ndarray:
|
||||
grid = _build_readout_grid(
|
||||
event_seq=event_seq,
|
||||
time_seq=time_seq,
|
||||
other_type=other_type,
|
||||
other_time=other_time,
|
||||
t_query=t_query,
|
||||
)
|
||||
if grid.size == 0:
|
||||
return np.zeros(disease_ids.size, dtype=np.float64)
|
||||
|
||||
end_times = np.concatenate([grid[1:], np.asarray([t_query], dtype=np.float32)])
|
||||
deltas = np.maximum(end_times - grid, 0.0).astype(np.float32)
|
||||
if np.all(deltas <= 0):
|
||||
return np.zeros(disease_ids.size, dtype=np.float64)
|
||||
|
||||
hidden = _query_hidden(
|
||||
ctx=ctx,
|
||||
event_seq=event_seq,
|
||||
time_seq=time_seq,
|
||||
sex=sex,
|
||||
other_type=other_type,
|
||||
other_value=other_value,
|
||||
other_value_kind=other_value_kind,
|
||||
other_time=other_time,
|
||||
query_times=grid.astype(np.float32),
|
||||
)
|
||||
interval_prob = _probabilities_from_hidden(
|
||||
interval_prob = probabilities_from_hidden(
|
||||
ctx=ctx,
|
||||
hidden=hidden,
|
||||
disease_ids=disease_ids,
|
||||
deltas=deltas,
|
||||
).astype(np.float64)
|
||||
survival = np.prod(1.0 - np.clip(interval_prob, 0.0, 1.0), axis=0)
|
||||
return 1.0 - survival
|
||||
|
||||
|
||||
def _observed_formed_burden(
|
||||
*,
|
||||
disease_ids: np.ndarray,
|
||||
event_seq: np.ndarray,
|
||||
time_seq: np.ndarray,
|
||||
t_query: float,
|
||||
) -> np.ndarray:
|
||||
valid = (
|
||||
(time_seq <= np.float32(t_query))
|
||||
& (event_seq > PAD_IDX)
|
||||
& (event_seq != CHECKUP_IDX)
|
||||
& (event_seq != NO_EVENT_IDX)
|
||||
deltas=deltas[valid],
|
||||
)
|
||||
observed = set(int(x) for x in event_seq[valid].tolist())
|
||||
return np.asarray([1.0 if int(d) in observed else 0.0 for d in disease_ids])
|
||||
survival = np.prod(1.0 - np.clip(interval_prob, 0.0, 1.0), axis=0)
|
||||
return (1.0 - survival).astype(np.float64, copy=False)
|
||||
|
||||
|
||||
def _build_readout_grid(
|
||||
def build_readout_grid(
|
||||
*,
|
||||
event_seq: np.ndarray,
|
||||
time_seq: np.ndarray,
|
||||
@@ -400,9 +270,10 @@ def _build_readout_grid(
|
||||
return np.unique(times)
|
||||
|
||||
|
||||
def _query_hidden(
|
||||
@torch.inference_mode()
|
||||
def query_hidden(
|
||||
*,
|
||||
ctx: BurdenContext,
|
||||
ctx: DeepHealthContext,
|
||||
event_seq: np.ndarray,
|
||||
time_seq: np.ndarray,
|
||||
sex: int,
|
||||
@@ -430,31 +301,24 @@ def _query_hidden(
|
||||
tq = torch.from_numpy(query_times.astype(np.float32, copy=False)).float()
|
||||
|
||||
event = event.to(ctx.device)
|
||||
times = times.to(ctx.device)
|
||||
other_t = other_t.to(ctx.device)
|
||||
other_v = other_v.to(ctx.device)
|
||||
other_k = other_k.to(ctx.device)
|
||||
other_tm = other_tm.to(ctx.device)
|
||||
sex_t = sex_t.to(ctx.device)
|
||||
tq = tq.to(ctx.device)
|
||||
|
||||
return ctx.model(
|
||||
event_seq=event,
|
||||
time_seq=times,
|
||||
sex=sex_t,
|
||||
time_seq=times.to(ctx.device),
|
||||
sex=sex_t.to(ctx.device),
|
||||
padding_mask=event > PAD_IDX,
|
||||
t_query=tq,
|
||||
other_type=other_t,
|
||||
other_value=other_v,
|
||||
other_value_kind=other_k,
|
||||
other_time=other_tm,
|
||||
t_query=tq.to(ctx.device),
|
||||
other_type=other_t.to(ctx.device),
|
||||
other_value=other_v.to(ctx.device),
|
||||
other_value_kind=other_k.to(ctx.device),
|
||||
other_time=other_tm.to(ctx.device),
|
||||
target_mode="all_future",
|
||||
)
|
||||
|
||||
|
||||
def _probabilities_from_hidden(
|
||||
@torch.inference_mode()
|
||||
def probabilities_from_hidden(
|
||||
*,
|
||||
ctx: BurdenContext,
|
||||
ctx: DeepHealthContext,
|
||||
hidden: torch.Tensor,
|
||||
disease_ids: np.ndarray,
|
||||
deltas: np.ndarray,
|
||||
@@ -489,16 +353,12 @@ def _probabilities_from_hidden(
|
||||
return prob.detach().cpu().numpy().astype(np.float64, copy=False)
|
||||
|
||||
|
||||
def _validate_formed_mode(mode: str) -> FormedBurdenMode:
|
||||
if mode not in {"observed", "model_weighted"}:
|
||||
raise ValueError(
|
||||
"formed_mode must be either 'observed' or 'model_weighted', "
|
||||
f"got {mode!r}."
|
||||
)
|
||||
return mode # type: ignore[return-value]
|
||||
class _ConfigNamespace:
|
||||
def __getattr__(self, _name: str) -> None:
|
||||
return None
|
||||
|
||||
|
||||
def _validate_disease_ids(ctx: BurdenContext, disease_ids: np.ndarray) -> None:
|
||||
def _validate_disease_ids(ctx: DeepHealthContext, disease_ids: np.ndarray) -> None:
|
||||
if disease_ids.ndim != 1 or disease_ids.size == 0:
|
||||
raise ValueError("disease_ids must be a non-empty 1D array.")
|
||||
vocab_size = int(getattr(ctx.model, "vocab_size", ctx.model.risk_head.out_features))
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
\documentclass[11pt]{article}
|
||||
|
||||
\usepackage[margin=1in]{geometry}
|
||||
\usepackage{amsmath, amssymb, amsfonts}
|
||||
\usepackage{bm}
|
||||
\usepackage{amsmath, amssymb}
|
||||
\usepackage{booktabs}
|
||||
\usepackage{enumitem}
|
||||
\usepackage{hyperref}
|
||||
|
||||
\title{DeepHealth Burden Indices: Dynamic Organ and Functional Burden}
|
||||
\title{DeepHealth Disease Expression, Organ Involvement, and Frailty Risk Indices}
|
||||
\author{}
|
||||
\date{}
|
||||
|
||||
@@ -16,561 +15,147 @@
|
||||
\maketitle
|
||||
|
||||
\begin{abstract}
|
||||
DeepHealth produces a query-time hidden representation \(h(t)\) and
|
||||
disease-specific future risk functions \(p_d(h,\Delta)\). These disease-level
|
||||
outputs are clinically granular but difficult to interpret directly as a
|
||||
patient-level health state. We therefore define Burden Indices (BI) that
|
||||
aggregate historical and predicted disease burden into higher-level,
|
||||
interpretable dimensions. The Organ Burden Index (OBI) maps diseases to
|
||||
anatomical systems, while the Functional Burden Index (FBI) maps diseases to
|
||||
function- and frailty-related burden domains, anchored by CIHI-HFRM-style
|
||||
diagnosis weights when available. For formed burden, we distinguish an
|
||||
observed-anchored version based on actual historical diagnoses and a
|
||||
model-weighted version based on DeepHealth's historical risk trajectory. The
|
||||
indices are burden measures, not direct health reserve measures, because the
|
||||
current model is supervised by disease events rather than direct functional
|
||||
outcomes such as ADL/IADL, gait speed, grip strength, cognition, or recovery
|
||||
capacity.
|
||||
DeepHealth provides a query-time hidden state \(h(t)\) and disease-specific
|
||||
risk functions \(p_d(h,\Delta)\). We use these outputs to define a continuous
|
||||
disease expression rate \(z_d(t)\). This quantity should be interpreted as how
|
||||
much disease \(d\) is model-implied to have formed or expressed by query time
|
||||
\(t\), not as true physiological damage. Based on \(z_d(t)\), we define two
|
||||
downstream indices: an organ involvement index, which summarizes whether an
|
||||
organ-age-inspired clinical system is involved by any related disease process,
|
||||
and a DeepHealth-HFRS frailty risk index, which is the original UK-HFRS weighted
|
||||
sum with binary disease occurrence replaced by continuous disease expression.
|
||||
\end{abstract}
|
||||
|
||||
\section{Motivation}
|
||||
\section{Disease Expression Rate}
|
||||
|
||||
At query time \(t\), DeepHealth produces a hidden state \(h(t)\) and
|
||||
disease-level risk predictions
|
||||
For a patient queried at time \(t\), let the historical readout times be
|
||||
\[
|
||||
p_d(h(t), \tau), \qquad d = 1,\ldots,D,
|
||||
t_0 < t_1 < \cdots < t_n \le t,\qquad t_{n+1}=t.
|
||||
\]
|
||||
where \(p_d(h(t),\tau)\) is the predicted probability of disease \(d\) occurring
|
||||
within future horizon \(\tau\). These outputs are useful for disease-specific
|
||||
risk prediction, but they do not directly answer patient-level questions such as
|
||||
where disease burden is concentrated or how much functional vulnerability is
|
||||
implied by the disease profile.
|
||||
|
||||
We introduce Burden Indices to summarize disease-level predictions into
|
||||
interpretable state representations:
|
||||
For each interval \([t_i,t_{i+1}]\), DeepHealth produces a hidden state
|
||||
\(h_i=h(t_i)\) and an interval risk
|
||||
\[
|
||||
\text{disease-level risk}
|
||||
\quad \longrightarrow \quad
|
||||
\text{system-level burden}.
|
||||
q_{d,i}(t)=p_d(h_i,t_{i+1}-t_i).
|
||||
\]
|
||||
The indices combine two components:
|
||||
\begin{enumerate}[leftmargin=*]
|
||||
\item formed burden: disease burden already accumulated by query time \(t\);
|
||||
\item future expected burden: disease burden expected to newly form within
|
||||
horizon \(\tau\).
|
||||
\end{enumerate}
|
||||
|
||||
At the current stage, these quantities should be called burden indices rather
|
||||
than health reserve or health state scores. The current model is trained and
|
||||
validated primarily on ICD disease events. Its directly verifiable semantics are
|
||||
disease occurrence and disease risk. Without direct functional labels or a
|
||||
calibrated healthy reference state, quantities such as \(100-\text{burden}\)
|
||||
cannot be rigorously interpreted as remaining health reserve.
|
||||
|
||||
\section{Two Burden Spaces}
|
||||
|
||||
We define two complementary burden spaces.
|
||||
|
||||
\subsection{Organ Burden Index}
|
||||
|
||||
The Organ Burden Index (OBI) maps disease burden to anatomical systems. It
|
||||
answers:
|
||||
The model-implied disease expression rate is defined by noisy-or accumulation:
|
||||
\[
|
||||
\text{Which organs or anatomical systems carry the largest pathological burden?}
|
||||
\]
|
||||
Typical dimensions may include heart/vascular, brain/neurological, kidney,
|
||||
lung, liver/digestive, metabolic/endocrine, musculoskeletal, hematologic, and
|
||||
malignancy-related systems. The mapping matrix is denoted
|
||||
\[
|
||||
A^{\mathrm{organ}} \in \mathbb{R}_{\ge 0}^{K_o \times D},
|
||||
\]
|
||||
where \(A^{\mathrm{organ}}_{k,d}\) is the contribution weight from disease
|
||||
\(d\) to organ dimension \(k\).
|
||||
|
||||
\subsection{Functional Burden Index}
|
||||
|
||||
The Functional Burden Index (FBI) maps disease burden to function- and
|
||||
frailty-related diagnostic burden domains. It answers:
|
||||
\[
|
||||
\text{How much functional vulnerability is implied by the disease burden?}
|
||||
\]
|
||||
Candidate dimensions include mobility burden, cognition burden, mood burden,
|
||||
sensory burden, nutrition burden, infection or immune vulnerability burden,
|
||||
functional dependence burden, and comorbidity burden.
|
||||
|
||||
When CIHI-HFRM or another validated hospital frailty risk measure code list is
|
||||
available, it should be used as the primary anchor for FBI. The mapping matrix
|
||||
is denoted
|
||||
\[
|
||||
A^{\mathrm{func}} \in \mathbb{R}_{\ge 0}^{K_f \times D},
|
||||
\]
|
||||
where \(A^{\mathrm{func}}_{k,d}\) is the contribution weight from disease \(d\)
|
||||
to functional burden dimension \(k\).
|
||||
|
||||
OBI and FBI are not redundant. OBI describes where pathology is concentrated,
|
||||
whereas FBI describes how disease burden may translate into functional
|
||||
vulnerability. For example, stroke contributes primarily to brain/vascular
|
||||
burden in OBI, but may contribute to mobility, cognition, sensory, and
|
||||
functional dependence burden in FBI.
|
||||
|
||||
\section{Model Outputs and Disease Risk Function}
|
||||
|
||||
For each hidden state \(h\), DeepHealth defines a disease-specific future risk
|
||||
function
|
||||
\[
|
||||
p_d(h,\Delta),
|
||||
\]
|
||||
where \(\Delta \ge 0\) is the time horizon. The risk function is produced by the
|
||||
all-future model. Let
|
||||
\[
|
||||
\eta_d(h) = \operatorname{risk\_head}(h)_d,
|
||||
\qquad
|
||||
\lambda_d(h) = \operatorname{softplus}(\eta_d(h)).
|
||||
\]
|
||||
|
||||
For the exponential all-future model,
|
||||
\[
|
||||
p_d(h,\Delta)
|
||||
=
|
||||
1-\exp[-\lambda_d(h)\Delta].
|
||||
\]
|
||||
|
||||
For the Weibull all-future model, with
|
||||
\[
|
||||
\rho_d(h)=\operatorname{softplus}(\operatorname{rho\_head}(h)_d),
|
||||
\]
|
||||
the risk function is
|
||||
\[
|
||||
p_d(h,\Delta)
|
||||
=
|
||||
1-\exp[-\lambda_d(h)\Delta^{\rho_d(h)}].
|
||||
\]
|
||||
|
||||
The burden formulation below only assumes access to \(p_d(h,\Delta)\); the
|
||||
exponential and Weibull cases are specializations.
|
||||
|
||||
\section{Formed Burden}
|
||||
|
||||
For a patient queried at time \(t\), let the available historical readout times
|
||||
be
|
||||
\[
|
||||
t_0 < t_1 < \cdots < t_n \le t.
|
||||
\]
|
||||
For notational convenience, define
|
||||
\[
|
||||
t_{n+1}=t.
|
||||
\]
|
||||
The historical trajectory is partitioned into adjacent, non-overlapping
|
||||
intervals
|
||||
\[
|
||||
[t_i,t_{i+1}], \qquad i=0,\ldots,n.
|
||||
\]
|
||||
Let
|
||||
\[
|
||||
h_i = h(t_i), \qquad \Delta_i = t_{i+1}-t_i.
|
||||
\]
|
||||
|
||||
The interval-level model-implied probability for disease \(d\) is
|
||||
\[
|
||||
q_{d,i}(t) = p_d(h_i,\Delta_i).
|
||||
\]
|
||||
|
||||
\subsection{Model-Weighted Formed Burden}
|
||||
|
||||
The model-weighted formed burden uses DeepHealth's own historical risk
|
||||
trajectory to quantify how strongly disease \(d\) is represented as formed
|
||||
burden by time \(t\). It is defined by noisy-or accumulation over historical
|
||||
intervals:
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t)
|
||||
z_d(t)
|
||||
=
|
||||
1-\prod_{i=0}^{n}\left[1-q_{d,i}(t)\right].
|
||||
\]
|
||||
Equivalently,
|
||||
Informally, \(z_d(t)\) is the degree to which disease \(d\) is expressed in the
|
||||
patient by time \(t\). Unlike a raw diagnosis indicator, it is continuous and
|
||||
can reflect heterogeneity within the same ICD label.
|
||||
|
||||
\section{Organ Involvement Index}
|
||||
|
||||
The organ index is not a frailty score, health reserve score, or organ age. It
|
||||
is an organ involvement index. Let \(\mathcal{D}_k\) be the set of diseases
|
||||
assigned to organ/system \(k\). Define disease expression intensity as
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t)
|
||||
\Lambda_d(t)=-\log\left[1-z_d(t)\right].
|
||||
\]
|
||||
The equal-weight organ involvement index is
|
||||
\[
|
||||
O_k(t)
|
||||
=
|
||||
1-\prod_{i=0}^{n}
|
||||
\left[
|
||||
1-p_d\!\left(h(t_i),t_{i+1}-t_i\right)
|
||||
\right],
|
||||
\qquad t_{n+1}=t.
|
||||
\]
|
||||
|
||||
This definition uses each segment of the historical trajectory exactly once and
|
||||
therefore avoids repeatedly counting overlapping predictions from multiple
|
||||
historical states to the same query time.
|
||||
|
||||
\subsection{Observed-Anchored Formed Burden}
|
||||
|
||||
The observed-anchored formed burden treats historical diagnoses as factual
|
||||
evidence. Define the observed historical disease indicator
|
||||
\[
|
||||
o_d(t)
|
||||
=
|
||||
\mathbb{I}\left\{
|
||||
\exists j:\; \mathrm{event}_j=d,\; \mathrm{time}_j\le t
|
||||
\right\}.
|
||||
\]
|
||||
The observed-anchored version is
|
||||
\[
|
||||
z^{\mathrm{obs}}_d(t)=o_d(t).
|
||||
\]
|
||||
|
||||
This version is closest to diagnosis-code burden measures such as HFRM: once a
|
||||
disease code has appeared before query time \(t\), the corresponding disease
|
||||
burden component is considered present. It is maximally auditable and aligned
|
||||
with code-based burden definitions, but it does not distinguish severity,
|
||||
recency, or residual impact among patients with the same historical diagnosis.
|
||||
|
||||
\subsection{Choice of Formed Burden}
|
||||
|
||||
The two definitions represent different semantics:
|
||||
\[
|
||||
z^{\mathrm{obs}}_d(t)
|
||||
=
|
||||
\text{observed diagnostic burden},
|
||||
\]
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t)
|
||||
=
|
||||
\text{model-weighted state burden}.
|
||||
\]
|
||||
The observed-anchored version should be used when the goal is to reproduce or
|
||||
extend diagnosis-code burden measures. The model-weighted version should be used
|
||||
when the goal is to let DeepHealth assign a continuous burden strength based on
|
||||
the historical hidden-state trajectory. In the formulas below, \(z_d(t)\)
|
||||
denotes either \(z^{\mathrm{obs}}_d(t)\) or \(z^{\mathrm{model}}_d(t)\), depending
|
||||
on the selected BI variant.
|
||||
|
||||
\subsection{Observed-Anchored versus Model-Weighted Burden}
|
||||
|
||||
The observed-anchored and model-weighted definitions share the same purpose:
|
||||
both quantify disease burden already formed by query time \(t\), before adding
|
||||
future expected burden. They also use the same downstream BI equations; the only
|
||||
difference is the definition of \(z_d(t)\).
|
||||
|
||||
Their key difference is the evidence treated as primary. The observed-anchored
|
||||
version treats diagnosis occurrence as the primary unit of evidence:
|
||||
\[
|
||||
z^{\mathrm{obs}}_d(t)=1
|
||||
\quad\text{once disease } d \text{ has been observed before } t.
|
||||
\]
|
||||
This is appropriate when the burden index is intended to remain close to
|
||||
diagnosis-code measures such as HFRM. It is transparent and robust to model
|
||||
miscalibration, but it treats all historical occurrences of the same disease as
|
||||
equally formed burden.
|
||||
|
||||
The model-weighted version treats the DeepHealth risk trajectory as the primary
|
||||
unit of evidence:
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t)
|
||||
=
|
||||
1-\prod_i
|
||||
\left[
|
||||
1-p_d\!\left(h(t_i),t_{i+1}-t_i\right)
|
||||
\right].
|
||||
\]
|
||||
This version can assign different burden strengths to the same observed disease
|
||||
depending on timing, surrounding history, extra-info context, and the hidden
|
||||
state trajectory. It may better reflect state-dependent burden intensity, but it
|
||||
can also downweight a disease that was truly observed if the model assigns low
|
||||
historical probability.
|
||||
|
||||
Thus the two variants answer related but non-identical questions:
|
||||
\[
|
||||
z^{\mathrm{obs}}_d(t):
|
||||
\text{Has disease } d \text{ been recorded as part of the patient's history?}
|
||||
\]
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t):
|
||||
\text{How strongly does the model-implied trajectory support burden from }
|
||||
d \text{ by time } t?
|
||||
\]
|
||||
For this reason, both should be considered useful sensitivity variants. The
|
||||
observed-anchored version is preferable for auditability and alignment with
|
||||
existing code-based indices. The model-weighted version is preferable when the
|
||||
goal is to use DeepHealth as a continuous state model and allow the learned
|
||||
trajectory to modulate burden strength.
|
||||
|
||||
\subsection{Cumulative Intensity Form}
|
||||
|
||||
Define the interval cumulative intensity
|
||||
\[
|
||||
\ell_d(h_i,\Delta_i)
|
||||
=
|
||||
-\log\left[1-p_d(h_i,\Delta_i)\right],
|
||||
\]
|
||||
and the accumulated historical intensity
|
||||
\[
|
||||
\Lambda^{\mathrm{model}}_d(t)=\sum_{i=0}^{n}\ell_d(h_i,\Delta_i).
|
||||
\]
|
||||
Then
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t)=1-\exp[-\Lambda^{\mathrm{model}}_d(t)].
|
||||
\]
|
||||
|
||||
For the exponential model,
|
||||
\[
|
||||
\ell_d(h_i,\Delta_i)=\lambda_d(h_i)\Delta_i,
|
||||
\]
|
||||
so
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t)
|
||||
=
|
||||
1-\exp\left[
|
||||
-\sum_{i=0}^{n}
|
||||
\lambda_d\!\left(h(t_i)\right)(t_{i+1}-t_i)
|
||||
\right].
|
||||
\]
|
||||
|
||||
For the Weibull model,
|
||||
\[
|
||||
\ell_d(h_i,\Delta_i)
|
||||
=
|
||||
\lambda_d(h_i)\Delta_i^{\rho_d(h_i)},
|
||||
\]
|
||||
so
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t)
|
||||
=
|
||||
1-\exp\left[
|
||||
-\sum_{i=0}^{n}
|
||||
\lambda_d\!\left(h(t_i)\right)
|
||||
(t_{i+1}-t_i)^{\rho_d(h(t_i))}
|
||||
\right].
|
||||
\]
|
||||
|
||||
\section{Future Expected Burden}
|
||||
|
||||
The selected formed burden \(z_d(t)\) represents disease burden already formed
|
||||
by query time \(t\). It can be either the observed-anchored burden
|
||||
\(z^{\mathrm{obs}}_d(t)\) or the model-weighted burden
|
||||
\(z^{\mathrm{model}}_d(t)\). The current future risk from query time \(t\) to
|
||||
horizon \(\tau\) is
|
||||
\[
|
||||
p_d(h(t),\tau).
|
||||
\]
|
||||
The future expected newly formed burden for disease \(d\) is defined as
|
||||
\[
|
||||
f_d(t,\tau)
|
||||
=
|
||||
\left[1-z_d(t)\right]p_d(h(t),\tau).
|
||||
\]
|
||||
This term counts only the portion of disease burden that has not already formed
|
||||
by time \(t\). The total dynamic disease burden contribution is
|
||||
\[
|
||||
b_d(t,\tau)
|
||||
=
|
||||
z_d(t)+f_d(t,\tau).
|
||||
1-\exp\left(
|
||||
-\sum_{d\in\mathcal{D}_k}\Lambda_d(t)
|
||||
\right).
|
||||
\]
|
||||
Equivalently,
|
||||
\[
|
||||
b_d(t,\tau)
|
||||
O_k(t)
|
||||
=
|
||||
1-
|
||||
\left[1-z_d(t)\right]
|
||||
\left[1-p_d(h(t),\tau)\right].
|
||||
\prod_{d\in\mathcal{D}_k}
|
||||
\left[1-z_d(t)\right].
|
||||
\]
|
||||
Thus \(b_d(t,\tau)\) can be interpreted as the probability that disease burden
|
||||
for \(d\) has formed by time \(t\) or will newly form within the future horizon
|
||||
\(\tau\).
|
||||
|
||||
\section{Burden Index Definition}
|
||||
|
||||
Let \(A \in \mathbb{R}_{\ge 0}^{K \times D}\) be a disease-to-burden mapping
|
||||
matrix. The historical, future, and total burden indices for dimension \(k\)
|
||||
are
|
||||
Thus \(O_k(t)\in[0,1]\) is the probability-like degree to which organ/system
|
||||
\(k\) is involved by at least one related disease process. In the current
|
||||
version all diseases assigned to the same organ are equally weighted; this is a
|
||||
first-stage structural definition. Future versions can introduce
|
||||
organ-specific disease weights \(\alpha_{k,d}\):
|
||||
\[
|
||||
\operatorname{BI}^{\mathrm{hist}}_k(t)
|
||||
O_k(t)
|
||||
=
|
||||
\sum_{d=1}^{D} A_{k,d} z_d(t),
|
||||
\]
|
||||
\[
|
||||
\operatorname{BI}^{\mathrm{future}}_k(t,\tau)
|
||||
=
|
||||
\sum_{d=1}^{D}
|
||||
A_{k,d}
|
||||
\left[1-z_d(t)\right]p_d(h(t),\tau),
|
||||
\]
|
||||
and
|
||||
\[
|
||||
\operatorname{BI}^{\mathrm{total}}_k(t,\tau)
|
||||
=
|
||||
\operatorname{BI}^{\mathrm{hist}}_k(t)
|
||||
+
|
||||
\operatorname{BI}^{\mathrm{future}}_k(t,\tau).
|
||||
\]
|
||||
Equivalently,
|
||||
\[
|
||||
\operatorname{BI}^{\mathrm{total}}_k(t,\tau)
|
||||
=
|
||||
\sum_{d=1}^{D}
|
||||
A_{k,d}
|
||||
\left\{
|
||||
1-
|
||||
\left[1-z_d(t)\right]
|
||||
\left[1-p_d(h(t),\tau)\right]
|
||||
\right\}.
|
||||
1-\exp\left(
|
||||
-\sum_{d\in\mathcal{D}_k}\alpha_{k,d}\Lambda_d(t)
|
||||
\right).
|
||||
\]
|
||||
|
||||
For OBI, \(A=A^{\mathrm{organ}}\). For FBI, \(A=A^{\mathrm{func}}\).
|
||||
\section{Organ List}
|
||||
|
||||
\section{Constructing the Mapping Matrices}
|
||||
|
||||
\subsection{Organ Mapping Matrix}
|
||||
|
||||
The organ mapping matrix should be constructed from code taxonomy or validated
|
||||
clinical grouping systems rather than manually assigned arbitrary weights. In
|
||||
the current ICD-token setting, the first version can use ICD chapters or
|
||||
predefined ICD ranges to construct a sparse disease-to-organ mask
|
||||
\[
|
||||
M^{\mathrm{organ}}_{k,d}\in\{0,1\}.
|
||||
\]
|
||||
Examples include:
|
||||
The organ/system categories are inspired by organ-age studies, especially
|
||||
organ-specific plasma proteomic aging models, and are adapted to ICD disease
|
||||
labels. The current list is:
|
||||
\begin{center}
|
||||
\begin{tabular}{ll}
|
||||
\toprule
|
||||
Dimension & Example ICD groups \\
|
||||
ID & Label \\
|
||||
\midrule
|
||||
Heart/vascular & I00--I99, optionally split into cardiac and vascular groups \\
|
||||
Brain/neurological & G00--G99, F00--F09, I60--I69 \\
|
||||
Kidney/urogenital & N00--N39, especially N17--N19 \\
|
||||
Lung/respiratory & J00--J99 \\
|
||||
Metabolic/endocrine & E00--E90 \\
|
||||
Liver/digestive & K00--K93, especially K70--K77 \\
|
||||
Musculoskeletal & M00--M99 \\
|
||||
brain\_neurologic & Brain and neurologic system \\
|
||||
heart & Heart \\
|
||||
artery\_vascular & Artery and vascular system \\
|
||||
immune & Immune and infection-related system \\
|
||||
intestine\_digestive & Intestine and digestive system \\
|
||||
kidney & Kidney and urinary system \\
|
||||
liver & Liver \\
|
||||
lung & Lung and respiratory system \\
|
||||
muscle\_musculoskeletal & Muscle and musculoskeletal system \\
|
||||
pancreas\_endocrine & Pancreas and endocrine system \\
|
||||
adipose\_metabolic & Adipose and metabolic system \\
|
||||
female\_reproductive & Female reproductive system \\
|
||||
male\_reproductive & Male reproductive system \\
|
||||
neoplasm & Neoplasm \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
The neoplasm category is retained as a disease-system category rather than
|
||||
forced into a single anatomical organ. Sex-specific reproductive diseases are
|
||||
separated into female and male reproductive systems.
|
||||
|
||||
The simplest organ weights are
|
||||
\section{DeepHealth-HFRS Frailty Risk Index}
|
||||
|
||||
The original UK-HFRS is a weighted sum over binary disease occurrence:
|
||||
\[
|
||||
A^{\mathrm{organ}}_{k,d}=M^{\mathrm{organ}}_{k,d}.
|
||||
\]
|
||||
If longitudinal organ endpoint labels are available, the weights can be learned
|
||||
under the mask:
|
||||
\[
|
||||
A^{\mathrm{organ}}_{k,d}\ge 0,
|
||||
\operatorname{HFRS}^{\mathrm{obs}}(t)
|
||||
=
|
||||
\sum_{d\in\mathcal{D}_{\mathrm{HFRS}}}
|
||||
w^{\mathrm{HFRS}}_d\,o_d(t),
|
||||
\qquad
|
||||
A^{\mathrm{organ}}_{k,d}=0
|
||||
\quad\text{if}\quad
|
||||
M^{\mathrm{organ}}_{k,d}=0.
|
||||
o_d(t)\in\{0,1\}.
|
||||
\]
|
||||
This keeps the projection clinically interpretable while allowing data-driven
|
||||
calibration.
|
||||
|
||||
\subsection{Functional Mapping Matrix}
|
||||
|
||||
The functional mapping matrix should be anchored by a validated frailty-related
|
||||
diagnosis code set whenever possible. CIHI-HFRM or a closely related Hospital
|
||||
Frailty Risk Measure provides a suitable starting point because it defines
|
||||
frailty burden from diagnosis codes and associated weights.
|
||||
|
||||
Let \(w^{\mathrm{HFRM}}_d\ge 0\) be the HFRM weight mapped to DeepHealth disease
|
||||
token \(d\). If the HFRM code list is more granular than the DeepHealth ICD
|
||||
token vocabulary, weights should be mapped by code prefix. For three-character
|
||||
ICD tokens, a conservative default is
|
||||
DeepHealth-HFRS keeps the published UK-HFRS weights and replaces the binary
|
||||
disease state with the continuous DeepHealth disease expression rate:
|
||||
\[
|
||||
w^{\mathrm{HFRM}}_d
|
||||
\operatorname{HFRS}^{\mathrm{DH}}(t)
|
||||
=
|
||||
\max_{c:\, c \text{ maps to token } d}
|
||||
w^{\mathrm{HFRM}}_c.
|
||||
\]
|
||||
|
||||
For total functional burden, the one-dimensional mapping is
|
||||
\[
|
||||
A^{\mathrm{func,total}}_{1,d}
|
||||
=
|
||||
w^{\mathrm{HFRM}}_d.
|
||||
\]
|
||||
For domain-specific functional burden, define a grouping mask
|
||||
\[
|
||||
G_{k,d}\in\{0,1\},
|
||||
\]
|
||||
where \(G_{k,d}=1\) means HFRM-associated disease token \(d\) belongs to
|
||||
functional burden domain \(k\). Then
|
||||
\[
|
||||
A^{\mathrm{func}}_{k,d}
|
||||
=
|
||||
G_{k,d} w^{\mathrm{HFRM}}_d.
|
||||
\]
|
||||
|
||||
Candidate functional domains include mobility, cognition, mood, sensory,
|
||||
nutrition, infection or immune vulnerability, functional dependence, and
|
||||
comorbidity burden. These domain labels should be treated as diagnostic-burden
|
||||
proxies unless direct functional measurements are available for calibration.
|
||||
|
||||
\section{Normalization and Reporting}
|
||||
|
||||
The raw burden index is an additive weighted burden:
|
||||
\[
|
||||
\operatorname{BI}_k(t,\tau)
|
||||
=
|
||||
\sum_d A_{k,d} b_d(t,\tau).
|
||||
\]
|
||||
For interpretability, the system should report the decomposition
|
||||
\[
|
||||
\operatorname{BI}^{\mathrm{hist}}_k(t),
|
||||
\sum_{d\in\mathcal{D}_{\mathrm{HFRS}}}
|
||||
w^{\mathrm{HFRS}}_d\,z_d(t),
|
||||
\qquad
|
||||
\operatorname{BI}^{\mathrm{future}}_k(t,\tau),
|
||||
\qquad
|
||||
\operatorname{BI}^{\mathrm{total}}_k(t,\tau).
|
||||
z_d(t)\in[0,1].
|
||||
\]
|
||||
This is a natural continuous extension of the original HFRS, so it can still be
|
||||
called a frailty risk index. The semantic change is not the HFRS weight system;
|
||||
the change is the disease state variable.
|
||||
|
||||
Optionally, a normalized burden can be reported as
|
||||
\section{Current Implementation}
|
||||
|
||||
The current code computes historical current-state indices only. No future
|
||||
horizon is used. For each landmark age \(t\), it outputs:
|
||||
\begin{itemize}[leftmargin=*]
|
||||
\item \(z_d(t)\) internally as model-implied disease expression;
|
||||
\item \(O_k(t)\) as equal-weight organ involvement;
|
||||
\item \(\operatorname{HFRS}^{\mathrm{DH}}(t)\) as DeepHealth-HFRS frailty
|
||||
risk.
|
||||
\end{itemize}
|
||||
The output table uses the columns
|
||||
\[
|
||||
\widetilde{\operatorname{BI}}_k(t,\tau)
|
||||
=
|
||||
\frac{
|
||||
\sum_d A_{k,d} b_d(t,\tau)
|
||||
}{
|
||||
\sum_d A_{k,d} + \epsilon
|
||||
},
|
||||
\texttt{index\_type},\quad
|
||||
\texttt{index\_id},\quad
|
||||
\texttt{index\_label},\quad
|
||||
\texttt{index\_value}.
|
||||
\]
|
||||
where \(\epsilon>0\) prevents division by zero. This normalized score lies on a
|
||||
dimension-comparable scale when \(b_d(t,\tau)\in[0,1]\) and \(A_{k,d}\ge 0\).
|
||||
|
||||
For cohort-level interpretation, an additional percentile score can be computed
|
||||
within age- and sex-specific reference strata:
|
||||
\[
|
||||
\operatorname{PercentileBI}_k(t,\tau)
|
||||
=
|
||||
\operatorname{rank}_{\mathrm{age,sex}}
|
||||
\left(
|
||||
\operatorname{BI}^{\mathrm{total}}_k(t,\tau)
|
||||
\right).
|
||||
\]
|
||||
This percentile is a relative burden ranking, not a health reserve percentage.
|
||||
|
||||
\section{Validation}
|
||||
|
||||
OBI and FBI should be validated against different endpoints.
|
||||
|
||||
For OBI, validation endpoints should be organ-system-specific future events, for
|
||||
example cardiac events for heart/vascular burden, stroke or dementia for
|
||||
brain/neurological burden, CKD progression for kidney burden, and respiratory
|
||||
events for lung burden.
|
||||
|
||||
For FBI, validation should use CIHI-HFRM-style frailty burden, frailty-related
|
||||
diagnosis endpoints, hospitalization, mortality, care dependence proxies, or
|
||||
direct functional outcomes if available. If direct functional labels such as
|
||||
ADL/IADL, gait speed, grip strength, cognitive tests, or recovery measures are
|
||||
not available, FBI should be reported as a diagnosis-risk-based functional
|
||||
burden proxy rather than a direct functional reserve measure.
|
||||
|
||||
\section{Summary}
|
||||
|
||||
DeepHealth Burden Indices transform disease-level risk predictions into
|
||||
interpretable burden representations. Formed burden can be defined either as
|
||||
observed-anchored burden \(z^{\mathrm{obs}}_d(t)\), which follows factual
|
||||
diagnosis history, or as model-weighted burden \(z^{\mathrm{model}}_d(t)\),
|
||||
which accumulates DeepHealth's predicted interval risks along the hidden-state
|
||||
trajectory. The future expected burden is the residual future risk among disease
|
||||
burden not already formed. OBI uses anatomical disease groupings to summarize
|
||||
where pathological burden is concentrated. FBI uses CIHI-HFRM-style
|
||||
frailty-related diagnosis weights to summarize functional vulnerability burden.
|
||||
Together, they provide two complementary views of disease burden while allowing
|
||||
the formed-burden semantics to be chosen explicitly.
|
||||
|
||||
\end{document}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
\documentclass[11pt]{ctexart}
|
||||
|
||||
\usepackage[margin=1in]{geometry}
|
||||
\usepackage{amsmath, amssymb, amsfonts}
|
||||
\usepackage{bm}
|
||||
\usepackage{amsmath, amssymb}
|
||||
\usepackage{booktabs}
|
||||
\usepackage{enumitem}
|
||||
\usepackage{hyperref}
|
||||
|
||||
\title{DeepHealth 负担指数:动态器官负担与功能负担}
|
||||
\title{DeepHealth 疾病表达率、器官受累指数与衰弱风险指数}
|
||||
\author{}
|
||||
\date{}
|
||||
|
||||
@@ -16,476 +15,128 @@
|
||||
\maketitle
|
||||
|
||||
\begin{abstract}
|
||||
DeepHealth 在查询时刻 \(t\) 输出隐含状态 \(h(t)\),并基于该隐含状态给出疾病级未来风险函数
|
||||
\(p_d(h,\Delta)\)。疾病级输出足够细,但很难直接解释为个体层面的健康状态。因此,我们定义负担指数
|
||||
(Burden Indices, BI),将历史已经形成的疾病负担和未来预期新增疾病负担聚合为更高层、可解释的表征。
|
||||
器官负担指数(Organ Burden Index, OBI)将疾病映射到解剖系统;功能负担指数
|
||||
(Functional Burden Index, FBI)将疾病映射到功能受损和衰弱相关的诊断负担维度,并在条件允许时使用
|
||||
CIHI-HFRM 风格的诊断代码权重作为锚点。对于已形成负担,我们区分基于真实历史诊断的观测锚定版本,
|
||||
以及基于 DeepHealth 历史风险轨迹的模型加权版本。当前阶段这些指标应被称为负担指数,而不是健康储备或健康状态评分,
|
||||
因为当前模型主要由疾病事件监督,而不是由 ADL/IADL、步速、握力、认知测验或恢复能力等真实功能结局监督。
|
||||
DeepHealth 在查询时刻 \(t\) 输出隐含状态 \(h(t)\),并给出疾病风险函数
|
||||
\(p_d(h,\Delta)\)。我们首先定义连续的疾病表达率 \(z_d(t)\):它表示模型认为疾病 \(d\)
|
||||
截至 \(t\) 在该个体身上形成或表达了多少,而不是疾病造成的真实损害。基于 \(z_d(t)\),
|
||||
本文定义两类指数:器官受累指数和 DeepHealth-HFRS 衰弱风险指数。前者表示器官/系统是否被相关疾病过程累及;
|
||||
后者是原版 UK-HFRS 的自然连续化,即用连续疾病表达率替代二值疾病发生状态。
|
||||
\end{abstract}
|
||||
|
||||
\section{动机}
|
||||
\section{疾病表达率}
|
||||
|
||||
在查询时刻 \(t\),DeepHealth 输出隐含状态 \(h(t)\),并给出疾病级风险预测
|
||||
设历史 readout 时间为
|
||||
\[
|
||||
p_d(h(t), \tau), \qquad d = 1,\ldots,D,
|
||||
t_0 < t_1 < \cdots < t_n \le t,\qquad t_{n+1}=t.
|
||||
\]
|
||||
其中 \(p_d(h(t),\tau)\) 表示疾病 \(d\) 在未来时间窗 \(\tau\) 内发生的预测概率。疾病级风险适合做单病种预测,
|
||||
但不能直接回答个体层面的状态问题,例如疾病负担集中在哪些系统、当前已经形成了多少疾病负担、未来还可能新增多少负担,
|
||||
以及疾病风险可能带来多少功能脆弱性。
|
||||
|
||||
因此,我们引入负担指数,将疾病级预测压缩为系统级负担表征:
|
||||
在区间 \([t_i,t_{i+1}]\) 上,模型给出疾病 \(d\) 的区间风险
|
||||
\[
|
||||
\text{疾病级风险}
|
||||
\quad \longrightarrow \quad
|
||||
\text{系统级负担}.
|
||||
q_{d,i}(t)=p_d(h(t_i),t_{i+1}-t_i).
|
||||
\]
|
||||
负担指数由两部分组成:
|
||||
\begin{enumerate}[leftmargin=*]
|
||||
\item 已形成负担:截至查询时刻 \(t\) 已经累积形成的疾病负担;
|
||||
\item 未来预期负担:未来时间窗 \(\tau\) 内预期新增形成的疾病负担。
|
||||
\end{enumerate}
|
||||
|
||||
当前阶段,这些量应称为负担指数,而不是健康储备或完整健康状态。原因是当前模型主要基于 ICD 疾病事件训练和验证,
|
||||
其直接可验证语义是疾病发生和疾病风险,而不是真实功能表现或生理储备。没有直接功能标签或健康参考系校准时,
|
||||
\(100-\text{负担}\) 不能被严谨解释为剩余健康储备。
|
||||
|
||||
\section{两类负担空间}
|
||||
|
||||
我们定义两类互补的负担空间。
|
||||
|
||||
\subsection{器官负担指数}
|
||||
|
||||
器官负担指数(OBI)将疾病负担映射到解剖系统,回答:
|
||||
疾病表达率定义为
|
||||
\[
|
||||
\text{病理负担主要集中在哪些器官或系统?}
|
||||
\]
|
||||
典型维度可以包括心脏/血管、脑/神经、肾脏、肺、肝脏/消化、代谢/内分泌、肌骨、血液以及肿瘤相关系统。
|
||||
其映射矩阵记为
|
||||
\[
|
||||
A^{\mathrm{organ}} \in \mathbb{R}_{\ge 0}^{K_o \times D},
|
||||
\]
|
||||
其中 \(A^{\mathrm{organ}}_{k,d}\) 表示疾病 \(d\) 对器官维度 \(k\) 的贡献权重。
|
||||
|
||||
\subsection{功能负担指数}
|
||||
|
||||
功能负担指数(FBI)将疾病负担映射到功能受损和衰弱相关的诊断负担维度,回答:
|
||||
\[
|
||||
\text{这些疾病负担提示了多少功能脆弱性?}
|
||||
\]
|
||||
候选维度包括行动负担、认知负担、情绪负担、感官负担、营养负担、感染或免疫脆弱性负担、功能依赖负担和共病负担。
|
||||
|
||||
如果可以获得 CIHI-HFRM 或其他经过验证的住院衰弱风险诊断代码表,应优先将其作为 FBI 的锚点。
|
||||
其映射矩阵记为
|
||||
\[
|
||||
A^{\mathrm{func}} \in \mathbb{R}_{\ge 0}^{K_f \times D},
|
||||
\]
|
||||
其中 \(A^{\mathrm{func}}_{k,d}\) 表示疾病 \(d\) 对功能负担维度 \(k\) 的贡献权重。
|
||||
|
||||
OBI 与 FBI 不是重复指标。OBI 描述病理负担的位置,FBI 描述疾病负担可能带来的功能脆弱性。例如,卒中在 OBI 中主要贡献脑/血管负担,
|
||||
但在 FBI 中可能同时贡献行动、认知、感官和功能依赖负担。
|
||||
|
||||
\section{模型输出与疾病风险函数}
|
||||
|
||||
对任意隐含状态 \(h\),DeepHealth 定义疾病级未来风险函数
|
||||
\[
|
||||
p_d(h,\Delta),
|
||||
\]
|
||||
其中 \(\Delta \ge 0\) 是时间窗长度。该风险函数由 all-future 模型给出。记
|
||||
\[
|
||||
\eta_d(h) = \operatorname{risk\_head}(h)_d,
|
||||
\qquad
|
||||
\lambda_d(h) = \operatorname{softplus}(\eta_d(h)).
|
||||
\]
|
||||
|
||||
对于 exponential all-future 模型,
|
||||
\[
|
||||
p_d(h,\Delta)
|
||||
=
|
||||
1-\exp[-\lambda_d(h)\Delta].
|
||||
\]
|
||||
|
||||
对于 Weibull all-future 模型,另有
|
||||
\[
|
||||
\rho_d(h)=\operatorname{softplus}(\operatorname{rho\_head}(h)_d),
|
||||
\]
|
||||
其风险函数为
|
||||
\[
|
||||
p_d(h,\Delta)
|
||||
=
|
||||
1-\exp[-\lambda_d(h)\Delta^{\rho_d(h)}].
|
||||
\]
|
||||
|
||||
下面的负担定义只要求能够访问 \(p_d(h,\Delta)\)。exponential 和 Weibull 是该定义的两个具体实现。
|
||||
|
||||
\section{已形成负担}
|
||||
|
||||
对一个在时刻 \(t\) 查询的个体,设其历史 readout 时间点为
|
||||
\[
|
||||
t_0 < t_1 < \cdots < t_n \le t.
|
||||
\]
|
||||
为方便记号,定义
|
||||
\[
|
||||
t_{n+1}=t.
|
||||
\]
|
||||
于是历史轨迹被划分为相邻且不重叠的区间
|
||||
\[
|
||||
[t_i,t_{i+1}], \qquad i=0,\ldots,n.
|
||||
\]
|
||||
记
|
||||
\[
|
||||
h_i = h(t_i), \qquad \Delta_i = t_{i+1}-t_i.
|
||||
\]
|
||||
|
||||
疾病 \(d\) 在第 \(i\) 个历史区间内的模型推断概率为
|
||||
\[
|
||||
q_{d,i}(t) = p_d(h_i,\Delta_i).
|
||||
\]
|
||||
|
||||
\subsection{模型加权已形成负担}
|
||||
|
||||
模型加权已形成负担使用 DeepHealth 自身的历史风险轨迹,刻画疾病 \(d\) 在查询时刻 \(t\) 之前已经形成的负担强度。
|
||||
它通过 noisy-or 沿历史区间累积定义:
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t)
|
||||
z_d(t)
|
||||
=
|
||||
1-\prod_{i=0}^{n}\left[1-q_{d,i}(t)\right].
|
||||
\]
|
||||
等价地,
|
||||
直观上,\(z_d(t)\) 表示“这个病在该个体身上形成或表达了多少”。它不是二值诊断记录,
|
||||
因此可以表达同一 ICD 标签下的个体异质性。
|
||||
|
||||
\section{器官受累指数}
|
||||
|
||||
器官指数不定义为器官年龄、器官健康储备或器官衰弱,而定义为器官受累指数。设 \(\mathcal{D}_k\)
|
||||
是归属于器官/系统 \(k\) 的疾病集合。定义疾病表达强度
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t)
|
||||
\Lambda_d(t)=-\log\left[1-z_d(t)\right].
|
||||
\]
|
||||
当前版本使用等权器官受累定义:
|
||||
\[
|
||||
O_k(t)
|
||||
=
|
||||
1-\prod_{i=0}^{n}
|
||||
\left[
|
||||
1-p_d\!\left(h(t_i),t_{i+1}-t_i\right)
|
||||
\right],
|
||||
\qquad t_{n+1}=t.
|
||||
1-\exp\left(
|
||||
-\sum_{d\in\mathcal{D}_k}\Lambda_d(t)
|
||||
\right),
|
||||
\]
|
||||
|
||||
该定义只使用每一段历史区间一次,因此避免了从多个历史节点重复预测到同一个查询时刻所造成的重叠计数。
|
||||
|
||||
\subsection{观测锚定已形成负担}
|
||||
|
||||
观测锚定已形成负担将历史诊断视为事实证据。定义疾病 \(d\) 的历史观测指示变量:
|
||||
等价于
|
||||
\[
|
||||
o_d(t)
|
||||
=
|
||||
\mathbb{I}\left\{
|
||||
\exists j:\; \mathrm{event}_j=d,\; \mathrm{time}_j\le t
|
||||
\right\}.
|
||||
\]
|
||||
观测锚定版本定义为
|
||||
\[
|
||||
z^{\mathrm{obs}}_d(t)=o_d(t).
|
||||
\]
|
||||
|
||||
该版本最接近 HFRM 等基于诊断代码的负担度量:一旦疾病代码在查询时刻 \(t\) 前出现,对应的疾病负担项即被视为存在。
|
||||
它最可审计,也最贴近代码负担定义,但不能区分同一历史诊断在严重程度、发生时间远近和当前残留影响上的差异。
|
||||
|
||||
\subsection{已形成负担版本选择}
|
||||
|
||||
两个定义对应不同语义:
|
||||
\[
|
||||
z^{\mathrm{obs}}_d(t)
|
||||
=
|
||||
\text{观测诊断负担},
|
||||
\]
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t)
|
||||
=
|
||||
\text{模型加权状态负担}.
|
||||
\]
|
||||
当目标是复现或扩展诊断代码负担指标时,应使用观测锚定版本。当目标是让 DeepHealth 根据历史隐含状态轨迹给出连续负担强度时,
|
||||
应使用模型加权版本。在后续公式中,\(z_d(t)\) 表示根据所选 BI 版本采用的
|
||||
\(z^{\mathrm{obs}}_d(t)\) 或 \(z^{\mathrm{model}}_d(t)\)。
|
||||
|
||||
\subsection{观测锚定与模型加权负担的异同}
|
||||
|
||||
观测锚定和模型加权两个定义具有相同目标:二者都试图刻画查询时刻 \(t\) 之前已经形成的疾病负担,并在此基础上再叠加未来预期负担。
|
||||
二者进入后续 BI 公式的方式完全相同,差异只在于如何定义 \(z_d(t)\)。
|
||||
|
||||
二者的核心区别在于优先采用哪类证据。观测锚定版本以诊断是否真实发生作为主要证据:
|
||||
\[
|
||||
z^{\mathrm{obs}}_d(t)=1
|
||||
\quad\text{一旦疾病 } d \text{ 在 } t \text{ 前被观测到。}
|
||||
\]
|
||||
这适用于希望 BI 尽量贴近 HFRM 等诊断代码负担指标的场景。它透明、可审计,并且不容易受到模型校准误差影响;
|
||||
但它会把同一种历史诊断都视为同等程度的已形成负担,不能表达严重程度、发生时间、上下文和残留影响的差异。
|
||||
|
||||
模型加权版本则以 DeepHealth 的历史风险轨迹作为主要证据:
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t)
|
||||
=
|
||||
1-\prod_i
|
||||
\left[
|
||||
1-p_d\!\left(h(t_i),t_{i+1}-t_i\right)
|
||||
\right].
|
||||
\]
|
||||
该版本允许同一种已发生疾病在不同个体、不同时间和不同上下文下具有不同负担强度。例如,extra-info、疾病序列背景和隐含状态轨迹
|
||||
都会影响模型给出的区间风险。它可能更接近状态依赖的连续负担强度,但如果模型对某个真实发生过的疾病给出较低历史概率,
|
||||
也可能低估该诊断事实对应的负担。
|
||||
|
||||
因此,二者回答的是相关但不完全相同的问题:
|
||||
\[
|
||||
z^{\mathrm{obs}}_d(t):
|
||||
\text{疾病 } d \text{ 是否已经作为诊断历史的一部分被记录?}
|
||||
\]
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t):
|
||||
\text{模型隐含轨迹在多大程度上支持疾病 } d \text{ 已经形成负担?}
|
||||
\]
|
||||
因此,这两个版本都应作为有价值的敏感性分析方案。观测锚定版本更适合强调可审计性和与既有代码指标的一致性;
|
||||
模型加权版本更适合将 DeepHealth 作为连续状态模型,让学习到的历史轨迹调节疾病负担强度。
|
||||
|
||||
\subsection{累计强度形式}
|
||||
|
||||
定义区间累计风险强度
|
||||
\[
|
||||
\ell_d(h_i,\Delta_i)
|
||||
=
|
||||
-\log\left[1-p_d(h_i,\Delta_i)\right],
|
||||
\]
|
||||
以及历史累计强度
|
||||
\[
|
||||
\Lambda^{\mathrm{model}}_d(t)=\sum_{i=0}^{n}\ell_d(h_i,\Delta_i).
|
||||
\]
|
||||
则
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t)=1-\exp[-\Lambda^{\mathrm{model}}_d(t)].
|
||||
\]
|
||||
|
||||
对于 exponential 模型,
|
||||
\[
|
||||
\ell_d(h_i,\Delta_i)=\lambda_d(h_i)\Delta_i,
|
||||
\]
|
||||
因此
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t)
|
||||
=
|
||||
1-\exp\left[
|
||||
-\sum_{i=0}^{n}
|
||||
\lambda_d\!\left(h(t_i)\right)(t_{i+1}-t_i)
|
||||
\right].
|
||||
\]
|
||||
|
||||
对于 Weibull 模型,
|
||||
\[
|
||||
\ell_d(h_i,\Delta_i)
|
||||
=
|
||||
\lambda_d(h_i)\Delta_i^{\rho_d(h_i)},
|
||||
\]
|
||||
因此
|
||||
\[
|
||||
z^{\mathrm{model}}_d(t)
|
||||
=
|
||||
1-\exp\left[
|
||||
-\sum_{i=0}^{n}
|
||||
\lambda_d\!\left(h(t_i)\right)
|
||||
(t_{i+1}-t_i)^{\rho_d(h(t_i))}
|
||||
\right].
|
||||
\]
|
||||
|
||||
\section{未来预期负担}
|
||||
|
||||
所选择的已形成负担 \(z_d(t)\) 表示截至查询时刻 \(t\) 已经形成的疾病负担。它可以是观测锚定负担
|
||||
\(z^{\mathrm{obs}}_d(t)\),也可以是模型加权负担 \(z^{\mathrm{model}}_d(t)\)。从当前查询时刻 \(t\) 出发,
|
||||
未来时间窗 \(\tau\) 内的疾病风险为
|
||||
\[
|
||||
p_d(h(t),\tau).
|
||||
\]
|
||||
疾病 \(d\) 的未来预期新增负担定义为
|
||||
\[
|
||||
f_d(t,\tau)
|
||||
=
|
||||
\left[1-z_d(t)\right]p_d(h(t),\tau).
|
||||
\]
|
||||
该项只计算尚未形成的疾病负担部分,避免历史负担与未来风险重复计数。疾病 \(d\) 的总动态负担贡献为
|
||||
\[
|
||||
b_d(t,\tau)
|
||||
=
|
||||
z_d(t)+f_d(t,\tau).
|
||||
\]
|
||||
等价地,
|
||||
\[
|
||||
b_d(t,\tau)
|
||||
O_k(t)
|
||||
=
|
||||
1-
|
||||
\left[1-z_d(t)\right]
|
||||
\left[1-p_d(h(t),\tau)\right].
|
||||
\prod_{d\in\mathcal{D}_k}
|
||||
\left[1-z_d(t)\right].
|
||||
\]
|
||||
因此,\(b_d(t,\tau)\) 可以解释为疾病 \(d\) 的负担在时刻 \(t\) 已经形成,或将在未来时间窗 \(\tau\) 内新形成的累计概率。
|
||||
|
||||
\section{负担指数定义}
|
||||
|
||||
设 \(A \in \mathbb{R}_{\ge 0}^{K \times D}\) 是疾病到负担维度的映射矩阵。维度 \(k\) 的历史负担、未来负担和总负担分别为
|
||||
因此 \(O_k(t)\in[0,1]\),表示器官/系统 \(k\) 被至少一个相关疾病过程累及的概率型程度。
|
||||
当前所有疾病在同一器官内等权;后续可扩展为带疾病权重的形式:
|
||||
\[
|
||||
\operatorname{BI}^{\mathrm{hist}}_k(t)
|
||||
O_k(t)
|
||||
=
|
||||
\sum_{d=1}^{D} A_{k,d} z_d(t),
|
||||
\]
|
||||
\[
|
||||
\operatorname{BI}^{\mathrm{future}}_k(t,\tau)
|
||||
=
|
||||
\sum_{d=1}^{D}
|
||||
A_{k,d}
|
||||
\left[1-z_d(t)\right]p_d(h(t),\tau),
|
||||
\]
|
||||
以及
|
||||
\[
|
||||
\operatorname{BI}^{\mathrm{total}}_k(t,\tau)
|
||||
=
|
||||
\operatorname{BI}^{\mathrm{hist}}_k(t)
|
||||
+
|
||||
\operatorname{BI}^{\mathrm{future}}_k(t,\tau).
|
||||
\]
|
||||
等价地,
|
||||
\[
|
||||
\operatorname{BI}^{\mathrm{total}}_k(t,\tau)
|
||||
=
|
||||
\sum_{d=1}^{D}
|
||||
A_{k,d}
|
||||
\left\{
|
||||
1-
|
||||
\left[1-z_d(t)\right]
|
||||
\left[1-p_d(h(t),\tau)\right]
|
||||
\right\}.
|
||||
1-\exp\left(
|
||||
-\sum_{d\in\mathcal{D}_k}\alpha_{k,d}\Lambda_d(t)
|
||||
\right).
|
||||
\]
|
||||
|
||||
对于 OBI,\(A=A^{\mathrm{organ}}\)。对于 FBI,\(A=A^{\mathrm{func}}\)。
|
||||
\section{器官列表}
|
||||
|
||||
\section{映射矩阵构建}
|
||||
|
||||
\subsection{器官映射矩阵}
|
||||
|
||||
器官映射矩阵应来自代码分类体系或经过验证的临床分组,而不是人为随意指定权重。在当前 ICD token 设置下,
|
||||
第一版可以使用 ICD 章节或预定义 ICD 范围构建稀疏的疾病到器官 mask:
|
||||
\[
|
||||
M^{\mathrm{organ}}_{k,d}\in\{0,1\}.
|
||||
\]
|
||||
示例包括:
|
||||
当前器官/系统列表参考器官年龄研究中的 organ-age-inspired systems,并结合 ICD 疾病标签空间调整:
|
||||
\begin{center}
|
||||
\begin{tabular}{ll}
|
||||
\toprule
|
||||
维度 & 示例 ICD 组 \\
|
||||
ID & 含义 \\
|
||||
\midrule
|
||||
心脏/血管 & I00--I99,可进一步拆分为心脏和血管组 \\
|
||||
脑/神经 & G00--G99,F00--F09,I60--I69 \\
|
||||
肾脏/泌尿生殖 & N00--N39,尤其 N17--N19 \\
|
||||
肺/呼吸 & J00--J99 \\
|
||||
代谢/内分泌 & E00--E90 \\
|
||||
肝脏/消化 & K00--K93,尤其 K70--K77 \\
|
||||
肌骨 & M00--M99 \\
|
||||
brain\_neurologic & 脑与神经系统 \\
|
||||
heart & 心脏 \\
|
||||
artery\_vascular & 动脉与血管系统 \\
|
||||
immune & 免疫与感染相关系统 \\
|
||||
intestine\_digestive & 肠道与消化系统 \\
|
||||
kidney & 肾脏与泌尿系统 \\
|
||||
liver & 肝脏 \\
|
||||
lung & 肺与呼吸系统 \\
|
||||
muscle\_musculoskeletal & 肌肉骨骼系统 \\
|
||||
pancreas\_endocrine & 胰腺与内分泌系统 \\
|
||||
adipose\_metabolic & 脂肪与代谢系统 \\
|
||||
female\_reproductive & 女性生殖系统 \\
|
||||
male\_reproductive & 男性生殖系统 \\
|
||||
neoplasm & 肿瘤 \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
肿瘤作为疾病系统单独保留,不强行归入某个单一器官。男女生殖系统单独拆分。
|
||||
|
||||
最简单的器官权重为
|
||||
\section{DeepHealth-HFRS 衰弱风险指数}
|
||||
|
||||
原版 UK-HFRS 是二值疾病发生状态的加权和:
|
||||
\[
|
||||
A^{\mathrm{organ}}_{k,d}=M^{\mathrm{organ}}_{k,d}.
|
||||
\]
|
||||
如果有纵向器官终点标签,可以在 mask 约束下学习权重:
|
||||
\[
|
||||
A^{\mathrm{organ}}_{k,d}\ge 0,
|
||||
\operatorname{HFRS}^{\mathrm{obs}}(t)
|
||||
=
|
||||
\sum_{d\in\mathcal{D}_{\mathrm{HFRS}}}
|
||||
w^{\mathrm{HFRS}}_d o_d(t),
|
||||
\qquad
|
||||
A^{\mathrm{organ}}_{k,d}=0
|
||||
\quad\text{if}\quad
|
||||
M^{\mathrm{organ}}_{k,d}=0.
|
||||
o_d(t)\in\{0,1\}.
|
||||
\]
|
||||
这样可以保持投影的临床可解释性,同时允许数据驱动校准。
|
||||
|
||||
\subsection{功能映射矩阵}
|
||||
|
||||
功能映射矩阵应尽可能锚定在经过验证的衰弱相关诊断代码表上。CIHI-HFRM 或相关的 Hospital Frailty Risk Measure
|
||||
是合适起点,因为它从诊断代码及其权重定义衰弱负担。
|
||||
|
||||
设 \(w^{\mathrm{HFRM}}_d\ge 0\) 是映射到 DeepHealth 疾病 token \(d\) 的 HFRM 权重。如果 HFRM 代码比
|
||||
DeepHealth 的 ICD token 更细,而 DeepHealth 使用三位 ICD token,则可按代码前缀聚合。保守默认方式是
|
||||
DeepHealth-HFRS 保留原版 UK-HFRS 权重,只把疾病状态从二值观测替换为连续疾病表达率:
|
||||
\[
|
||||
w^{\mathrm{HFRM}}_d
|
||||
\operatorname{HFRS}^{\mathrm{DH}}(t)
|
||||
=
|
||||
\max_{c:\, c \text{ maps to token } d}
|
||||
w^{\mathrm{HFRM}}_c.
|
||||
\]
|
||||
|
||||
对于总功能负担,一维映射为
|
||||
\[
|
||||
A^{\mathrm{func,total}}_{1,d}
|
||||
=
|
||||
w^{\mathrm{HFRM}}_d.
|
||||
\]
|
||||
对于分域功能负担,定义分组 mask
|
||||
\[
|
||||
G_{k,d}\in\{0,1\},
|
||||
\]
|
||||
其中 \(G_{k,d}=1\) 表示 HFRM 相关疾病 token \(d\) 属于功能负担维度 \(k\)。于是
|
||||
\[
|
||||
A^{\mathrm{func}}_{k,d}
|
||||
=
|
||||
G_{k,d} w^{\mathrm{HFRM}}_d.
|
||||
\]
|
||||
|
||||
候选功能维度包括行动、认知、情绪、感官、营养、感染或免疫脆弱性、功能依赖和共病负担。在没有直接功能测量校准之前,
|
||||
这些维度应被解释为诊断风险驱动的功能负担代理,而不是直接的功能储备测量。
|
||||
|
||||
\section{归一化与报告}
|
||||
|
||||
原始负担指数是加权加和:
|
||||
\[
|
||||
\operatorname{BI}_k(t,\tau)
|
||||
=
|
||||
\sum_d A_{k,d} b_d(t,\tau).
|
||||
\]
|
||||
为了可解释性,系统应报告三项分解:
|
||||
\[
|
||||
\operatorname{BI}^{\mathrm{hist}}_k(t),
|
||||
\sum_{d\in\mathcal{D}_{\mathrm{HFRS}}}
|
||||
w^{\mathrm{HFRS}}_d z_d(t),
|
||||
\qquad
|
||||
\operatorname{BI}^{\mathrm{future}}_k(t,\tau),
|
||||
\qquad
|
||||
\operatorname{BI}^{\mathrm{total}}_k(t,\tau).
|
||||
z_d(t)\in[0,1].
|
||||
\]
|
||||
因此 DeepHealth-HFRS 仍然可以称为衰弱风险指数;它是原版 HFRS 的自然连续化。
|
||||
|
||||
也可以报告归一化负担:
|
||||
\section{当前实现}
|
||||
|
||||
当前代码只计算历史当前状态,不再使用未来 horizon。每个 landmark age \(t\) 输出:
|
||||
\begin{itemize}[leftmargin=*]
|
||||
\item 内部疾病表达率 \(z_d(t)\);
|
||||
\item 等权器官受累指数 \(O_k(t)\);
|
||||
\item DeepHealth-HFRS 衰弱风险指数 \(\operatorname{HFRS}^{\mathrm{DH}}(t)\)。
|
||||
\end{itemize}
|
||||
输出表使用
|
||||
\[
|
||||
\widetilde{\operatorname{BI}}_k(t,\tau)
|
||||
=
|
||||
\frac{
|
||||
\sum_d A_{k,d} b_d(t,\tau)
|
||||
}{
|
||||
\sum_d A_{k,d} + \epsilon
|
||||
},
|
||||
\texttt{index\_type},\quad
|
||||
\texttt{index\_id},\quad
|
||||
\texttt{index\_label},\quad
|
||||
\texttt{index\_value}.
|
||||
\]
|
||||
其中 \(\epsilon>0\) 用于避免除零。当 \(b_d(t,\tau)\in[0,1]\) 且 \(A_{k,d}\ge 0\) 时,该分数便于不同维度之间比较。
|
||||
|
||||
在队列层面,还可以在年龄和性别分层参考人群中计算相对分位数:
|
||||
\[
|
||||
\operatorname{PercentileBI}_k(t,\tau)
|
||||
=
|
||||
\operatorname{rank}_{\mathrm{age,sex}}
|
||||
\left(
|
||||
\operatorname{BI}^{\mathrm{total}}_k(t,\tau)
|
||||
\right).
|
||||
\]
|
||||
该分位数表示相对负担排名,而不是健康储备百分比。
|
||||
|
||||
\section{验证}
|
||||
|
||||
OBI 与 FBI 应使用不同结局进行验证。
|
||||
|
||||
OBI 应针对器官系统特异性未来事件验证。例如,心脏/血管负担对应心血管事件,脑/神经负担对应卒中或痴呆,
|
||||
肾脏负担对应 CKD 进展,肺部负担对应呼吸系统事件。
|
||||
|
||||
FBI 应针对 CIHI-HFRM 风格的衰弱诊断负担、衰弱相关诊断终点、住院、死亡、照护依赖代理指标,
|
||||
或在条件允许时针对直接功能结局验证。如果没有 ADL/IADL、步速、握力、认知测验或恢复能力等直接功能标签,
|
||||
FBI 应被报告为基于诊断风险的功能负担代理,而不是直接的功能储备测量。
|
||||
|
||||
\section{总结}
|
||||
|
||||
DeepHealth 负担指数将疾病级风险预测转换为可解释的负担表征。已形成负担可以定义为观测锚定负担
|
||||
\(z^{\mathrm{obs}}_d(t)\),即遵循真实历史诊断;也可以定义为模型加权负担 \(z^{\mathrm{model}}_d(t)\),
|
||||
即沿历史隐含状态轨迹累积 DeepHealth 预测的区间风险。未来预期负担则是在尚未形成的疾病负担部分上计算未来新增风险。
|
||||
OBI 使用解剖系统分组描述病理负担集中在哪里;FBI 使用 CIHI-HFRM 风格的衰弱相关诊断权重描述功能脆弱性负担。
|
||||
二者提供疾病负担的两种互补视角,同时允许明确选择已形成负担的语义。
|
||||
|
||||
\end{document}
|
||||
|
||||
@@ -1,306 +0,0 @@
|
||||
token_id,label_code,label_name,hfrm_category_id,hfrm_category,hfrm_key_area,hfrm_category_weight,hfrm_normalized_weight,n_matched_hfrm_codes,matched_hfrm_codes,matched_hfrm_code_descriptions,match_types,source_pdf
|
||||
7,A04,(other bacterial intestinal infections),20,Infections,Other,1.0,0.027777777777777776,1,A04,A04: Other bacterial intestinal infections,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
11,A08,(viral and other specified intestinal infections),20,Infections,Other,1.0,0.027777777777777776,1,A08,A08: Viral and other specified intestinal infections,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
12,A09,(diarrhoea and gastro-enteritis of presumed infectious origin),16,Gastrointestinal,Morbidity,1.0,0.027777777777777776,1,A09,A09: Other gastroenteritis and colitis of infectious and,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
35,A40,(streptococcal septicaemia),20,Infections,Other,1.0,0.027777777777777776,1,A40,A40: Streptococcal sepsis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
36,A41,(other septicaemia),20,Infections,Other,1.0,0.027777777777777776,1,A41,A41: Other sepsis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
41,A48,"(other bacterial diseases, not elsewhere classified)",20,Infections,Other,1.0,0.027777777777777776,1,A48.8,A48.8: Other specified bacterial diseases,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
42,A49,(bacterial infection of unspecified site),20,Infections,Other,1.0,0.027777777777777776,5,A49.0;A49.1;A49.2;A49.8;A49.9,"A49.0: Staphylococcal infection, unspecified site | A49.1: Streptococcal and enterococcal infection, unspecified site | A49.2: Haemophilus influenzae infection, unspecified site | A49.8: Other bacterial infections of unspecified site | A49.9: Bacterial infection, unspecified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
158,B95,(streptococcus and staphylococcus as the cause of diseases classified to other chapters),20,Infections,Other,1.0,0.027777777777777776,1,B95,B95: Streptococcus and staphylococcus as the cause of disease,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
159,B96,(other bacterial agents as the cause of diseases classified to other chapters),20,Infections,Other,1.0,0.027777777777777776,1,B96,B96: Other specified bacterial agents as the cause of diseases,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
160,B97,(viral agents as the cause of diseases classified to other chapters),20,Infections,Other,1.0,0.027777777777777776,1,B97,B97: Viral agents as the cause of diseases classified to,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
176,D64,(other anaemias),1,Anemia,Morbidity,1.0,0.027777777777777776,1,D64,D64: Other anaemias,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
198,E02,(subclinical iodine-deficiency hypothyroidism),11,Endocrine,Other,1.0,0.027777777777777776,1,E02,E02: Subclinical iodine-deficiency hypothyroidism,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
199,E03,(other hypothyroidism),11,Endocrine,Other,1.0,0.027777777777777776,1,E03,E03: Other hypothyroidism,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
200,E04,(other non-toxic goitre),11,Endocrine,Other,1.0,0.027777777777777776,1,E04,E04: Other nontoxic goitre,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
201,E05,(thyrotoxicosis [hyperthyroidism]),11,Endocrine,Other,1.0,0.027777777777777776,1,E05,E05: Thyrotoxicosis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
202,E06,(thyroiditis),11,Endocrine,Other,1.0,0.027777777777777776,1,E06,E06: Thyroiditis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
203,E07,(other disorders of thyroid),11,Endocrine,Other,1.0,0.027777777777777776,1,E07,E07: Other disorders of thyroid,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
204,E10,(insulin-dependent diabetes mellitus),9,Diabetes,Morbidity,1.0,0.027777777777777776,1,E10,E10: Type 1 diabetes mellitus,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
205,E11,(non-insulin-dependent diabetes mellitus),9,Diabetes,Morbidity,1.0,0.027777777777777776,1,E11,E11: Type 2 diabetes mellitus,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
207,E13,(other specified diabetes mellitus),9,Diabetes,Morbidity,1.0,0.027777777777777776,1,E13,E13: Other specified diabetes mellitus,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
208,E14,(unspecified diabetes mellitus),9,Diabetes,Morbidity,1.0,0.027777777777777776,1,E14,E14: Unspecified diabetes mellitus,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
210,E16,(other disorders of pancreatic internal secretion),11,Endocrine,Other,1.0,0.027777777777777776,1,E16,E16: Other disorders of pancreatic internal secretion,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
211,E20,(hypoparathyroidism),11,Endocrine,Other,1.0,0.027777777777777776,1,E20.9,"E20.9: Hypoparathyroidism, unspecified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
212,E21,(hyperparathyroidism and other disorders of parathyroid gland),11,Endocrine,Other,1.0,0.027777777777777776,5,E21.0;E21.1;E21.2;E21.3;E21.4,"E21.0: Primary hyperparathyroidism | E21.1: Secondary hyperparathyroidism, not elsewhere classified | E21.2: Other hyperparathyroidism | E21.3: Hyperparathyroidism, unspecified | E21.4: Other specified disorders of parathyroid gland",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
213,E22,(hyperfunction of pituitary gland),11,Endocrine,Other,1.0,0.027777777777777776,1,E22.2,E22.2: Syndrome of inappropriate secretions of antidiuretic hormone,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
214,E23,(hypofunction and other disorders of pituitary gland),11,Endocrine,Other,1.0,0.027777777777777776,2,E23.0;E23.2,E23.0: Hypopituitarism | E23.2: Diabetes insipidus,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
218,E27,(other disorders of adrenal gland),11,Endocrine,Other,1.0,0.027777777777777776,7,E27.1;E27.2;E27.3;E27.4;E27.5;E27.8;E27.9,"E27.1: Primary adrenocortical insufficiency | E27.2: Addisonian crisis | E27.3: Drug-induced adrenocortical insufficiency | E27.4: Other and unspecified adrenocortical insufficiency | E27.5: Adrenomedullary hyperfunction | E27.8: Other specified disorders of adrenal gland | E27.9: Disorder of adrenal gland, unspecified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
223,E32,(diseases of thymus),11,Endocrine,Other,1.0,0.027777777777777776,1,E32.8,E32.8: Other diseases of thymus,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
224,E34,(other endocrine disorders),11,Endocrine,Other,1.0,0.027777777777777776,2,E34.0;E34.9,"E34.0: Carcinoid syndrome | E34.9: Endocrine disorder, unspecified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
226,E41,(nutritional marasmus),25,Nutrition and wasting,Other,1.0,0.027777777777777776,1,E41,E41: Nutritional marasmus,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
227,E43,(unspecified severe protein-energy malnutrition),25,Nutrition and wasting,Other,1.0,0.027777777777777776,1,E43,E43: Unspecified severe protein-energy malnutrition,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
228,E44,(protein-energy malnutrition of moderate and mild degree),25,Nutrition and wasting,Other,1.0,0.027777777777777776,2,E44.0;E44.1,E44.0: Moderate protein-energy malnutrition | E44.1: Mild protein-energy malnutrition,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
230,E46,(unspecified protein-energy malnutrition),25,Nutrition and wasting,Other,1.0,0.027777777777777776,1,E46,E46: Unspecified protein-energy malnutrition,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
234,E53,(deficiency of other b group vitamins),25,Nutrition and wasting,Other,1.0,0.027777777777777776,1,E53,E53: Deficiency of other B group vitamins,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
236,E55,(vitamin d deficiency),25,Nutrition and wasting,Other,1.0,0.027777777777777776,1,E55,E55: Vitamin D deficiency,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
242,E63,(other nutritional deficiencies),25,Nutrition and wasting,Other,1.0,0.027777777777777776,1,E63.9,"E63.9: Nutritional deficiency, unspecified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
259,E83,(disorders of mineral metabolism),25,Nutrition and wasting,Other,1.0,0.027777777777777776,1,E83,E83: Disorders of mineral metabolism,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
261,E85,(amyloidosis),28,Other frailty conditions and diseases,Other,1.0,0.027777777777777776,3,E85.3;E85.4;E85.9,"E85.3: Secondary systemic amyloidosis | E85.4: Organ-limited amyloidosis | E85.9: Amyloidosis, unspecified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
262,E86,(volume depletion),25,Nutrition and wasting,Other,1.0,0.027777777777777776,1,E86,E86: Volume depletion,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
263,E87,"(other disorders of fluid, electrolyte and acid-base balance)",25,Nutrition and wasting,Other,1.0,0.027777777777777776,1,E87,"E87: Other disorders of fluid, electrolyte, and acid-base balance",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
266,F00,(dementia in alzheimer's disease),8,Dementia and Alzheimer's,Cognition and mood,1.0,0.027777777777777776,1,F00,F00: Dementia in Alzheimer’s disease,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
267,F01,(vascular dementia),8,Dementia and Alzheimer's,Cognition and mood,1.0,0.027777777777777776,1,F01,F01: Vascular dementia,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
268,F02,(dementia in other diseases classified elsewhere),8,Dementia and Alzheimer's,Cognition and mood,1.0,0.027777777777777776,1,F02,F02: Dementia in other diseases classified elsewhere,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
269,F03,(unspecified dementia),8,Dementia and Alzheimer's,Cognition and mood,1.0,0.027777777777777776,1,F03,F03: Unspecified dementia,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
271,F05,"(delirium, not induced by alcohol and other psychoactive substances)",6,Delirium,Cognition and mood,1.0,0.027777777777777776,1,F05,"F05: Delirium, not induced by alcohol and other",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
272,F06,(other mental disorders due to brain damage and dysfunction and to physical disease),12,Epilepsy,Other,1.0,0.027777777777777776,1,F06.8,F06.8: Other specified mental disorders due to brain damage,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
272,F06,(other mental disorders due to brain damage and dysfunction and to physical disease),27,Other cognitive disorders,Cognition and mood,1.0,0.027777777777777776,1,F06.7,F06.7: Mild cognitive disorder,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
278,F13,(mental and behavioural disorders due to use of sedatives or hypnotics),6,Delirium,Cognition and mood,1.0,0.027777777777777776,1,F13.4,F13.4: Mental and behavioral disorders due to use of sedatives,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
287,F22,(persistent delusional disorders),7,Delusions and hallucinations,Cognition and mood,1.0,0.027777777777777776,1,F22,F22: Persistent delusional disorders,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
295,F32,(depressive episode),22,Mood disorders,Cognition and mood,1.0,0.027777777777777776,1,F32,F32: Depressive episode,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
301,F41,(other anxiety disorders),22,Mood disorders,Cognition and mood,1.0,0.027777777777777776,1,F41,F41: Other anxiety disorders,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
305,F45,(somatoform disorders),30,Pain,Other,1.0,0.027777777777777776,1,F45.4,F45.4: Persistent somatoform pain disorder,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
328,F80,(specific developmental disorders of speech and language),27,Other cognitive disorders,Cognition and mood,1.0,0.027777777777777776,3,F80.1;F80.2;F80.3,F80.1: Expressive language disorder | F80.2: Receptive language disorder | F80.3: Acquired aphasia with epilepsy [Landau-Kleffner],hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
355,G12,(spinal muscular atrophy and related syndromes),28,Other frailty conditions and diseases,Other,1.0,0.027777777777777776,1,G12.20,G12.20: Amyotrophic lateral sclerosis,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
358,G20,(parkinson's disease),28,Other frailty conditions and diseases,Other,1.0,0.027777777777777776,1,G20,G20: Parkinson’s disease,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
359,G21,(secondary parkinsonism),28,Other frailty conditions and diseases,Other,1.0,0.027777777777777776,1,G21,G21: Secondary parkinsonism,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
360,G22,(parkinsonism in diseases classified elsewhere),28,Other frailty conditions and diseases,Other,1.0,0.027777777777777776,1,G22,G22: Parkinsonism in diseases classified elsewhere,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
364,G30,(alzheimer's disease),8,Dementia and Alzheimer's,Cognition and mood,1.0,0.027777777777777776,1,G30,G30: Alzheimer’s disease,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
365,G31,"(other degenerative diseases of nervous system, not elsewhere classified)",8,Dementia and Alzheimer's,Cognition and mood,1.0,0.027777777777777776,3,G31.00;G31.02;G31.1,"G31.00: Pick’s disease | G31.02: Frontal lobe dementia | G31.1: Senile degeneration of brain, not elsewhere specified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
365,G31,"(other degenerative diseases of nervous system, not elsewhere classified)",27,Other cognitive disorders,Cognition and mood,1.0,0.027777777777777776,1,G31.01,G31.01: Progressive isolated aphasia [Mesulam],hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
367,G35,(multiple sclerosis),28,Other frailty conditions and diseases,Other,1.0,0.027777777777777776,1,G35,G35: Multiple sclerosis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
370,G40,(epilepsy),12,Epilepsy,Other,1.0,0.027777777777777776,1,G40,G40: Epilepsy,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
374,G45,(transient cerebral ischaemic attacks and related syndromes),5,Cerebrovascular,Morbidity,1.0,0.027777777777777776,1,G45,G45: Transient cerebral ischaemic attacks and related syndromes,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
376,G47,(sleep disorders),27,Other cognitive disorders,Cognition and mood,1.0,0.027777777777777776,5,G47.0;G47.1;G47.2;G47.8;G47.9,"G47.0: Disorders of initiating and maintaining sleep | G47.1: Disorders of excessive somnolence [hypersomnias] | G47.2: Disorders of the sleep-wake schedule | G47.8: Other sleep disorders | G47.9: Sleep disorder, unspecified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
377,G50,(disorders of trigeminal nerve),30,Pain,Other,1.0,0.027777777777777776,1,G50.0,G50.0: Trigeminal neuralgia,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
397,G81,(hemiplegia),23,Movement and immobility,Function,1.0,0.027777777777777776,1,G81,G81: Hemiplegia,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
398,G82,(paraplegia and tetraplegia),23,Movement and immobility,Function,1.0,0.027777777777777776,1,G82,G82: Paraplegia and tetraplegia,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
439,H40,(glaucoma),33,Sensory impairment,Sensory loss,1.0,0.027777777777777776,1,H40,H40: Glaucoma,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
440,H42,(glaucoma in diseases classified elsewhere),33,Sensory impairment,Sensory loss,1.0,0.027777777777777776,1,H42,H42: Glaucoma in diseases classified elsewhere,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
451,H53,(visual disturbances),33,Sensory impairment,Sensory loss,1.0,0.027777777777777776,1,H53,H53: Visual disturbances,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
452,H54,(blindness and low vision),33,Sensory impairment,Sensory loss,1.0,0.027777777777777776,1,H54,H54: Visual impairment including blindness,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
454,H57,(other disorders of eye and adnexa),30,Pain,Other,1.0,0.027777777777777776,1,H57.1,H57.1: Ocular pain,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
472,H81,(disorders of vestibular function),23,Movement and immobility,Function,1.0,0.027777777777777776,1,H81,H81: Disorders of vestibular function,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
474,H83,(other diseases of inner ear),33,Sensory impairment,Sensory loss,1.0,0.027777777777777776,1,H83.3,H83.3: Noise effects on inner ear,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
476,H91,(other hearing loss),33,Sensory impairment,Sensory loss,1.0,0.027777777777777776,1,H91,H91: Other hearing loss,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
477,H92,(otalgia and effusion of ear),30,Pain,Other,1.0,0.027777777777777776,1,H92.0,H92.0: Otalgia,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
484,I05,(rheumatic mitral valve diseases),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I05,I05: Rheumatic mitral valve diseases,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
485,I06,(rheumatic aortic valve diseases),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I06,I06: Rheumatic aortic valve diseases,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
486,I07,(rheumatic tricuspid valve diseases),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I07,I07: Rheumatic tricuspid valve diseases,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
487,I08,(multiple valve diseases),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I08,I08: Multiple valve diseases,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
488,I09,(other rheumatic heart diseases),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I09.0,I09.0: Rheumatic myocarditis,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
489,I10,(essential (primary) hypertension),18,Hypo- and hypertension,Morbidity,1.0,0.027777777777777776,1,I10,I10: Essential (primary) hypertension,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
490,I11,(hypertensive heart disease),18,Hypo- and hypertension,Morbidity,1.0,0.027777777777777776,1,I11,I11: Hypertensive heart disease,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
491,I12,(hypertensive renal disease),18,Hypo- and hypertension,Morbidity,1.0,0.027777777777777776,1,I12,I12: Hypertensive renal disease,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
492,I13,(hypertensive heart and renal disease),18,Hypo- and hypertension,Morbidity,1.0,0.027777777777777776,1,I13,I13: Hypertensive heart and renal disease,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
493,I15,(secondary hypertension),18,Hypo- and hypertension,Morbidity,1.0,0.027777777777777776,1,I15,I15: Secondary hypertension,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
499,I25,(chronic ischaemic heart disease),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I25.1,I25.1: Atherosclerotic heart disease,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
500,I26,(pulmonary embolism),34,Thrombosis and embolism,Morbidity,1.0,0.027777777777777776,1,I26,I26: Pulmonary embolism,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
507,I34,(nonrheumatic mitral valve disorders),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I34,I34: Nonrheumatic mitral valve disorders,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
508,I35,(nonrheumatic aortic valve disorders),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I35,I35: Nonrheumatic aortic valve disorders,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
509,I36,(nonrheumatic tricuspid valve disorders),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I36,I36: Nonrheumatic tricuspid valve disorders,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
510,I37,(pulmonary valve disorders),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I37,I37: Pulmonary valve disorders,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
511,I38,"(endocarditis, valve unspecified)",4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I38,"I38: Endocarditis, valve unspecified",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
512,I39,(endocarditis and heart valve disorders in diseases classified elsewhere),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I39,I39: Endocarditis and heart valve disorders in diseases,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
515,I42,(cardiomyopathy),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I42,I42: Cardiomyopathy,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
516,I43,(cardiomyopathy in diseases classified elsewhere),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I43,I43: Cardiomyopathy in diseases classified elsewhere,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
520,I47,(paroxysmal tachycardia),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I47,I47: Paroxysmal tachycardia,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
521,I48,(atrial fibrillation and flutter),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I48,I48: Atrial fibrillation and flutter,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
522,I49,(other cardiac arrhythmias),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I49,I49: Other cardiac arrhythmias,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
523,I50,(heart failure),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,3,I50.0;I50.1;I50.9,"I50.0: Congestive heart failure | I50.1: Left ventricular failure | I50.9: Heart failure, unspecified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
526,I60,(subarachnoid haemorrhage),5,Cerebrovascular,Morbidity,1.0,0.027777777777777776,1,I60,I60: Subarachnoid haemorrhage,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
527,I61,(intracerebral haemorrhage),5,Cerebrovascular,Morbidity,1.0,0.027777777777777776,1,I61,I61: Intracerebral haemorrhage,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
529,I63,(cerebral infarction),5,Cerebrovascular,Morbidity,1.0,0.027777777777777776,8,I63.0;I63.1;I63.2;I63.3;I63.4;I63.5;I63.8;I63.9,"I63.0: Cerebral infarction due to thrombosis of precerebral arteries | I63.1: Cerebral infarction due to embolism of precerebral arteries | I63.2: Cerebral infarction due to unspecified occlusion or stenosis | I63.3: Cerebral infarction due to thrombosis of cerebral arteries | I63.4: Cerebral infarction due to embolism of cerebral arteries | I63.5: Cerebral infarction due to unspecified occlusion or stenosis | I63.8: Other cerebral infarction | I63.9: Cerebral infarction, unspecified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
530,I64,"(stroke, not specified as haemorrhage or infarction)",5,Cerebrovascular,Morbidity,1.0,0.027777777777777776,1,I64,"I64: Stroke, not specified as haemorrhage or infarction",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
535,I69,(sequelae of cerebrovascular disease),5,Cerebrovascular,Morbidity,1.0,0.027777777777777776,1,I69,I69: Sequelae of cerebrovascular disease,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
536,I70,(atherosclerosis),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I70,I70: Atherosclerosis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
537,I71,(aortic aneurysm and dissection),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,4,I71.3;I71.4;I71.5;I71.6,"I71.3: Abdominal aortic aneurysm, ruptured | I71.4: Abdominal aortic aneurysm, without mention of rupture | I71.5: Thoracoabdominal aortic aneurysm, ruptured | I71.6: Thoracoabdominal aortic aneurysm, without mention",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
538,I72,(other aneurysm),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,4,I72.1;I72.2;I72.3;I72.4,I72.1: Aneurysm and dissection of artery of upper extremity | I72.2: Aneurysm and dissection of renal artery | I72.3: Aneurysm and dissection of iliac artery | I72.4: Aneurysm and dissection of artery of lower extremity,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
539,I73,(other peripheral vascular diseases),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,I73,I73: Other peripheral vascular diseases,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
544,I80,(phlebitis and thrombophlebitis),34,Thrombosis and embolism,Morbidity,1.0,0.027777777777777776,1,I80,I80: Phlebitis and thrombophlebitis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
545,I81,(portal vein thrombosis),34,Thrombosis and embolism,Morbidity,1.0,0.027777777777777776,1,I81,I81: Portal vein thrombosis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
546,I82,(other venous embolism and thrombosis),34,Thrombosis and embolism,Morbidity,1.0,0.027777777777777776,4,I82.2;I82.3;I82.8;I82.9,I82.2: Embolism and thrombosis of vena cava | I82.3: Embolism and thrombosis of renal vein | I82.8: Embolism and thrombosis of other specified veins | I82.9: Embolism and thrombosis of unspecified vein,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
554,I95,(hypotension),18,Hypo- and hypertension,Morbidity,1.0,0.027777777777777776,1,I95,I95: Hypotension,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
587,J39,(other diseases of upper respiratory tract),30,Pain,Other,1.0,0.027777777777777776,1,J39.2,J39.2: Other diseases of pharynx,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
588,J40,"(bronchitis, not specified as acute or chronic)",32,Respiratory,Morbidity,1.0,0.027777777777777776,1,J40,"J40: Bronchitis, not specified as acute or chronic",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
589,J41,(simple and mucopurulent chronic bronchitis),32,Respiratory,Morbidity,1.0,0.027777777777777776,1,J41,J41: Simple and mucopurulent chronic bronchitis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
590,J42,(unspecified chronic bronchitis),32,Respiratory,Morbidity,1.0,0.027777777777777776,1,J42,J42: Unspecified chronic bronchitis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
591,J43,(emphysema),32,Respiratory,Morbidity,1.0,0.027777777777777776,1,J43,J43: Emphysema,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
592,J44,(other chronic obstructive pulmonary disease),32,Respiratory,Morbidity,1.0,0.027777777777777776,1,J44,J44: Other chronic obstructive pulmonary disease,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
593,J45,(asthma),32,Respiratory,Morbidity,1.0,0.027777777777777776,1,J45,J45: Asthma,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
595,J47,(bronchiectasis),32,Respiratory,Morbidity,1.0,0.027777777777777776,1,J47,J47: Bronchiectasis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
604,J69,(pneumonitis due to solids and liquids),32,Respiratory,Morbidity,1.0,0.027777777777777776,1,J69,J69: Pneumonitis due to solids and liquids,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
618,J96,"(respiratory failure, not elsewhere classified)",32,Respiratory,Morbidity,1.0,0.027777777777777776,1,J96,"J96: Respiratory failure, not elsewhere classified",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
631,K10,(other diseases of jaws),30,Pain,Other,1.0,0.027777777777777776,1,K10.8,K10.8: Other specified diseases of jaws,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
634,K13,(other diseases of lip and oral mucosa),30,Pain,Other,1.0,0.027777777777777776,1,K13.7,K13.7: Other and unspecified lesions of oral mucosa,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
635,K14,(diseases of tongue),30,Pain,Other,1.0,0.027777777777777776,1,K14.6,K14.6: Glossodynia,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
641,K26,(duodenal ulcer),16,Gastrointestinal,Morbidity,1.0,0.027777777777777776,1,K26,K26: Duodenal ulcer,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
644,K29,(gastritis and duodenitis),25,Nutrition and wasting,Other,1.0,0.027777777777777776,1,K29.0,K29.0: Acute haemorrhagic gastritis,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
660,K52,(other non-infective gastro-enteritis and colitis),16,Gastrointestinal,Morbidity,1.0,0.027777777777777776,1,K52,K52: Other noninfective gastroenteritis and colitis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
661,K55,(vascular disorders of intestine),4,Cardiac and vascular,Morbidity,1.0,0.027777777777777776,1,K55.1,K55.1: Chronic vascular disorders of intestine,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
665,K59,(other functional intestinal disorders),16,Gastrointestinal,Morbidity,1.0,0.027777777777777776,1,K59,K59: Other functional intestinal disorders,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
668,K62,(other diseases of anus and rectum),30,Pain,Other,1.0,0.027777777777777776,1,K62.8,K62.8: Other specified diseases of anus and rectum,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
696,L03,(cellulitis),20,Infections,Other,1.0,0.027777777777777776,1,L03,L03: Cellulitis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
699,L08,(other local infections of skin and subcutaneous tissue),20,Infections,Other,1.0,0.027777777777777776,1,L08,L08: Other local infections of skin and subcutaneous tissue,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
754,L89,(decubitus ulcer),35,Ulcers and soft tissue disorders,Other,1.0,0.027777777777777776,1,L89,L89: Decubitus [pressure] ulcer and pressure area,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
761,L97,"(ulcer of lower limb, not elsewhere classified)",35,Ulcers and soft tissue disorders,Other,1.0,0.027777777777777776,1,L97,"L97: Ulcer of the lower limb, not elsewhere classified",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
762,L98,"(other disorders of skin and subcutaneous tissue, not elsewhere classified)",35,Ulcers and soft tissue disorders,Other,1.0,0.027777777777777776,3,L98.4;L98.8;L98.9,"L98.4: Chronic ulcer of skin, not elsewhere classified | L98.8: Other specified disorders of skin and subcutaneous tissue | L98.9: Disorder of skin and subcutaneous tissue, unspecified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
766,M02,(reactive arthropathies),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M02,M02: Reactive arthropathies,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
767,M03,(postinfective and reactive arthropathies in diseases classified elsewhere),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M03,M03: Postinfective and reactive arthropathies in diseases,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
768,M05,(seropositive rheumatoid arthritis),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M05,M05: Seropositive rheumatoid arthritis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
769,M06,(other rheumatoid arthritis),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M06,M06: Other rheumatoid arthritis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
770,M07,(psoriatic and enteropathic arthropathies),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M07,M07: Psoriatic and enteropathic arthropathies,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
773,M10,(gout),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M10,M10: Gout,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
774,M11,(other crystal arthropathies),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M11,M11: Other crystal arthropathies,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
775,M12,(other specific arthropathies),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,4,M12.0;M12.3;M12.5;M12.8,"M12.0: Chronic postrheumatic arthropathy [Jaccoud] | M12.3: Palindromic rheumatism | M12.5: Traumatic arthropathy | M12.8: Other specific arthropathies, not elsewhere classified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
776,M13,(other arthritis),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,4,M13.0;M13.1;M13.8;M13.9,"M13.0: Polyarthritis, unspecified | M13.1: Monoarthritis, not elsewhere classified | M13.8: Other specified arthritis | M13.9: Arthritis, unspecified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
777,M14,(arthropathies in other diseases classified elsewhere),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M14,M14: Arthropathies in other diseases classified elsewhere,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
778,M15,(polyarthrosis),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M15,M15: Polyarthrosis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
779,M16,(coxarthrosis [arthrosis of hip]),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M16,M16: Coxarthrosis [arthrosis of hip],exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
780,M17,(gonarthrosis [arthrosis of knee]),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M17,M17: Gonarthrosis [arthrosis of knee],exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
781,M18,(arthrosis of first carpometacarpal joint),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M18,M18: Arthrosis of first carpometacarpal joint,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
782,M19,(other arthrosis),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M19,M19: Other arthrosis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
788,M25,"(other joint disorders, not elsewhere classified)",24,Musculoskeletal,Function,1.0,0.027777777777777776,1,M25,"M25: Other joint disorders, not elsewhere classified",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
788,M25,"(other joint disorders, not elsewhere classified)",30,Pain,Other,1.0,0.027777777777777776,1,M25.5,M25.5: Pain in joint,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
790,M31,(other necrotising vasculopathies),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M31.5,M31.5: Giant cell arteritis with polymyalgia rheumatica,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
791,M32,(systemic lupus erythematosus),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M32,M32: Systematic lupus erythematosus,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
792,M33,(dermatopolymyositis),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M33,M33: Dermatopolymyositis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
793,M34,(systemic sclerosis),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M34,M34: Systemic sclerosis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
794,M35,(other systemic involvement of connective tissue),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,3,M35.1;M35.2;M35.3,M35.1: Other overlap syndromes | M35.2: Behçet’s disease | M35.3: Polymyalgia rheumatica,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
795,M36,(systemic disorders of connective tissue in diseases classified elsewhere),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,4,M36.0;M36.1;M36.2;M36.3,M36.0: Dermato(poly)myositis in neoplastic disease | M36.1: Arthropathy in neoplastic disease | M36.2: Haemophilic arthropathy | M36.3: Arthropathy in other blood disorders,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
797,M41,(scoliosis),24,Musculoskeletal,Function,1.0,0.027777777777777776,1,M41,M41: Scoliosis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
800,M45,(ankylosing spondylitis),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M45,M45: Ankylosing spondylitis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
801,M46,(other inflammatory spondylopathies),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,2,M46.5;M46.9,"M46.5: Other infective spondylopathies | M46.9: Inflammatory spondylopathy, unspecified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
803,M48,(other spondylopathies),24,Musculoskeletal,Function,1.0,0.027777777777777776,1,M48,M48: Other spondylopathies,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
808,M54,(dorsalgia),30,Pain,Other,1.0,0.027777777777777776,7,M54.2;M54.3;M54.4;M54.5;M54.6;M54.8;M54.9,"M54.2: Cervicalgia | M54.3: Sciatica | M54.4: Lumbago with sciatica | M54.5: Low back pain | M54.6: Pain in thoracic spine | M54.8: Other dorsalgia | M54.9: Dorsalgia, unspecified site",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
811,M62,(other disorders of muscle),23,Movement and immobility,Function,1.0,0.027777777777777776,1,M62.3,M62.3: Immobility syndrome (paraplegic),hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
811,M62,(other disorders of muscle),25,Nutrition and wasting,Other,1.0,0.027777777777777776,1,M62.5,"M62.5: Muscle wasting and atrophy, not elsewhere classified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
821,M75,(shoulder lesions),2,Arthritis and inflammation,Function,1.0,0.027777777777777776,1,M75.0,M75.0: Adhesive capsulitis of shoulder,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
824,M79,"(other soft tissue disorders, not elsewhere classified)",30,Pain,Other,1.0,0.027777777777777776,3,M79.1;M79.2;M79.6,"M79.1: Myalgia | M79.2: Neuralgia and neuritis, unspecified | M79.6: Pain in limb",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
824,M79,"(other soft tissue disorders, not elsewhere classified)",35,Ulcers and soft tissue disorders,Other,1.0,0.027777777777777776,1,M79,"M79: Other soft tissue disorders, not elsewhere classified",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
825,M80,(osteoporosis with pathological fracture),14,Fractures and osteoporosis,Function,1.0,0.027777777777777776,1,M80,M80: Osteoporosis with pathological fracture,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
826,M81,(osteoporosis without pathological fracture),14,Fractures and osteoporosis,Function,1.0,0.027777777777777776,1,M81,M81: Osteoporosis without pathological fracture,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
827,M82,(osteoporosis in diseases classified elsewhere),14,Fractures and osteoporosis,Function,1.0,0.027777777777777776,1,M82,M82: Osteoporosis in diseases classified elsewhere,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
834,M89,(other disorders of bone),30,Pain,Other,1.0,0.027777777777777776,1,M89.8,M89.8: Other specified disorders of bone,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
835,M90,(osteopathies in diseases classified elsewhere),14,Fractures and osteoporosis,Function,1.0,0.027777777777777776,1,M90.7,M90.7: Fracture of bone in neoplastic disease,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
843,N00,(acute nephritic syndrome),31,Renal,Morbidity,1.0,0.027777777777777776,1,N00,N00: Acute nephritic syndrome,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
844,N01,(rapidly progressive nephritic syndrome),31,Renal,Morbidity,1.0,0.027777777777777776,1,N01,N01: Rapidly progressive nephritic syndrome,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
845,N02,(recurrent and persistent haematuria),31,Renal,Morbidity,1.0,0.027777777777777776,1,N02,N02: Recurrent and persistent haematuria,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
846,N03,(chronic nephritic syndrome),31,Renal,Morbidity,1.0,0.027777777777777776,1,N03,N03: Chronic nephritic syndrome,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
847,N04,(nephrotic syndrome),31,Renal,Morbidity,1.0,0.027777777777777776,1,N04,N04: Nephrotic syndrome,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
848,N05,(unspecified nephritic syndrome),31,Renal,Morbidity,1.0,0.027777777777777776,1,N05,N05: Unspecified nephritic syndrome,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
849,N06,(isolated proteinuria with specified morphological lesion),31,Renal,Morbidity,1.0,0.027777777777777776,1,N06,N06: Isolated proteinuria with specified morphological lesion,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
850,N07,"(hereditary nephropathy, not elsewhere classified)",31,Renal,Morbidity,1.0,0.027777777777777776,1,N07,"N07: Hereditary nephropathy, not elsewhere classified",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
851,N08,(glomerular disorders in diseases classified elsewhere),31,Renal,Morbidity,1.0,0.027777777777777776,1,N08,N08: Glomerular disorders in diseases classified elsewhere,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
852,N10,(acute tubulo-interstitial nephritis),31,Renal,Morbidity,1.0,0.027777777777777776,1,N10,N10: Acute tubulo-interstitial nephritis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
853,N11,(chronic tubulo-interstitial nephritis),31,Renal,Morbidity,1.0,0.027777777777777776,1,N11,N11: Chronic tubulo-interstitial nephritis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
854,N12,"(tubulo-interstitial nephritis, not specified as acute or chronic)",31,Renal,Morbidity,1.0,0.027777777777777776,1,N12,"N12: Tubulo-interstitial nephritis, not specified as acute or chronic",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
855,N13,(obstructive and reflux uropathy),31,Renal,Morbidity,1.0,0.027777777777777776,1,N13,N13: Obstructive and reflux uropathy,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
856,N14,(drug- and heavy-metal-induced tubulo-interstitial and tubular conditions),31,Renal,Morbidity,1.0,0.027777777777777776,1,N14,N14: Drug and heavy-metal-induced tubulo-interstitial,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
857,N15,(other renal tubulo-interstitial diseases),31,Renal,Morbidity,1.0,0.027777777777777776,1,N15,N15: Other renal tubulo-interstitial diseases,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
858,N16,(renal tubulo-interstitial disorders in diseases classified elsewhere),31,Renal,Morbidity,1.0,0.027777777777777776,1,N16,N16: Renal tubulo-interstitial disorders in diseases,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
859,N17,(acute renal failure),31,Renal,Morbidity,1.0,0.027777777777777776,1,N17,N17: Acute renal failure,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
860,N18,(chronic renal failure),31,Renal,Morbidity,1.0,0.027777777777777776,1,N18,N18: Chronic kidney disease,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
861,N19,(unspecified renal failure),31,Renal,Morbidity,1.0,0.027777777777777776,1,N19,N19: Unspecified kidney failure,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
862,N20,(calculus of kidney and ureter),31,Renal,Morbidity,1.0,0.027777777777777776,4,N20.0;N20.1;N20.2;N20.9,"N20.0: Calculus of kidney | N20.1: Calculus of ureter | N20.2: Calculus of kidney with calculus of ureter | N20.9: Urinary calculus, unspecified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
866,N25,(disorders resulting from impaired renal tubular function),31,Renal,Morbidity,1.0,0.027777777777777776,1,N25,N25: Disorders resulting from impaired renal tubular function,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
867,N26,(unspecified contracted kidney),31,Renal,Morbidity,1.0,0.027777777777777776,1,N26,N26: Unspecified contracted kidney,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
869,N28,"(other disorders of kidney and ureter, not elsewhere classified)",31,Renal,Morbidity,1.0,0.027777777777777776,4,N28.0;N28.80;N28.88;N28.9,"N28.0: Ischaemia and infarction of kidney | N28.80: Hypertrophy of kidney | N28.88: Other specified disorders of kidney and ureter | N28.9: Disorder of kidney and ureter, unspecified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
870,N29,(other disorders of kidney and ureter in diseases classified elsewhere),31,Renal,Morbidity,1.0,0.027777777777777776,1,N29,N29: Other disorders of kidney and ureter in diseases,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
879,N39,(other disorders of urinary system),19,Incontinence,Morbidity,1.0,0.027777777777777776,2,N39.30;N39.4,N39.30: Mixed incontinence | N39.4: Other specified urinary incontinence,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
879,N39,(other disorders of urinary system),20,Infections,Other,1.0,0.027777777777777776,1,N39.0,"N39.0: Urinary tract infection, site not specified",hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
888,N48,(other disorders of penis),30,Pain,Other,1.0,0.027777777777777776,1,N48.8,N48.8: Other specified disorders of penis,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
890,N50,(other disorders of male genital organs),30,Pain,Other,1.0,0.027777777777777776,1,N50.8,N50.8: Other specified disorders of male genital organs,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
896,N64,(other disorders of breast),30,Pain,Other,1.0,0.027777777777777776,1,N64.4,N64.4: Mastodynia,hfrm_child_of_label,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1133,C00,Malignant neoplasm of lip,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C00,C00: Malignant neoplasm of lip,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1134,C01,Malignant neoplasm of base of tongue,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C01,C01: Malignant neoplasm of base of tongue,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1135,C02,Malignant neoplasm of other and unspecified parts of tongue,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C02,C02: Malignant neoplasm of other and unspecified parts of tongue,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1136,C03,Malignant neoplasm of gum,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C03,C03: Malignant neoplasm of gum,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1137,C04,Malignant neoplasm of floor of mouth,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C04,C04: Malignant neoplasm of floor of mouth,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1138,C05,Malignant neoplasm of palate,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C05,C05: Malignant neoplasm of palate,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1139,C06,Malignant neoplasm of other and unspecified parts of mouth,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C06,C06: Malignant neoplasm of other and unspecified parts of mouth,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1140,C07,Malignant neoplasm of parotid gland,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C07,C07: Malignant neoplasm of parotid gland,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1141,C08,Malignant neoplasm of other and unspecified major salivary glands,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C08,C08: Malignant neoplasm of other and unspecified major,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1142,C09,Malignant neoplasm of tonsil,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C09,C09: Malignant neoplasm of tonsil,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1143,C10,Malignant neoplasm of oropharynx,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C10,C10: Malignant neoplasm of oropharynx,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1144,C11,Malignant neoplasm of nasopharynx,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C11,C11: Malignant neoplasm of nasopharynx,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1145,C12,Malignant neoplasm of pyriform sinus,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C12,C12: Malignant neoplasm of pyriform sinus,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1146,C13,Malignant neoplasm of hypopharynx,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C13,C13: Malignant neoplasm of hypopharynx,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1147,C14,"Malignant neoplasm of other and ill-defined sites in the lip, oral cavity and pharynx",3,Cancer,Morbidity,1.0,0.027777777777777776,1,C14,"C14: Malignant neoplasm of other and ill-defined sites in the lip,",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1148,C15,Malignant neoplasm of oesophagus,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C15,C15: Malignant neoplasm of oesophagus,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1149,C16,Malignant neoplasm of stomach,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C16,C16: Malignant neoplasm of stomach,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1150,C17,Malignant neoplasm of small intestine,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C17,C17: Malignant neoplasm of small intestine,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1151,C18,Malignant neoplasm of colon,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C18,C18: Malignant neoplasm of colon,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1152,C19,Malignant neoplasm of rectosigmoid junction,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C19,C19: Malignant neoplasm of rectosigmoid junction,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1153,C20,Malignant neoplasm of rectum,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C20,C20: Malignant neoplasm of rectum,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1154,C21,Malignant neoplasm of anus and anal canal,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C21,C21: Malignant neoplasm of anus and anal canal,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1155,C22,Malignant neoplasm of liver and intrahepatic bile ducts,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C22,C22: Malignant neoplasm of liver and intrahepatic bile ducts,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1156,C23,Malignant neoplasm of gallbladder,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C23,C23: Malignant neoplasm of gallbladder,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1157,C24,Malignant neoplasm of other and unspecified parts of biliary tract,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C24,C24: Malignant neoplasm of other and unspecified parts,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1158,C25,Malignant neoplasm of pancreas,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C25,C25: Malignant neoplasm of pancreas,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1159,C26,Malignant neoplasm of other and ill-defined digestive organs,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C26,C26: Malignant neoplasm of other and ill-defined digestive organs,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1160,C30,Malignant neoplasm of nasal cavity and middle ear,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C30,C30: Malignant neoplasm of nasal cavity and middle ear,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1161,C31,Malignant neoplasm of accessory sinuses,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C31,C31: Malignant neoplasm of accessory sinuses,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1162,C32,Malignant neoplasm of larynx,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C32,C32: Malignant neoplasm of larynx,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1163,C33,Malignant neoplasm of trachea,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C33,C33: Malignant neoplasm of trachea,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1164,C34,Malignant neoplasm of bronchus and lung,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C34,C34: Malignant neoplasm of bronchus and lung,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1165,C37,Malignant neoplasm of thymus,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C37,C37: Malignant neoplasm of thymus,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1166,C38,"Malignant neoplasm of heart, mediastinum and pleura",3,Cancer,Morbidity,1.0,0.027777777777777776,1,C38,"C38: Malignant neoplasm of heart, mediastinum and pleura",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1167,C39,Malignant neoplasm of other and ill-defined sites in the respiratory system and intrathoracic organs,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C39,C39: Malignant neoplasm of other and ill-defined sites in the,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1168,C40,Malignant neoplasm of bone and articular cartilage of limbs,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C40,C40: Malignant neoplasm of bone and articular cartilage of limbs,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1169,C41,Malignant neoplasm of bone and articular cartilage of other and unspecified sites,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C41,C41: Malignant neoplasm of bone and articular cartilage of other,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1171,C43,Malignant melanoma of skin,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C43,C43: Malignant melanoma of skin,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1172,C44,Other malignant neoplasms of skin,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C44,C44: Other malignant neoplasms of skin,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1173,C45,Mesothelioma,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C45,C45: Mesothelioma,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1174,C46,Kaposi's sarcoma,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C46,C46: Kaposi’s sarcoma,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1175,C47,Malignant neoplasm of peripheral nerves and autonomic nervous system,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C47,C47: Malignant neoplasm of peripheral nerves and autonomic,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1176,C48,Malignant neoplasm of retroperitoneum and peritoneum,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C48,C48: Malignant neoplasm of retroperitoneum and peritoneum,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1177,C49,Malignant neoplasm of other connective and soft tissue,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C49,C49: Malignant neoplasm of other connective and soft tissue,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1178,C50,Malignant neoplasm of breast,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C50,C50: Malignant neoplasm of breast,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1179,C51,Malignant neoplasm of vulva,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C51,C51: Malignant neoplasm of vulva,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1180,C52,Malignant neoplasm of vagina,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C52,C52: Malignant neoplasm of vagina,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1181,C53,Malignant neoplasm of cervix uteri,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C53,C53: Malignant neoplasm of cervix uteri,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1182,C54,Malignant neoplasm of corpus uteri,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C54,C54: Malignant neoplasm of corpus uteri,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1183,C55,"Malignant neoplasm of uterus, part unspecified",3,Cancer,Morbidity,1.0,0.027777777777777776,1,C55,"C55: Malignant neoplasm of uterus, part unspecified",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1184,C56,Malignant neoplasm of ovary,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C56,C56: Malignant neoplasm of ovary,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1185,C57,Malignant neoplasm of other and unspecified female genital organs,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C57,C57: Malignant neoplasm of other and unspecified female,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1186,C58,Malignant neoplasm of placenta,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C58,C58: Malignant neoplasm of placenta,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1187,C60,Malignant neoplasm of penis,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C60,C60: Malignant neoplasm of penis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1188,C61,Malignant neoplasm of prostate,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C61,C61: Malignant neoplasm of prostate,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1189,C62,Malignant neoplasm of testis,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C62,C62: Malignant neoplasm of testis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1190,C63,Malignant neoplasm of other and unspecified male genital organs,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C63,C63: Malignant neoplasm of other and unspecified male,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1191,C64,"Malignant neoplasm of kidney, except renal pelvis",3,Cancer,Morbidity,1.0,0.027777777777777776,1,C64,"C64: Malignant neoplasm of kidney, except renal pelvis",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1192,C65,Malignant neoplasm of renal pelvis,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C65,C65: Malignant neoplasm of renal pelvis,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1193,C66,Malignant neoplasm of ureter,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C66,C66: Malignant neoplasm of ureter,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1194,C67,Malignant neoplasm of bladder,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C67,C67: Malignant neoplasm of bladder,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1195,C68,Malignant neoplasm of other and unspecified urinary organs,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C68,C68: Malignant neoplasm of other and unspecified urinary organs,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1196,C69,Malignant neoplasm of eye and adnexa,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C69,C69: Malignant neoplasm of eye and adnexa,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1197,C70,Malignant neoplasm of meninges,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C70,C70: Malignant neoplasm of meninges,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1198,C71,Malignant neoplasm of brain,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C71,C71: Malignant neoplasm of brain,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1199,C72,"Malignant neoplasm of spinal cord, cranial nerves and other parts of central nervous system",3,Cancer,Morbidity,1.0,0.027777777777777776,1,C72,"C72: Malignant neoplasm of spinal cord, cranial nerves and other",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1200,C73,Malignant neoplasm of thyroid gland,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C73,C73: Malignant neoplasm of thyroid gland,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1201,C74,Malignant neoplasm of adrenal gland,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C74,C74: Malignant neoplasm of adrenal gland,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1202,C75,Malignant neoplasm of other endocrine glands and related structures,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C75,C75: Malignant neoplasm of other endocrine glands,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1203,C76,Malignant neoplasm of other and ill-defined sites,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C76,C76: Malignant neoplasm of other and ill-defined sites,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1204,C77,Secondary and unspecified malignant neoplasm of lymph nodes,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C77,C77: Secondary and unspecified malignant neoplasm,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1205,C78,Secondary malignant neoplasm of respiratory and digestive organs,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C78,C78: Secondary malignant neoplasm of respiratory,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1206,C79,Secondary malignant neoplasm of other sites,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C79,C79: Secondary malignant neoplasm of other and,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1207,C80,Malignant neoplasm without specification of site,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C80,C80: Malignant neoplasm without specification of site,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1208,C81,Hodgkin's disease,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C81,C81: Hodgkin lymphoma,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1209,C82,Follicular [nodular] non-Hodgkin's lymphoma,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C82,C82: Follicular lymphoma,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1210,C83,Diffuse non-Hodgkin's lymphoma,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C83,C83: Non-follicular lymphoma,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1211,C84,Peripheral and cutaneous T-cell lymphomas,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C84,C84: Mature T/NK-cell lymphomas,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1212,C85,Other and unspecified types of non-Hodgkin's lymphoma,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C85,C85: Other and unspecified types of non-Hodgkin lymphoma,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1213,C86,Other specified types of T/NK-cell lymphoma,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C86,C86: Other specified types of T/NK-cell lymphoma,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1214,C88,Malignant immunoproliferative diseases,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C88,C88: Malignant immunoproliferative diseases,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1215,C90,Multiple myeloma and malignant plasma cell neoplasms,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C90,C90: Multiple myeloma and malignant plasma cell neoplasms,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1216,C91,Lymphoid leukaemia,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C91,C91: Lymphoid leukaemia,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1217,C92,Myeloid leukaemia,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C92,C92: Myeloid leukaemia,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1218,C93,Monocytic leukaemia,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C93,C93: Monocytic leukaemia,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1219,C94,Other leukaemias of specified cell type,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C94,C94: Other leukaemias of specified cell type,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1220,C95,Leukaemia of unspecified cell type,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C95,C95: Leukaemia of unspecified cell type,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1221,C96,"Other and unspecified malignant neoplasms of lymphoid, haematopoietic and related tissue",3,Cancer,Morbidity,1.0,0.027777777777777776,1,C96,"C96: Other and unspecified malignant neoplasms of lymphoid,",exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1222,C97,Malignant neoplasms of independent (primary) multiple sites,3,Cancer,Morbidity,1.0,0.027777777777777776,1,C97,C97: Malignant neoplasms of independent (primary) multiple sites,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1246,D37,Neoplasm of uncertain or unknown behaviour of oral cavity and digestive organs,3,Cancer,Morbidity,1.0,0.027777777777777776,1,D37,D37: Neoplasm of uncertain or unknown behaviour of oral cavity,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1247,D38,Neoplasm of uncertain or unknown behaviour of middle ear and respiratory and intrathoracic organs,3,Cancer,Morbidity,1.0,0.027777777777777776,1,D38,D38: Neoplasm of uncertain or unknown behaviour of middle ear,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1248,D39,Neoplasm of uncertain or unknown behaviour of female genital organs,3,Cancer,Morbidity,1.0,0.027777777777777776,1,D39,D39: Neoplasm of uncertain or unknown behaviour of female,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1249,D40,Neoplasm of uncertain or unknown behaviour of male genital organs,3,Cancer,Morbidity,1.0,0.027777777777777776,1,D40,D40: Neoplasm of uncertain or unknown behaviour of male,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1250,D41,Neoplasm of uncertain or unknown behaviour of urinary organs,3,Cancer,Morbidity,1.0,0.027777777777777776,1,D41,D41: Neoplasm of uncertain or unknown behaviour,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1251,D42,Neoplasm of uncertain or unknown behaviour of meninges,3,Cancer,Morbidity,1.0,0.027777777777777776,1,D42,D42: Neoplasm of uncertain or unknown behaviour of meninges,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1252,D43,Neoplasm of uncertain or unknown behaviour of brain and central nervous system,3,Cancer,Morbidity,1.0,0.027777777777777776,1,D43,D43: Neoplasm of uncertain or unknown behaviour of brain and,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1253,D44,Neoplasm of uncertain or unknown behaviour of endocrine glands,3,Cancer,Morbidity,1.0,0.027777777777777776,1,D44,D44: Neoplasm of uncertain or unknown behaviour,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1254,D45,Polycythaemia vera,3,Cancer,Morbidity,1.0,0.027777777777777776,1,D45,D45: Polycythaemia vera,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1255,D46,Myelodysplastic syndromes,3,Cancer,Morbidity,1.0,0.027777777777777776,1,D46,D46: Myelodysplastic syndromes,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1256,D47,"Other neoplasms of uncertain or unknown behaviour of lymphoid, haematopoietic and related tissue",3,Cancer,Morbidity,1.0,0.027777777777777776,1,D47,D47: Other neoplasms of uncertain or unknown behaviour,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
1257,D48,Neoplasm of uncertain or unknown behaviour of other and unspecified sites,3,Cancer,Morbidity,1.0,0.027777777777777776,1,D48,D48: Neoplasm of uncertain or unknown behaviour of other,exact,cihi-hospital-frailty-risk-measure-meth-notes-en.pdf
|
||||
|
File diff suppressed because it is too large
Load Diff
717
compute_deephealth_indices_landmarks.py
Normal file
717
compute_deephealth_indices_landmarks.py
Normal file
@@ -0,0 +1,717 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import multiprocessing as mp
|
||||
import time
|
||||
from concurrent.futures import ProcessPoolExecutor, as_completed
|
||||
from pathlib import Path
|
||||
from typing import Any, Iterable
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import torch
|
||||
from torch.nn.utils.rnn import pad_sequence
|
||||
from torch.utils.data import DataLoader, IterableDataset, get_worker_info
|
||||
from tqdm.auto import tqdm
|
||||
|
||||
from burden_index import (
|
||||
build_readout_grid,
|
||||
load_deephealth_context,
|
||||
probabilities_from_hidden,
|
||||
)
|
||||
from evaluate_auc_v2 import make_eval_indices, parse_float_list
|
||||
from targets import CHECKUP_IDX, NO_EVENT_IDX, PAD_IDX
|
||||
|
||||
|
||||
def _parse_landmark_ages(args: argparse.Namespace) -> np.ndarray:
|
||||
explicit = parse_float_list(args.landmark_ages)
|
||||
if explicit:
|
||||
ages = np.asarray(explicit, dtype=np.float32)
|
||||
else:
|
||||
ages = np.arange(
|
||||
float(args.landmark_start),
|
||||
float(args.landmark_stop) + 1e-6,
|
||||
float(args.landmark_step),
|
||||
dtype=np.float32,
|
||||
)
|
||||
if ages.size == 0:
|
||||
raise ValueError("No landmark ages were provided.")
|
||||
return ages
|
||||
|
||||
|
||||
def _parse_devices(args: argparse.Namespace) -> list[str | None]:
|
||||
if args.devices is not None and str(args.devices).strip():
|
||||
devices = [x.strip() for x in str(args.devices).split(",") if x.strip()]
|
||||
if not devices:
|
||||
raise ValueError("--devices was provided but no devices were parsed.")
|
||||
return devices
|
||||
return [args.device]
|
||||
|
||||
|
||||
def _load_index_matrices(
|
||||
*,
|
||||
organ_mapping_csv: Path,
|
||||
hfrs_mapping_csv: Path,
|
||||
) -> tuple[np.ndarray, list[dict[str, Any]], dict[str, Any]]:
|
||||
organ_df = pd.read_csv(organ_mapping_csv)
|
||||
organ_required = {"token_id", "organ_id", "organ_label", "organ_weight"}
|
||||
missing = sorted(organ_required - set(organ_df.columns))
|
||||
if missing:
|
||||
raise ValueError(f"{organ_mapping_csv} is missing required columns: {missing}")
|
||||
organ_df = organ_df.copy()
|
||||
organ_df["token_id"] = pd.to_numeric(organ_df["token_id"], errors="raise").astype(int)
|
||||
organ_df["organ_weight"] = pd.to_numeric(
|
||||
organ_df["organ_weight"], errors="raise"
|
||||
).astype(float)
|
||||
organ_df = organ_df[(organ_df["organ_id"].astype(str) != "") & (organ_df["organ_weight"] > 0)]
|
||||
if organ_df.empty:
|
||||
raise ValueError(f"{organ_mapping_csv} has no mapped organ rows.")
|
||||
|
||||
hfrs_df = pd.read_csv(hfrs_mapping_csv)
|
||||
hfrs_required = {"token_id", "hfrs_weight"}
|
||||
missing = sorted(hfrs_required - set(hfrs_df.columns))
|
||||
if missing:
|
||||
raise ValueError(f"{hfrs_mapping_csv} is missing required columns: {missing}")
|
||||
hfrs_df = hfrs_df.copy()
|
||||
hfrs_df["token_id"] = pd.to_numeric(hfrs_df["token_id"], errors="raise").astype(int)
|
||||
hfrs_df["hfrs_weight"] = pd.to_numeric(
|
||||
hfrs_df["hfrs_weight"], errors="raise"
|
||||
).astype(float)
|
||||
hfrs_df = hfrs_df[hfrs_df["hfrs_weight"] > 0]
|
||||
if hfrs_df.empty:
|
||||
raise ValueError(f"{hfrs_mapping_csv} has no non-zero HFRS weights.")
|
||||
|
||||
union_disease_ids = np.asarray(
|
||||
sorted(
|
||||
set(organ_df["token_id"].astype(int).tolist())
|
||||
| set(hfrs_df["token_id"].astype(int).tolist())
|
||||
),
|
||||
dtype=np.int64,
|
||||
)
|
||||
union_pos = {int(token): i for i, token in enumerate(union_disease_ids.tolist())}
|
||||
|
||||
organ_ids = sorted(organ_df["organ_id"].astype(str).unique().tolist())
|
||||
organ_pos = {organ_id: i for i, organ_id in enumerate(organ_ids)}
|
||||
organ_matrix = np.zeros((len(organ_ids), union_disease_ids.size), dtype=np.float32)
|
||||
organ_meta_by_id = {}
|
||||
for _, row in organ_df.iterrows():
|
||||
organ_id = str(row["organ_id"])
|
||||
token = int(row["token_id"])
|
||||
organ_matrix[organ_pos[organ_id], union_pos[token]] = 1.0
|
||||
organ_meta_by_id.setdefault(
|
||||
organ_id,
|
||||
{
|
||||
"index_type": "organ_involvement",
|
||||
"index_id": organ_id,
|
||||
"index_label": str(row["organ_label"]),
|
||||
},
|
||||
)
|
||||
organ_meta = [organ_meta_by_id[organ_id] for organ_id in organ_ids]
|
||||
|
||||
hfrs_weights = np.zeros(union_disease_ids.size, dtype=np.float32)
|
||||
for _, row in hfrs_df.iterrows():
|
||||
hfrs_weights[union_pos[int(row["token_id"])]] = float(row["hfrs_weight"])
|
||||
hfrs_meta = {
|
||||
"index_type": "frailty_risk",
|
||||
"index_id": "deephealth_hfrs",
|
||||
"index_label": "DeepHealth-HFRS frailty risk index",
|
||||
}
|
||||
|
||||
matrices = [
|
||||
{
|
||||
"kind": "organ_involvement",
|
||||
"matrix": organ_matrix,
|
||||
"meta": organ_meta,
|
||||
},
|
||||
{
|
||||
"kind": "frailty_risk",
|
||||
"weights": hfrs_weights,
|
||||
"meta": hfrs_meta,
|
||||
},
|
||||
]
|
||||
return union_disease_ids, matrices, {
|
||||
"organ_mapped_tokens": int(organ_df["token_id"].nunique()),
|
||||
"hfrs_mapped_tokens": int(hfrs_df["token_id"].nunique()),
|
||||
}
|
||||
|
||||
|
||||
def _config_split_indices(
|
||||
n: int,
|
||||
cfg: dict[str, Any],
|
||||
eval_split: str,
|
||||
subset_size: int,
|
||||
) -> np.ndarray:
|
||||
args = argparse.Namespace(
|
||||
train_ratio=None,
|
||||
val_ratio=None,
|
||||
test_ratio=None,
|
||||
seed=None,
|
||||
eval_split=eval_split,
|
||||
dataset_subset_size=subset_size if subset_size > 0 else None,
|
||||
)
|
||||
|
||||
class _Sized:
|
||||
def __len__(self) -> int:
|
||||
return n
|
||||
|
||||
return make_eval_indices(_Sized(), args, cfg)
|
||||
|
||||
|
||||
def _eligible_landmark_rows(
|
||||
dataset: Any,
|
||||
subset_indices: np.ndarray,
|
||||
landmark_ages: np.ndarray,
|
||||
*,
|
||||
min_history_events: int,
|
||||
) -> list[dict[str, Any]]:
|
||||
rows: list[dict[str, Any]] = []
|
||||
special = np.asarray([PAD_IDX, CHECKUP_IDX, NO_EVENT_IDX], dtype=np.int64)
|
||||
for patient_id, dataset_index in enumerate(subset_indices.tolist()):
|
||||
sample = dataset.samples[int(dataset_index)]
|
||||
seq_event = np.asarray(sample["event_seq"], dtype=np.int64)
|
||||
seq_time = np.asarray(sample["time_seq"], dtype=np.float32)
|
||||
tgt_event = np.asarray(sample["target_event_seq"], dtype=np.int64)
|
||||
tgt_time = np.asarray(sample["target_time_seq"], dtype=np.float32)
|
||||
if seq_event.size == 0 or tgt_event.size == 0:
|
||||
continue
|
||||
|
||||
full_event = np.concatenate([seq_event, tgt_event[-1:]])
|
||||
full_time = np.concatenate([seq_time, tgt_time[-1:]])
|
||||
followup_end = float(np.max(full_time))
|
||||
|
||||
for landmark_age in landmark_ages.tolist():
|
||||
t_query = np.float32(float(landmark_age))
|
||||
if not (followup_end > float(t_query)):
|
||||
continue
|
||||
prefix_mask = full_time <= t_query
|
||||
if not np.any(prefix_mask):
|
||||
continue
|
||||
prefix_events = full_event[prefix_mask].astype(np.int64, copy=False)
|
||||
valid_history = ~np.isin(prefix_events, special)
|
||||
if int(valid_history.sum()) < int(min_history_events):
|
||||
continue
|
||||
rows.append(
|
||||
{
|
||||
"patient_id": int(patient_id),
|
||||
"dataset_index": int(dataset_index),
|
||||
"sex": int(sample["sex"]),
|
||||
"landmark_age": t_query,
|
||||
"t_query": t_query,
|
||||
"followup_end_time": np.float32(followup_end),
|
||||
"event_seq": prefix_events,
|
||||
"time_seq": full_time[prefix_mask].astype(np.float32, copy=False),
|
||||
"other_type": np.asarray(sample["other_type"], dtype=np.int64),
|
||||
"other_value": np.asarray(sample["other_value"], dtype=np.float32),
|
||||
"other_value_kind": np.asarray(sample["other_value_kind"], dtype=np.int64),
|
||||
"other_time": np.asarray(sample["other_time"], dtype=np.float32),
|
||||
}
|
||||
)
|
||||
return rows
|
||||
|
||||
|
||||
def _row_to_worker_spec(row: dict[str, Any]) -> dict[str, Any]:
|
||||
return {
|
||||
"patient_id": int(row["patient_id"]),
|
||||
"dataset_index": int(row["dataset_index"]),
|
||||
"landmark_age": float(row["landmark_age"]),
|
||||
"followup_end_time": float(row["followup_end_time"]),
|
||||
}
|
||||
|
||||
|
||||
def _materialize_worker_rows(
|
||||
dataset: Any,
|
||||
row_specs: list[dict[str, Any]],
|
||||
) -> list[dict[str, Any]]:
|
||||
rows: list[dict[str, Any]] = []
|
||||
for spec in row_specs:
|
||||
sample = dataset.samples[int(spec["dataset_index"])]
|
||||
seq_event = np.asarray(sample["event_seq"], dtype=np.int64)
|
||||
seq_time = np.asarray(sample["time_seq"], dtype=np.float32)
|
||||
tgt_event = np.asarray(sample["target_event_seq"], dtype=np.int64)
|
||||
tgt_time = np.asarray(sample["target_time_seq"], dtype=np.float32)
|
||||
full_event = np.concatenate([seq_event, tgt_event[-1:]])
|
||||
full_time = np.concatenate([seq_time, tgt_time[-1:]])
|
||||
t_query = np.float32(float(spec["landmark_age"]))
|
||||
prefix_mask = full_time <= t_query
|
||||
rows.append(
|
||||
{
|
||||
"patient_id": int(spec["patient_id"]),
|
||||
"dataset_index": int(spec["dataset_index"]),
|
||||
"sex": int(sample["sex"]),
|
||||
"landmark_age": t_query,
|
||||
"t_query": t_query,
|
||||
"followup_end_time": np.float32(float(spec["followup_end_time"])),
|
||||
"event_seq": full_event[prefix_mask].astype(np.int64, copy=False),
|
||||
"time_seq": full_time[prefix_mask].astype(np.float32, copy=False),
|
||||
"other_type": np.asarray(sample["other_type"], dtype=np.int64),
|
||||
"other_value": np.asarray(sample["other_value"], dtype=np.float32),
|
||||
"other_value_kind": np.asarray(sample["other_value_kind"], dtype=np.int64),
|
||||
"other_time": np.asarray(sample["other_time"], dtype=np.float32),
|
||||
}
|
||||
)
|
||||
return rows
|
||||
|
||||
|
||||
class HistoricalReadoutDataset(IterableDataset):
|
||||
def __init__(self, rows: list[dict[str, Any]]) -> None:
|
||||
super().__init__()
|
||||
self.rows = rows
|
||||
|
||||
def __iter__(self) -> Iterable[dict[str, torch.Tensor]]:
|
||||
worker = get_worker_info()
|
||||
if worker is None:
|
||||
start, step = 0, 1
|
||||
else:
|
||||
start, step = int(worker.id), int(worker.num_workers)
|
||||
|
||||
for row_idx in range(start, len(self.rows), step):
|
||||
row = self.rows[row_idx]
|
||||
grid = build_readout_grid(
|
||||
event_seq=row["event_seq"],
|
||||
time_seq=row["time_seq"],
|
||||
other_type=row["other_type"],
|
||||
other_time=row["other_time"],
|
||||
t_query=float(row["t_query"]),
|
||||
)
|
||||
if grid.size == 0:
|
||||
continue
|
||||
end_times = np.concatenate([grid[1:], np.asarray([row["t_query"]], dtype=np.float32)])
|
||||
deltas = np.maximum(end_times - grid, 0.0).astype(np.float32)
|
||||
valid = deltas > 0
|
||||
for query_time, delta in zip(grid[valid].tolist(), deltas[valid].tolist()):
|
||||
yield _make_readout_job(row, row_idx, query_time, delta)
|
||||
|
||||
|
||||
def _make_readout_job(
|
||||
row: dict[str, Any],
|
||||
row_idx: int,
|
||||
query_time: float,
|
||||
delta: float,
|
||||
) -> dict[str, torch.Tensor]:
|
||||
return {
|
||||
"event_seq": torch.from_numpy(np.asarray(row["event_seq"], dtype=np.int64)).long(),
|
||||
"time_seq": torch.from_numpy(np.asarray(row["time_seq"], dtype=np.float32)).float(),
|
||||
"sex": torch.tensor(int(row["sex"]), dtype=torch.long),
|
||||
"other_type": torch.from_numpy(np.asarray(row["other_type"], dtype=np.int64)).long(),
|
||||
"other_value": torch.from_numpy(np.asarray(row["other_value"], dtype=np.float32)).float(),
|
||||
"other_value_kind": torch.from_numpy(
|
||||
np.asarray(row["other_value_kind"], dtype=np.int64)
|
||||
).long(),
|
||||
"other_time": torch.from_numpy(np.asarray(row["other_time"], dtype=np.float32)).float(),
|
||||
"query_time": torch.tensor(float(query_time), dtype=torch.float32),
|
||||
"delta": torch.tensor(float(delta), dtype=torch.float32),
|
||||
"row_idx": torch.tensor(int(row_idx), dtype=torch.long),
|
||||
}
|
||||
|
||||
|
||||
def _collate_readout_jobs(batch: list[dict[str, torch.Tensor]]) -> dict[str, torch.Tensor]:
|
||||
event_seq = pad_sequence(
|
||||
[x["event_seq"] for x in batch], batch_first=True, padding_value=PAD_IDX
|
||||
)
|
||||
return {
|
||||
"event_seq": event_seq,
|
||||
"time_seq": pad_sequence(
|
||||
[x["time_seq"] for x in batch], batch_first=True, padding_value=0.0
|
||||
),
|
||||
"padding_mask": event_seq > PAD_IDX,
|
||||
"sex": torch.stack([x["sex"] for x in batch]),
|
||||
"other_type": pad_sequence(
|
||||
[x["other_type"] for x in batch], batch_first=True, padding_value=0
|
||||
),
|
||||
"other_value": pad_sequence(
|
||||
[x["other_value"] for x in batch], batch_first=True, padding_value=0.0
|
||||
),
|
||||
"other_value_kind": pad_sequence(
|
||||
[x["other_value_kind"] for x in batch], batch_first=True, padding_value=0
|
||||
),
|
||||
"other_time": pad_sequence(
|
||||
[x["other_time"] for x in batch], batch_first=True, padding_value=0.0
|
||||
),
|
||||
"query_time": torch.stack([x["query_time"] for x in batch]),
|
||||
"delta": torch.stack([x["delta"] for x in batch]),
|
||||
"row_idx": torch.stack([x["row_idx"] for x in batch]),
|
||||
}
|
||||
|
||||
|
||||
@torch.inference_mode()
|
||||
def _readout_probabilities(
|
||||
*,
|
||||
ctx: Any,
|
||||
batch: dict[str, torch.Tensor],
|
||||
disease_ids: np.ndarray,
|
||||
) -> torch.Tensor:
|
||||
event = batch["event_seq"].long().to(ctx.device, non_blocking=True)
|
||||
hidden = ctx.model(
|
||||
event_seq=event,
|
||||
time_seq=batch["time_seq"].float().to(ctx.device, non_blocking=True),
|
||||
sex=batch["sex"].long().to(ctx.device, non_blocking=True),
|
||||
padding_mask=event > PAD_IDX,
|
||||
t_query=batch["query_time"].float().to(ctx.device, non_blocking=True),
|
||||
other_type=batch["other_type"].long().to(ctx.device, non_blocking=True),
|
||||
other_value=batch["other_value"].float().to(ctx.device, non_blocking=True),
|
||||
other_value_kind=batch["other_value_kind"].long().to(ctx.device, non_blocking=True),
|
||||
other_time=batch["other_time"].float().to(ctx.device, non_blocking=True),
|
||||
target_mode="all_future",
|
||||
)
|
||||
deltas = batch["delta"].detach().cpu().numpy().astype(np.float32, copy=False)
|
||||
prob = probabilities_from_hidden(
|
||||
ctx=ctx,
|
||||
hidden=hidden,
|
||||
disease_ids=disease_ids,
|
||||
deltas=deltas,
|
||||
)
|
||||
return torch.as_tensor(prob, dtype=torch.float32, device=ctx.device)
|
||||
|
||||
|
||||
def _project_rows(
|
||||
*,
|
||||
rows: list[dict[str, Any]],
|
||||
survival_by_row: torch.Tensor,
|
||||
matrices: list[dict[str, Any]],
|
||||
ctx: Any,
|
||||
) -> list[dict[str, Any]]:
|
||||
disease_expression = 1.0 - survival_by_row.clamp(0.0, 1.0)
|
||||
disease_intensity = -torch.log(survival_by_row.clamp(1e-7, 1.0))
|
||||
out: list[dict[str, Any]] = []
|
||||
|
||||
organ_matrix = torch.as_tensor(
|
||||
matrices[0]["matrix"], dtype=torch.float32, device=ctx.device
|
||||
)
|
||||
organ_values = -torch.expm1(-torch.matmul(disease_intensity, organ_matrix.T))
|
||||
organ_values_np = organ_values.detach().cpu().numpy()
|
||||
|
||||
hfrs_weights = torch.as_tensor(
|
||||
matrices[1]["weights"], dtype=torch.float32, device=ctx.device
|
||||
)
|
||||
hfrs_values = torch.matmul(disease_expression, hfrs_weights)
|
||||
hfrs_values_np = hfrs_values.detach().cpu().numpy()
|
||||
|
||||
for row_idx, row in enumerate(rows):
|
||||
base = {
|
||||
"patient_id": row["patient_id"],
|
||||
"dataset_index": row["dataset_index"],
|
||||
"sex": row["sex"],
|
||||
"landmark_age": float(row["landmark_age"]),
|
||||
"t_query": float(row["t_query"]),
|
||||
"followup_end_time": float(row["followup_end_time"]),
|
||||
}
|
||||
for dim_idx, meta in enumerate(matrices[0]["meta"]):
|
||||
out.append(
|
||||
{
|
||||
**base,
|
||||
"index_type": meta["index_type"],
|
||||
"index_id": meta["index_id"],
|
||||
"index_label": meta["index_label"],
|
||||
"index_value": float(organ_values_np[row_idx, dim_idx]),
|
||||
}
|
||||
)
|
||||
out.append(
|
||||
{
|
||||
**base,
|
||||
"index_type": matrices[1]["meta"]["index_type"],
|
||||
"index_id": matrices[1]["meta"]["index_id"],
|
||||
"index_label": matrices[1]["meta"]["index_label"],
|
||||
"index_value": float(hfrs_values_np[row_idx]),
|
||||
}
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
def _compute_rows(
|
||||
*,
|
||||
rows: list[dict[str, Any]],
|
||||
disease_ids: np.ndarray,
|
||||
matrices: list[dict[str, Any]],
|
||||
readout_batch_size: int,
|
||||
num_workers: int,
|
||||
ctx: Any,
|
||||
log_prefix: str,
|
||||
) -> tuple[list[dict[str, Any]], int, dict[str, float]]:
|
||||
survival_by_row = torch.ones(
|
||||
(len(rows), disease_ids.size), dtype=torch.float32, device=ctx.device
|
||||
)
|
||||
loader = DataLoader(
|
||||
HistoricalReadoutDataset(rows),
|
||||
batch_size=max(1, int(readout_batch_size)),
|
||||
collate_fn=_collate_readout_jobs,
|
||||
num_workers=max(0, int(num_workers)),
|
||||
pin_memory=ctx.device.type == "cuda",
|
||||
persistent_workers=int(num_workers) > 0,
|
||||
prefetch_factor=2 if int(num_workers) > 0 else None,
|
||||
)
|
||||
readout_jobs = 0
|
||||
n_batches = 0
|
||||
forward_sec = 0.0
|
||||
reduce_sec = 0.0
|
||||
for batch in loader:
|
||||
t0 = time.perf_counter()
|
||||
prob = _readout_probabilities(ctx=ctx, batch=batch, disease_ids=disease_ids)
|
||||
if ctx.device.type == "cuda":
|
||||
torch.cuda.synchronize(ctx.device)
|
||||
forward_sec += time.perf_counter() - t0
|
||||
|
||||
t1 = time.perf_counter()
|
||||
row_indices = batch["row_idx"].long().to(ctx.device, non_blocking=True)
|
||||
interval_survival = 1.0 - prob.clamp(0.0, 1.0)
|
||||
if hasattr(survival_by_row, "scatter_reduce_"):
|
||||
survival_by_row.scatter_reduce_(
|
||||
dim=0,
|
||||
index=row_indices[:, None].expand_as(interval_survival),
|
||||
src=interval_survival,
|
||||
reduce="prod",
|
||||
include_self=True,
|
||||
)
|
||||
else:
|
||||
for job_idx in range(interval_survival.shape[0]):
|
||||
survival_by_row[int(row_indices[job_idx].item())] *= interval_survival[job_idx]
|
||||
if ctx.device.type == "cuda":
|
||||
torch.cuda.synchronize(ctx.device)
|
||||
reduce_sec += time.perf_counter() - t1
|
||||
|
||||
n_batches += 1
|
||||
readout_jobs += int(batch["row_idx"].numel())
|
||||
if n_batches == 1 or n_batches % 50 == 0:
|
||||
print(
|
||||
f"{log_prefix} processed {readout_jobs} readout jobs in {n_batches} batches",
|
||||
flush=True,
|
||||
)
|
||||
|
||||
t2 = time.perf_counter()
|
||||
out = _project_rows(
|
||||
rows=rows,
|
||||
survival_by_row=survival_by_row,
|
||||
matrices=matrices,
|
||||
ctx=ctx,
|
||||
)
|
||||
if ctx.device.type == "cuda":
|
||||
torch.cuda.synchronize(ctx.device)
|
||||
reduce_sec += time.perf_counter() - t2
|
||||
return out, readout_jobs, {"forward_sec": forward_sec, "reduce_sec": reduce_sec}
|
||||
|
||||
|
||||
def _write_rows_csv(rows: list[dict[str, Any]], output_path: Path) -> int:
|
||||
df = pd.DataFrame(rows)
|
||||
df.to_csv(output_path, index=False)
|
||||
return int(len(df))
|
||||
|
||||
|
||||
def _concat_csv_shards(shard_paths: list[Path], output_path: Path) -> None:
|
||||
wrote_header = False
|
||||
with output_path.open("w", encoding="utf-8", newline="") as out_f:
|
||||
for shard_path in shard_paths:
|
||||
with shard_path.open("r", encoding="utf-8", newline="") as in_f:
|
||||
header = in_f.readline()
|
||||
if not wrote_header:
|
||||
out_f.write(header)
|
||||
wrote_header = True
|
||||
for line in in_f:
|
||||
out_f.write(line)
|
||||
shard_path.unlink(missing_ok=True)
|
||||
|
||||
|
||||
def _estimate_jobs(row: dict[str, Any]) -> int:
|
||||
grid = build_readout_grid(
|
||||
event_seq=row["event_seq"],
|
||||
time_seq=row["time_seq"],
|
||||
other_type=row["other_type"],
|
||||
other_time=row["other_time"],
|
||||
t_query=float(row["t_query"]),
|
||||
)
|
||||
if grid.size == 0:
|
||||
return 1
|
||||
end_times = np.concatenate([grid[1:], np.asarray([row["t_query"]], dtype=np.float32)])
|
||||
return max(int(np.sum(np.maximum(end_times - grid, 0.0) > 0)), 1)
|
||||
|
||||
|
||||
def _split_rows(rows: list[dict[str, Any]], devices: list[str | None]) -> list[tuple[str | None, list[dict[str, Any]]]]:
|
||||
if len(devices) <= 1:
|
||||
return [(devices[0], rows)]
|
||||
buckets: list[list[dict[str, Any]]] = [[] for _ in devices]
|
||||
loads = np.zeros(len(devices), dtype=np.int64)
|
||||
for row in sorted(rows, key=_estimate_jobs, reverse=True):
|
||||
idx = int(np.argmin(loads))
|
||||
buckets[idx].append(row)
|
||||
loads[idx] += _estimate_jobs(row)
|
||||
return [(device, bucket) for device, bucket in zip(devices, buckets) if bucket]
|
||||
|
||||
|
||||
def _worker(payload: dict[str, Any]) -> dict[str, Any]:
|
||||
device = payload["device"]
|
||||
shard_path = Path(payload["shard_path"])
|
||||
print(f"[Index worker {device}] starting with {len(payload['row_specs'])} rows", flush=True)
|
||||
ctx = load_deephealth_context(payload["run_path"], device=device)
|
||||
rows = _materialize_worker_rows(ctx.dataset, payload["row_specs"])
|
||||
out, readout_jobs, timings = _compute_rows(
|
||||
rows=rows,
|
||||
disease_ids=payload["disease_ids"],
|
||||
matrices=payload["matrices"],
|
||||
readout_batch_size=int(payload["readout_batch_size"]),
|
||||
num_workers=int(payload["num_workers"]),
|
||||
ctx=ctx,
|
||||
log_prefix=f"[Index worker {device}]",
|
||||
)
|
||||
t0 = time.perf_counter()
|
||||
row_count = _write_rows_csv(out, shard_path)
|
||||
timings["write_csv_sec"] = time.perf_counter() - t0
|
||||
print(f"[Index worker {device}] wrote {row_count} rows to {shard_path}", flush=True)
|
||||
return {
|
||||
"shard_path": str(shard_path),
|
||||
"row_count": row_count,
|
||||
"readout_jobs": readout_jobs,
|
||||
"timings": timings,
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Compute DeepHealth organ involvement and frailty risk indices."
|
||||
)
|
||||
parser.add_argument("--run_path", type=str, required=True)
|
||||
parser.add_argument(
|
||||
"--organ_mapping_csv",
|
||||
type=str,
|
||||
default="organ_involvement_label_mapping.csv",
|
||||
)
|
||||
parser.add_argument("--hfrs_mapping_csv", type=str, default="uk_hfrs_label_mapping.csv")
|
||||
parser.add_argument("--output_path", type=str, default=None)
|
||||
parser.add_argument(
|
||||
"--eval_split",
|
||||
type=str,
|
||||
default="test",
|
||||
choices=["train", "val", "valid", "validation", "test", "all"],
|
||||
)
|
||||
parser.add_argument("--landmark_ages", type=str, default=None)
|
||||
parser.add_argument("--landmark_start", type=float, default=40.0)
|
||||
parser.add_argument("--landmark_stop", type=float, default=80.0)
|
||||
parser.add_argument("--landmark_step", type=float, default=5.0)
|
||||
parser.add_argument("--min_history_events", type=int, default=1)
|
||||
parser.add_argument("--dataset_subset_size", type=int, default=0)
|
||||
parser.add_argument("--readout_batch_size", type=int, default=8192)
|
||||
parser.add_argument("--num_workers", type=int, default=4)
|
||||
parser.add_argument("--device", type=str, default=None)
|
||||
parser.add_argument("--devices", type=str, default=None)
|
||||
parser.add_argument(
|
||||
"--mp_start_method",
|
||||
type=str,
|
||||
default="fork",
|
||||
choices=["fork", "forkserver"],
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
run_path = Path(args.run_path)
|
||||
devices = _parse_devices(args)
|
||||
initial_device = "cpu" if len(devices) > 1 else devices[0]
|
||||
ctx = load_deephealth_context(run_path, device=initial_device)
|
||||
|
||||
disease_ids, matrices, mapping_counts = _load_index_matrices(
|
||||
organ_mapping_csv=Path(args.organ_mapping_csv),
|
||||
hfrs_mapping_csv=Path(args.hfrs_mapping_csv),
|
||||
)
|
||||
landmark_ages = _parse_landmark_ages(args)
|
||||
eval_split = str(args.eval_split).lower()
|
||||
if eval_split in {"valid", "validation"}:
|
||||
eval_split = "val"
|
||||
subset_indices = _config_split_indices(
|
||||
len(ctx.dataset),
|
||||
ctx.cfg,
|
||||
eval_split,
|
||||
int(args.dataset_subset_size),
|
||||
)
|
||||
rows = _eligible_landmark_rows(
|
||||
ctx.dataset,
|
||||
subset_indices,
|
||||
landmark_ages,
|
||||
min_history_events=int(args.min_history_events),
|
||||
)
|
||||
if not rows:
|
||||
raise RuntimeError("No eligible landmark rows.")
|
||||
|
||||
output_path = Path(args.output_path) if args.output_path else (
|
||||
run_path / f"deephealth_indices_{eval_split}.csv"
|
||||
)
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
chunks = _split_rows(rows, devices)
|
||||
for device, chunk in chunks:
|
||||
print(
|
||||
f"Assigned {len(chunk)} rows / ~{sum(_estimate_jobs(r) for r in chunk)} "
|
||||
f"readout jobs to {device}",
|
||||
flush=True,
|
||||
)
|
||||
|
||||
total_readout_jobs = 0
|
||||
timings = {"forward_sec": 0.0, "reduce_sec": 0.0, "write_csv_sec": 0.0}
|
||||
if len(chunks) == 1:
|
||||
out, total_readout_jobs, chunk_timings = _compute_rows(
|
||||
rows=rows,
|
||||
disease_ids=disease_ids,
|
||||
matrices=matrices,
|
||||
readout_batch_size=int(args.readout_batch_size),
|
||||
num_workers=int(args.num_workers),
|
||||
ctx=ctx,
|
||||
log_prefix="[Index main]",
|
||||
)
|
||||
for key, value in chunk_timings.items():
|
||||
timings[key] += float(value)
|
||||
t0 = time.perf_counter()
|
||||
_write_rows_csv(out, output_path)
|
||||
timings["write_csv_sec"] = time.perf_counter() - t0
|
||||
else:
|
||||
del ctx
|
||||
payloads = [
|
||||
{
|
||||
"device": device,
|
||||
"run_path": str(run_path),
|
||||
"shard_path": str(
|
||||
output_path.with_name(
|
||||
f"{output_path.stem}.part{part_idx:03d}{output_path.suffix}"
|
||||
)
|
||||
),
|
||||
"row_specs": [_row_to_worker_spec(row) for row in chunk],
|
||||
"disease_ids": disease_ids,
|
||||
"matrices": matrices,
|
||||
"readout_batch_size": int(args.readout_batch_size),
|
||||
"num_workers": int(args.num_workers),
|
||||
}
|
||||
for part_idx, (device, chunk) in enumerate(chunks)
|
||||
]
|
||||
shard_paths = []
|
||||
with ProcessPoolExecutor(
|
||||
max_workers=len(payloads),
|
||||
mp_context=mp.get_context(args.mp_start_method),
|
||||
) as executor:
|
||||
futures = [executor.submit(_worker, payload) for payload in payloads]
|
||||
for future in tqdm(
|
||||
as_completed(futures),
|
||||
total=len(futures),
|
||||
desc="Computing DeepHealth index chunks",
|
||||
dynamic_ncols=True,
|
||||
):
|
||||
result = future.result()
|
||||
shard_paths.append(Path(result["shard_path"]))
|
||||
total_readout_jobs += int(result["readout_jobs"])
|
||||
for key, value in result["timings"].items():
|
||||
timings[key] += float(value)
|
||||
t0 = time.perf_counter()
|
||||
_concat_csv_shards(sorted(shard_paths), output_path)
|
||||
timings["write_csv_sec"] += time.perf_counter() - t0
|
||||
|
||||
print(f"Run path: {run_path}")
|
||||
print(f"Eval split: {eval_split}")
|
||||
print(f"Landmark rows: {len(rows)}")
|
||||
print(f"Readout jobs: {total_readout_jobs}")
|
||||
print(f"Union disease tokens: {disease_ids.size}")
|
||||
print(f"Organ mapped tokens: {mapping_counts['organ_mapped_tokens']}")
|
||||
print(f"HFRS mapped tokens: {mapping_counts['hfrs_mapped_tokens']}")
|
||||
print(
|
||||
"Timing seconds: "
|
||||
f"forward={timings['forward_sec']:.2f}, "
|
||||
f"reduce={timings['reduce_sec']:.2f}, "
|
||||
f"write_csv={timings['write_csv_sec']:.2f}"
|
||||
)
|
||||
print(f"Devices: {', '.join(str(d) for d, _ in chunks)}")
|
||||
print(f"Output: {output_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
File diff suppressed because it is too large
Load Diff
1257
organ_involvement_label_mapping.csv
Normal file
1257
organ_involvement_label_mapping.csv
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,258 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from typing import Iterable
|
||||
|
||||
try:
|
||||
import matplotlib
|
||||
|
||||
matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
except ModuleNotFoundError as exc:
|
||||
raise ModuleNotFoundError(
|
||||
"plot_burden_index_trajectories.py requires matplotlib. "
|
||||
"Install it in the server environment before running this script."
|
||||
) from exc
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
|
||||
REQUIRED_COLUMNS = {
|
||||
"patient_id",
|
||||
"sex",
|
||||
"landmark_age",
|
||||
"burden_type",
|
||||
"burden_dimension",
|
||||
"bi_historical",
|
||||
"bi_future",
|
||||
"bi_total",
|
||||
}
|
||||
|
||||
|
||||
def _sex_label(value: object) -> str:
|
||||
text = str(value).strip().lower()
|
||||
if text in {"0", "0.0", "female", "f", "woman"}:
|
||||
return "female"
|
||||
if text in {"1", "1.0", "male", "m", "man"}:
|
||||
return "male"
|
||||
return text or "unknown"
|
||||
|
||||
|
||||
def _load_bi_csv(path: Path) -> pd.DataFrame:
|
||||
header = pd.read_csv(path, nrows=0)
|
||||
missing = sorted(REQUIRED_COLUMNS - set(header.columns))
|
||||
if missing:
|
||||
raise ValueError(f"{path} is missing required columns: {missing}")
|
||||
|
||||
df = pd.read_csv(
|
||||
path,
|
||||
usecols=[
|
||||
"patient_id",
|
||||
"sex",
|
||||
"landmark_age",
|
||||
"burden_type",
|
||||
"burden_dimension",
|
||||
"bi_historical",
|
||||
"bi_future",
|
||||
"bi_total",
|
||||
],
|
||||
)
|
||||
df["sex_label"] = df["sex"].map(_sex_label)
|
||||
df["landmark_age"] = pd.to_numeric(df["landmark_age"], errors="raise")
|
||||
for col in ["bi_historical", "bi_future", "bi_total"]:
|
||||
df[col] = pd.to_numeric(df[col], errors="raise")
|
||||
return df
|
||||
|
||||
|
||||
def _sample_patients(
|
||||
df: pd.DataFrame,
|
||||
*,
|
||||
n_per_sex: int,
|
||||
seed: int,
|
||||
) -> dict[str, np.ndarray]:
|
||||
rng = np.random.default_rng(int(seed))
|
||||
samples: dict[str, np.ndarray] = {}
|
||||
for sex_label in ["female", "male"]:
|
||||
ids = np.asarray(sorted(df.loc[df["sex_label"] == sex_label, "patient_id"].unique()))
|
||||
if ids.size == 0:
|
||||
samples[sex_label] = np.asarray([], dtype=np.int64)
|
||||
continue
|
||||
take = min(int(n_per_sex), int(ids.size))
|
||||
samples[sex_label] = np.asarray(rng.choice(ids, size=take, replace=False))
|
||||
return samples
|
||||
|
||||
|
||||
def _aggregate_total(df: pd.DataFrame) -> pd.DataFrame:
|
||||
return (
|
||||
df.groupby(["patient_id", "sex_label", "burden_type", "landmark_age"], as_index=False)
|
||||
[["bi_historical", "bi_future", "bi_total"]]
|
||||
.sum()
|
||||
)
|
||||
|
||||
|
||||
def _plot_selected_trajectories(
|
||||
total_df: pd.DataFrame,
|
||||
*,
|
||||
burden_type: str,
|
||||
selected: dict[str, np.ndarray],
|
||||
output_dir: Path,
|
||||
) -> None:
|
||||
sub = total_df[total_df["burden_type"] == burden_type].copy()
|
||||
mean_df = (
|
||||
sub.groupby(["sex_label", "landmark_age"], as_index=False)["bi_total"]
|
||||
.mean()
|
||||
.sort_values("landmark_age")
|
||||
)
|
||||
|
||||
fig, ax = plt.subplots(figsize=(9.5, 5.5), dpi=160)
|
||||
colors = {"female": "#b83280", "male": "#2563eb"}
|
||||
for sex_label in ["female", "male"]:
|
||||
patient_ids = selected.get(sex_label, np.asarray([], dtype=np.int64))
|
||||
for pid in patient_ids:
|
||||
one = sub[sub["patient_id"] == pid].sort_values("landmark_age")
|
||||
if one.empty:
|
||||
continue
|
||||
ax.plot(
|
||||
one["landmark_age"],
|
||||
one["bi_total"],
|
||||
color=colors.get(sex_label, "0.4"),
|
||||
alpha=0.22,
|
||||
linewidth=1.0,
|
||||
)
|
||||
mean_one = mean_df[mean_df["sex_label"] == sex_label]
|
||||
if not mean_one.empty:
|
||||
ax.plot(
|
||||
mean_one["landmark_age"],
|
||||
mean_one["bi_total"],
|
||||
color=colors.get(sex_label, "0.4"),
|
||||
linewidth=2.8,
|
||||
label=f"{sex_label} mean",
|
||||
)
|
||||
|
||||
ax.set_title(f"{burden_type}: sampled individual trajectories and sex-specific means")
|
||||
ax.set_xlabel("Landmark age")
|
||||
ax.set_ylabel("Total burden index")
|
||||
ax.grid(True, alpha=0.25)
|
||||
ax.legend(frameon=False)
|
||||
fig.tight_layout()
|
||||
fig.savefig(output_dir / f"{burden_type}_sampled_trajectories_by_sex.png")
|
||||
plt.close(fig)
|
||||
|
||||
|
||||
def _top_dimensions(df: pd.DataFrame, *, burden_type: str, top_n: int) -> list[str]:
|
||||
sub = df[df["burden_type"] == burden_type]
|
||||
if sub.empty:
|
||||
return []
|
||||
ranked = (
|
||||
sub.groupby("burden_dimension")["bi_total"]
|
||||
.mean()
|
||||
.sort_values(ascending=False)
|
||||
.head(int(top_n))
|
||||
)
|
||||
return [str(x) for x in ranked.index.tolist()]
|
||||
|
||||
|
||||
def _plot_dimension_mean_panels(
|
||||
df: pd.DataFrame,
|
||||
*,
|
||||
burden_type: str,
|
||||
dimensions: Iterable[str],
|
||||
output_dir: Path,
|
||||
) -> None:
|
||||
dims = list(dimensions)
|
||||
if not dims:
|
||||
return
|
||||
|
||||
mean_df = (
|
||||
df[(df["burden_type"] == burden_type) & (df["burden_dimension"].isin(dims))]
|
||||
.groupby(["sex_label", "burden_dimension", "landmark_age"], as_index=False)["bi_total"]
|
||||
.mean()
|
||||
.sort_values("landmark_age")
|
||||
)
|
||||
n_cols = min(3, len(dims))
|
||||
n_rows = int(np.ceil(len(dims) / n_cols))
|
||||
fig, axes = plt.subplots(
|
||||
n_rows,
|
||||
n_cols,
|
||||
figsize=(4.2 * n_cols, 3.2 * n_rows),
|
||||
dpi=160,
|
||||
squeeze=False,
|
||||
)
|
||||
colors = {"female": "#b83280", "male": "#2563eb"}
|
||||
for ax, dim in zip(axes.ravel(), dims):
|
||||
panel = mean_df[mean_df["burden_dimension"] == dim]
|
||||
for sex_label in ["female", "male"]:
|
||||
one = panel[panel["sex_label"] == sex_label]
|
||||
if one.empty:
|
||||
continue
|
||||
ax.plot(
|
||||
one["landmark_age"],
|
||||
one["bi_total"],
|
||||
color=colors.get(sex_label, "0.4"),
|
||||
linewidth=2.0,
|
||||
label=sex_label,
|
||||
)
|
||||
ax.set_title(str(dim), fontsize=9)
|
||||
ax.set_xlabel("Age")
|
||||
ax.set_ylabel("Mean BI")
|
||||
ax.grid(True, alpha=0.25)
|
||||
|
||||
for ax in axes.ravel()[len(dims):]:
|
||||
ax.axis("off")
|
||||
handles, labels = axes.ravel()[0].get_legend_handles_labels()
|
||||
if handles:
|
||||
fig.legend(handles, labels, loc="upper right", frameon=False)
|
||||
fig.suptitle(f"{burden_type}: sex-specific mean trajectories for top dimensions")
|
||||
fig.tight_layout(rect=(0, 0, 0.98, 0.95))
|
||||
fig.savefig(output_dir / f"{burden_type}_top_dimension_means_by_sex.png")
|
||||
plt.close(fig)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Plot DeepHealth burden-index trajectories by sex."
|
||||
)
|
||||
parser.add_argument("--input_csv", type=str, required=True)
|
||||
parser.add_argument("--output_dir", type=str, default=None)
|
||||
parser.add_argument("--n_per_sex", type=int, default=10)
|
||||
parser.add_argument("--seed", type=int, default=2026)
|
||||
parser.add_argument("--top_dimensions", type=int, default=12)
|
||||
args = parser.parse_args()
|
||||
|
||||
input_csv = Path(args.input_csv)
|
||||
output_dir = Path(args.output_dir) if args.output_dir else input_csv.with_suffix("")
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
df = _load_bi_csv(input_csv)
|
||||
total_df = _aggregate_total(df)
|
||||
selected = _sample_patients(total_df, n_per_sex=int(args.n_per_sex), seed=int(args.seed))
|
||||
|
||||
for burden_type in sorted(df["burden_type"].dropna().unique().tolist()):
|
||||
burden_type = str(burden_type)
|
||||
_plot_selected_trajectories(
|
||||
total_df,
|
||||
burden_type=burden_type,
|
||||
selected=selected,
|
||||
output_dir=output_dir,
|
||||
)
|
||||
dims = _top_dimensions(df, burden_type=burden_type, top_n=int(args.top_dimensions))
|
||||
_plot_dimension_mean_panels(
|
||||
df,
|
||||
burden_type=burden_type,
|
||||
dimensions=dims,
|
||||
output_dir=output_dir,
|
||||
)
|
||||
|
||||
selected_rows = []
|
||||
for sex_label, patient_ids in selected.items():
|
||||
for pid in patient_ids.tolist():
|
||||
selected_rows.append({"sex": sex_label, "patient_id": int(pid)})
|
||||
pd.DataFrame(selected_rows).to_csv(output_dir / "sampled_patients_by_sex.csv", index=False)
|
||||
print(f"Input: {input_csv}")
|
||||
print(f"Output directory: {output_dir}")
|
||||
print(f"Sampled patients per sex: {int(args.n_per_sex)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
214
plot_deephealth_index_trajectories.py
Normal file
214
plot_deephealth_index_trajectories.py
Normal file
@@ -0,0 +1,214 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import matplotlib
|
||||
|
||||
matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
except ModuleNotFoundError as exc:
|
||||
raise ModuleNotFoundError(
|
||||
"plot_deephealth_index_trajectories.py requires matplotlib. "
|
||||
"Install it in the server environment before running this script."
|
||||
) from exc
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
|
||||
REQUIRED_COLUMNS = {
|
||||
"patient_id",
|
||||
"sex",
|
||||
"landmark_age",
|
||||
"index_type",
|
||||
"index_id",
|
||||
"index_label",
|
||||
"index_value",
|
||||
}
|
||||
|
||||
|
||||
def _sex_label(value: object) -> str:
|
||||
text = str(value).strip().lower()
|
||||
if text in {"0", "0.0", "female", "f", "woman"}:
|
||||
return "female"
|
||||
if text in {"1", "1.0", "male", "m", "man"}:
|
||||
return "male"
|
||||
return text or "unknown"
|
||||
|
||||
|
||||
def _load_index_csv(path: Path) -> pd.DataFrame:
|
||||
header = pd.read_csv(path, nrows=0)
|
||||
missing = sorted(REQUIRED_COLUMNS - set(header.columns))
|
||||
if missing:
|
||||
raise ValueError(f"{path} is missing required columns: {missing}")
|
||||
df = pd.read_csv(path, usecols=sorted(REQUIRED_COLUMNS))
|
||||
df["sex_label"] = df["sex"].map(_sex_label)
|
||||
df["landmark_age"] = pd.to_numeric(df["landmark_age"], errors="raise")
|
||||
df["index_value"] = pd.to_numeric(df["index_value"], errors="raise")
|
||||
return df
|
||||
|
||||
|
||||
def _sample_patients(df: pd.DataFrame, *, n_per_sex: int, seed: int) -> dict[str, np.ndarray]:
|
||||
rng = np.random.default_rng(int(seed))
|
||||
samples: dict[str, np.ndarray] = {}
|
||||
for sex_label in ["female", "male"]:
|
||||
ids = np.asarray(sorted(df.loc[df["sex_label"] == sex_label, "patient_id"].unique()))
|
||||
if ids.size == 0:
|
||||
samples[sex_label] = np.asarray([], dtype=np.int64)
|
||||
continue
|
||||
samples[sex_label] = np.asarray(
|
||||
rng.choice(ids, size=min(int(n_per_sex), int(ids.size)), replace=False)
|
||||
)
|
||||
return samples
|
||||
|
||||
|
||||
def _plot_sampled_trajectories(
|
||||
df: pd.DataFrame,
|
||||
*,
|
||||
index_type: str,
|
||||
selected: dict[str, np.ndarray],
|
||||
output_dir: Path,
|
||||
) -> None:
|
||||
sub = df[df["index_type"] == index_type].copy()
|
||||
if sub.empty:
|
||||
return
|
||||
if index_type == "organ_involvement":
|
||||
total = (
|
||||
sub.groupby(["patient_id", "sex_label", "landmark_age"], as_index=False)[
|
||||
"index_value"
|
||||
]
|
||||
.mean()
|
||||
.rename(columns={"index_value": "trajectory_value"})
|
||||
)
|
||||
title = "mean organ involvement"
|
||||
else:
|
||||
total = sub.rename(columns={"index_value": "trajectory_value"})
|
||||
title = "frailty risk"
|
||||
|
||||
mean_df = (
|
||||
total.groupby(["sex_label", "landmark_age"], as_index=False)["trajectory_value"]
|
||||
.mean()
|
||||
.sort_values("landmark_age")
|
||||
)
|
||||
|
||||
fig, ax = plt.subplots(figsize=(9.5, 5.5), dpi=160)
|
||||
colors = {"female": "#b83280", "male": "#2563eb"}
|
||||
for sex_label in ["female", "male"]:
|
||||
for pid in selected.get(sex_label, np.asarray([], dtype=np.int64)):
|
||||
one = total[total["patient_id"] == pid].sort_values("landmark_age")
|
||||
if one.empty:
|
||||
continue
|
||||
ax.plot(
|
||||
one["landmark_age"],
|
||||
one["trajectory_value"],
|
||||
color=colors.get(sex_label, "0.4"),
|
||||
alpha=0.22,
|
||||
linewidth=1.2,
|
||||
)
|
||||
mean_one = mean_df[mean_df["sex_label"] == sex_label]
|
||||
if not mean_one.empty:
|
||||
ax.plot(
|
||||
mean_one["landmark_age"],
|
||||
mean_one["trajectory_value"],
|
||||
color=colors.get(sex_label, "0.4"),
|
||||
linewidth=2.6,
|
||||
label=f"{sex_label} mean",
|
||||
)
|
||||
|
||||
ax.set_title(f"{index_type}: sampled trajectories and sex-specific means")
|
||||
ax.set_xlabel("Landmark age")
|
||||
ax.set_ylabel(title)
|
||||
ax.grid(True, alpha=0.25)
|
||||
ax.legend(frameon=False)
|
||||
fig.tight_layout()
|
||||
fig.savefig(output_dir / f"{index_type}_sampled_trajectories_by_sex.png")
|
||||
plt.close(fig)
|
||||
|
||||
|
||||
def _plot_top_dimensions(
|
||||
df: pd.DataFrame,
|
||||
*,
|
||||
output_dir: Path,
|
||||
top_n: int,
|
||||
) -> None:
|
||||
sub = df[df["index_type"] == "organ_involvement"].copy()
|
||||
if sub.empty:
|
||||
return
|
||||
order = (
|
||||
sub.groupby("index_id")["index_value"]
|
||||
.mean()
|
||||
.sort_values(ascending=False)
|
||||
.head(int(top_n))
|
||||
.index.tolist()
|
||||
)
|
||||
n = len(order)
|
||||
if n == 0:
|
||||
return
|
||||
ncols = min(3, n)
|
||||
nrows = int(np.ceil(n / ncols))
|
||||
fig, axes = plt.subplots(nrows, ncols, figsize=(4.0 * ncols, 3.0 * nrows), dpi=160)
|
||||
axes_arr = np.asarray(axes).reshape(-1)
|
||||
colors = {"female": "#b83280", "male": "#2563eb"}
|
||||
for ax, index_id in zip(axes_arr, order):
|
||||
one = sub[sub["index_id"] == index_id]
|
||||
mean_df = (
|
||||
one.groupby(["sex_label", "landmark_age"], as_index=False)["index_value"]
|
||||
.mean()
|
||||
.sort_values("landmark_age")
|
||||
)
|
||||
for sex_label in ["female", "male"]:
|
||||
m = mean_df[mean_df["sex_label"] == sex_label]
|
||||
if not m.empty:
|
||||
ax.plot(
|
||||
m["landmark_age"],
|
||||
m["index_value"],
|
||||
color=colors.get(sex_label, "0.4"),
|
||||
linewidth=1.8,
|
||||
label=sex_label,
|
||||
)
|
||||
ax.set_title(str(index_id), fontsize=9)
|
||||
ax.set_xlabel("Age")
|
||||
ax.set_ylabel("Organ involvement")
|
||||
ax.grid(True, alpha=0.22)
|
||||
for ax in axes_arr[n:]:
|
||||
ax.axis("off")
|
||||
handles, labels = axes_arr[0].get_legend_handles_labels()
|
||||
if handles:
|
||||
fig.legend(handles, labels, loc="upper right", frameon=False)
|
||||
fig.suptitle("organ_involvement: sex-specific mean trajectories for top dimensions")
|
||||
fig.tight_layout(rect=(0, 0, 0.98, 0.96))
|
||||
fig.savefig(output_dir / "organ_involvement_top_dimensions_by_sex.png")
|
||||
plt.close(fig)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Plot DeepHealth organ involvement and frailty risk trajectories."
|
||||
)
|
||||
parser.add_argument("--input_csv", type=str, required=True)
|
||||
parser.add_argument("--output_dir", type=str, default=None)
|
||||
parser.add_argument("--n_per_sex", type=int, default=10)
|
||||
parser.add_argument("--seed", type=int, default=2026)
|
||||
parser.add_argument("--top_n", type=int, default=12)
|
||||
args = parser.parse_args()
|
||||
|
||||
input_csv = Path(args.input_csv)
|
||||
output_dir = Path(args.output_dir) if args.output_dir else input_csv.parent
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
df = _load_index_csv(input_csv)
|
||||
selected = _sample_patients(df, n_per_sex=int(args.n_per_sex), seed=int(args.seed))
|
||||
for index_type in ["organ_involvement", "frailty_risk"]:
|
||||
_plot_sampled_trajectories(
|
||||
df,
|
||||
index_type=index_type,
|
||||
selected=selected,
|
||||
output_dir=output_dir,
|
||||
)
|
||||
_plot_top_dimensions(df, output_dir=output_dir, top_n=int(args.top_n))
|
||||
print(f"Input: {input_csv}")
|
||||
print(f"Output directory: {output_dir}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1257
uk_hfrs_label_mapping.csv
Normal file
1257
uk_hfrs_label_mapping.csv
Normal file
File diff suppressed because it is too large
Load Diff
53
uk_hfrs_missing_label_codes.csv
Normal file
53
uk_hfrs_missing_label_codes.csv
Normal file
@@ -0,0 +1,53 @@
|
||||
hfrs_source_code,hfrs_weight,missing_reason,hfrs_source
|
||||
R00,0.7,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R02,1.0,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R11,0.3,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R13,0.8,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R26,2.6,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R29,3.6,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R31,3.0,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R32,1.2,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R33,1.3,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R40,2.5,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R41,2.7,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R44,1.6,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R45,1.2,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R47,1.0,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R50,0.1,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R54,2.2,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R55,1.8,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R56,2.6,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R63,0.9,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R69,1.3,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R79,0.6,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
R94,1.4,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
S00,3.2,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
S01,1.1,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
S06,2.4,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
S09,1.2,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
S22,1.8,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
S32,1.4,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
S42,2.3,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
S51,0.5,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
S72,1.4,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
S80,2.0,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
T83,2.4,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
U80,0.8,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
W01,0.9,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
W06,1.1,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
W10,0.9,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
W18,2.1,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
W19,3.2,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
X59,1.5,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
Y84,0.7,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
Y95,1.2,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
Z22,1.7,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
Z50,2.1,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
Z60,1.8,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
Z73,0.6,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
Z74,1.1,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
Z75,2.0,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
Z87,1.5,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
Z91,0.5,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
Z93,1.0,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
Z99,0.8,not_present_in_labels_csv,Gilbert et al. Lancet 2018 supplementary appendix Table A2
|
||||
|
Reference in New Issue
Block a user