Spaces:
Sleeping
Sleeping
File size: 3,825 Bytes
7787c15 f666f82 7787c15 f666f82 f570757 7787c15 f570757 f666f82 7787c15 f666f82 7787c15 f666f82 7787c15 f570757 7787c15 e61da8d 7787c15 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | """DM ๊ฐ์ธ๋ณ ์ํ์์ธ - local SHAP.
LLM_Report/utils/dm_risk.py์ ๊ณ์ฐ ๋ก์ง์ ๊ฐ๋ค(5-fold ์ฒดํฌํฌ์ธํธ ๊ฐ๊ฐ์
๋ํด KernelExplainer๋ก local SHAP์ ๊ตฌํ๊ณ ํ๊ท - ์ฌํ์ต ์์). ๋ค๋ฅธ ์ ์
๋ฐฐ๊ฒฝํ๋ณธ์ ์๋ณธ ๋ฐ์ดํฐ์์ ์ค์๊ฐ์ผ๋ก kmeans ์์ฝํ์ง ์๊ณ
WEB/scripts/precompute_artifacts.py๊ฐ ๋ฏธ๋ฆฌ ๋ง๋ค์ด๋ dm_shap_background.csv
(kmeans ํฉ์ฑ ๋ํ์ 100๊ฐ, ์ค์ ๊ฐ์ธ ๋ ์ฝ๋ ์๋)๋ฅผ ๊ทธ๋๋ก ์ด๋ค๋ ๊ฒ -
์๋ณธ ๋ฐ์ดํฐ๋ฅผ Space์ ์ ์ฌ๋ฆฌ๊ธฐ ์ํจ์ด์, ๋งค ์์ฒญ๋ง๋ค kmeans๋ฅผ ๋ค์ ์
๋๋ ค๋ ๋๋ฏ๋ก ๋ ๋น ๋ฅด๋ค(๋ฌด๋ฃ CPU์์ ํนํ ์ค์).
์ฒดํฌํฌ์ธํธ๋ PRS_DM์ ๋ฃ์ด ํ์ตํ ๋ชจ๋ธ(ML/checkpoints/dm_prs)์ด๋ค. prs_value
(z ์ ์)๋ฅผ ์ฃผ๋ฉด PRS๋ฅผ mask=1๋ก ๋ฃ๊ณ PRS_DM๋ ํ๋์ SHAP feature๋ก ์ค๋ช
ํ๋ค.
None์ด๋ฉด PRS๋ฅผ [MASK]๋ก ๋๊ณ EHR feature๋ง ์ค๋ช
ํ๋ค(ํ์ต ๋ --prs-dropout์ผ๋ก
[MASK]๋ ํ์ต๋ผ ์์ด EHR๋ง์ผ๋ก ์์ธก ๊ฐ๋ฅ).
"""
from pathlib import Path
import numpy as np
import pandas as pd
import shap
import torch
from models.mlp import MultimodalModel
from utils.shap_utils import build_predict_fn
def compute_dm_local_shap(
patient_row: dict,
features: list,
background_df: pd.DataFrame,
checkpoint_dir: str = "artifacts/checkpoints",
n_folds: int = 5,
prs_dim: int = 1,
device: str = "cpu",
top_k: int = 8,
prs_value: float = None,
prs_feature: str = "PRS_DM",
exclude_features: tuple = (),
) -> tuple:
"""๋ฐํ: (importance_df(top_k, feature/patient_value/local_shap/direction),
ensemble_predicted_prob). 5๊ฐ fold ์ฒดํฌํฌ์ธํธ ๊ฐ๊ฐ์ผ๋ก ์ด ํ ์ฌ๋์ local
SHAP์ ๊ตฌํ๊ณ feature๋ณ ํ๊ท ์ ์ต์ข
๊ฐ์ผ๋ก ์ด๋ค(์์ธก ํ๋ฅ ๋ 5๊ฐ ๋ชจ๋ธ ํ๊ท ).
exclude_features: ์์ธก์๋ ๊ทธ๋๋ก ์ฐ๋ ์ค๋ช
ํ์์๋ง ๋บ feature - ์ฌ์ฉ์๊ฐ
์
๋ ฅํ์ง ์์ ์ธ๊ตฌ ์ค๊ฐ๊ฐ์ผ๋ก ์ฑ์ด ํญ๋ชฉ์ ์ค๊ฐ๊ฐ์ด SHAP ๋ฐฐ๊ฒฝ ํ๊ท ๊ณผ ๋ฌ๋ผ
(์: ALT ์ค๊ฐ๊ฐ 19 vs ํ๊ท 22.7) ์
๋ ฅํ์ง๋ ์์ ๊ฐ์ ๊ธฐ์ฌ๋๊ฐ ์๊ธฐ๋ฏ๋ก ๋บ๋ค."""
prs_in_input = prs_value is not None
ehr_features = list(features)
patient_row = dict(patient_row)
if prs_in_input:
features = ehr_features + [prs_feature]
patient_row[prs_feature] = float(prs_value)
patient_vec = np.array([[patient_row[f] for f in features]], dtype=np.float32)
background = background_df[features].to_numpy(dtype=np.float32)
shap_values_per_fold, probs = [], []
for fold_id in range(n_folds):
checkpoint_path = Path(checkpoint_dir) / f"dm_fold{fold_id}.pt"
model = MultimodalModel(ehr_dim=len(ehr_features), prs_dim=prs_dim).to(device)
model.load_state_dict(torch.load(checkpoint_path, map_location=device))
model.eval()
predict_fn = build_predict_fn(
model, prs_dim=max(prs_dim, 1), device=device, apply_sigmoid=True, prs_in_input=prs_in_input
)
explainer = shap.KernelExplainer(predict_fn, background)
sv = np.asarray(explainer.shap_values(patient_vec)).reshape(1, len(features))
shap_values_per_fold.append(sv[0])
probs.append(float(predict_fn(patient_vec)[0]))
mean_shap = np.mean(shap_values_per_fold, axis=0)
ensemble_prob = float(np.mean(probs))
df = pd.DataFrame(
{"feature": features, "patient_value": [patient_row[f] for f in features], "local_shap": mean_shap}
)
df = df[~df["feature"].isin(exclude_features)]
df = df.assign(_abs=df["local_shap"].abs()).sort_values("_abs", ascending=False).drop(columns="_abs")
df = df.head(top_k).reset_index(drop=True)
df["direction"] = df["local_shap"].apply(lambda x: "๋น๋จ๋ณ ์ํ ์ฆ๊ฐ" if x > 0 else "๋น๋จ๋ณ ์ํ ๊ฐ์")
return df, ensemble_prob
|