Spaces:
Sleeping
Sleeping
Upload 2 files
Browse files- app.py +223 -0
- saved_model/model1.pkl +3 -0
app.py
ADDED
@@ -0,0 +1,223 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import joblib
|
2 |
+
import pandas as pd
|
3 |
+
import streamlit as st
|
4 |
+
from streamlit_shap import st_shap
|
5 |
+
import shap
|
6 |
+
import numpy as np
|
7 |
+
|
8 |
+
# Load Model
|
9 |
+
model1 = joblib.load('saved_model/model1.pkl')
|
10 |
+
predictor = model1
|
11 |
+
st.title('Prediction of postoperative delirium')
|
12 |
+
st.write('#### For geriatric patients undergoing cardiac surgery')
|
13 |
+
|
14 |
+
asa_options = {
|
15 |
+
"Ⅰ": -1.38814621350096,
|
16 |
+
"Ⅱ": 0.511717257330668,
|
17 |
+
"Ⅲ": -0.395963387679586,
|
18 |
+
"Ⅳ": -1.4681889211745,
|
19 |
+
"Ⅴ": -1.4681889211745
|
20 |
+
}
|
21 |
+
hypertension_options = {
|
22 |
+
"No": 3.68035036162672,
|
23 |
+
"Ⅰ": -0.544235316554776,
|
24 |
+
"Ⅱ": -0.844034612101507,
|
25 |
+
"Ⅲ": -0.943664453050348
|
26 |
+
}
|
27 |
+
dm_options = {
|
28 |
+
"No": 0.122040527036218,
|
29 |
+
"Non-insulin dependent": -0.638909566289975,
|
30 |
+
"Insulin dependent": -1.7072632945609
|
31 |
+
}
|
32 |
+
illness_options = {
|
33 |
+
"Yes": 1,
|
34 |
+
"No": 0
|
35 |
+
}
|
36 |
+
os_options = {
|
37 |
+
"": 2.70805020110221,
|
38 |
+
"Dermatological surgery": 2.22692108269007,
|
39 |
+
"Limb surgery": 0.752566153571913,
|
40 |
+
"Arthroplasty": 0.532164318353033,
|
41 |
+
"Spinal surgery": 1.6127011607198,
|
42 |
+
"Head and neck surgery": 2.52541407124607,
|
43 |
+
"Upper abdomen surgery": -0.649878597660549,
|
44 |
+
"Lower abdomen surgery": -0.464370149938076,
|
45 |
+
"Abdomen surgery": -2.20389571615324,
|
46 |
+
"Thoracic surgery": 0.416954872664665,
|
47 |
+
"cranial surgery": 0.0899556968720493,
|
48 |
+
"Thoracoabdominal surgery": 0.0899556968720493,
|
49 |
+
"Vascular surgery": 0.281010933634758
|
50 |
+
}
|
51 |
+
es_options = {
|
52 |
+
"No": 0.0175056050012399,
|
53 |
+
"yes": -1.97901454494049
|
54 |
+
}
|
55 |
+
eot_options = {
|
56 |
+
"": 2.944439,
|
57 |
+
"1h": 0.768487407184522,
|
58 |
+
"1h-1.5h": 0.523271451886264,
|
59 |
+
"1.5-2h": -0.170387892577323,
|
60 |
+
"2h-3h": -0.345346138774783,
|
61 |
+
">=3h": -0.749296055496119
|
62 |
+
}
|
63 |
+
up_options = {
|
64 |
+
"": 3.59497984361465,
|
65 |
+
"No": 0.0374632790768398,
|
66 |
+
"+/-": -0.465955759499621,
|
67 |
+
"1+": -1.18050684872272,
|
68 |
+
"2+": -1.18050684872272,
|
69 |
+
"3+": -1.4681889211745
|
70 |
+
}
|
71 |
+
|
72 |
+
sccl_zh = '血清胱抑素C测定'
|
73 |
+
asa_zh = 'ASA分级'
|
74 |
+
hypertension_zh = '高血压_分级'
|
75 |
+
dm_zh = '糖尿病_控制方式'
|
76 |
+
os_zh = '手术风险评估_手术部位'
|
77 |
+
es_zh = '急诊'
|
78 |
+
eot_zh = '手术时长_分钟'
|
79 |
+
up_zh = '尿蛋白定性'
|
80 |
+
coovorbcdw_zh = 'RBC分布宽度CV'
|
81 |
+
inr_zh = '国际标准化比值'
|
82 |
+
|
83 |
+
sccl_en = 'Serum cystatin C level (mg/L)'
|
84 |
+
asa_en = 'ASA classification'
|
85 |
+
hypertension_en = 'Hypertension'
|
86 |
+
dm_en = 'Diabetes mellitus'
|
87 |
+
os_en = 'Operation site'
|
88 |
+
es_en = 'Emergency surgery'
|
89 |
+
eot_en = 'Estimated operation time'
|
90 |
+
up_en = 'Urine protein'
|
91 |
+
coovorbcdw_en = 'RDW-CV (%)'
|
92 |
+
inr_en = 'International normalized ratio'
|
93 |
+
|
94 |
+
# Form
|
95 |
+
with st.form(key='form_parameters'):
|
96 |
+
col1, col2 = st.columns(2) # Create two columns
|
97 |
+
|
98 |
+
# First column
|
99 |
+
with col1:
|
100 |
+
sccl = st.number_input('Serum cystatin C level (mg/L)')
|
101 |
+
asa = st.selectbox('ASA classification', list(asa_options.keys()))
|
102 |
+
asa_woe = asa_options.get(asa, 0)
|
103 |
+
hypertension = st.selectbox('Hypertension', list(hypertension_options.keys()))
|
104 |
+
hypertension_woe = hypertension_options.get(hypertension, 0)
|
105 |
+
dm = st.selectbox('Diabetes mellitus', list(dm_options.keys()))
|
106 |
+
dm_woe = dm_options.get(dm, 0)
|
107 |
+
os = st.selectbox('Operation site', list(os_options.keys()))
|
108 |
+
os_woe = os_options.get(os, 0)
|
109 |
+
es = st.selectbox('Emergency surgery', list(es_options.keys()))
|
110 |
+
es_woe = es_options.get(es, 0)
|
111 |
+
|
112 |
+
sccl_woe = 0
|
113 |
+
if sccl == '':
|
114 |
+
sccl_woe = 2.99885240089024
|
115 |
+
sccl = np.nan
|
116 |
+
elif float(sccl) < 0.87:
|
117 |
+
sccl_woe = 0.645372775418255
|
118 |
+
elif (float(sccl) >= 0.87) and (float(sccl) < 0.95):
|
119 |
+
sccl_woe = 0.369025188040581
|
120 |
+
elif (float(sccl) >= 0.95) and (float(sccl) < 1.03):
|
121 |
+
sccl_woe = -0.10610555179212
|
122 |
+
elif (float(sccl) >= 1.03) and (float(sccl) < 1.13):
|
123 |
+
sccl_woe = 0.0898098195273885
|
124 |
+
elif float(sccl) >= 1.13:
|
125 |
+
sccl_woe = -0.925496780781878
|
126 |
+
sccl = float(sccl)
|
127 |
+
|
128 |
+
|
129 |
+
# Second column
|
130 |
+
with col2:
|
131 |
+
eot = st.selectbox('Estimated operation time', list(eot_options.keys()))
|
132 |
+
eot_woe = eot_options.get(eot, 0)
|
133 |
+
up = st.selectbox('Urine protein', list(up_options.keys()))
|
134 |
+
up_woe = up_options.get(up, 0)
|
135 |
+
coovorbcdw = st.number_input('RDW-CV (%)')
|
136 |
+
inr = st.number_input('International normalized ratio')
|
137 |
+
|
138 |
+
coovorbcdw_woe = 0
|
139 |
+
if coovorbcdw == '':
|
140 |
+
coovorbcdw_woe = 3.34041249059303
|
141 |
+
coovorbcdw = np.nan
|
142 |
+
elif float(coovorbcdw) < 12.7:
|
143 |
+
coovorbcdw_woe = 0.398231895412054
|
144 |
+
elif (float(coovorbcdw) >= 12.7) and (float(coovorbcdw) < 13.3):
|
145 |
+
coovorbcdw_woe = 0.048813472291148
|
146 |
+
elif (float(coovorbcdw) >= 13.3) and (float(coovorbcdw) < 13.7):
|
147 |
+
coovorbcdw_woe = -0.104034700025362
|
148 |
+
elif (float(coovorbcdw) >= 13.7) and (float(coovorbcdw) < 14.6):
|
149 |
+
coovorbcdw_woe = -0.0861214293356946
|
150 |
+
elif float(coovorbcdw) >= 14.6:
|
151 |
+
coovorbcdw_woe = -0.646032944021757
|
152 |
+
coovorbcdw = float(coovorbcdw)
|
153 |
+
|
154 |
+
inr_woe = 0
|
155 |
+
if inr == '':
|
156 |
+
inr_woe = 3.38627173144548
|
157 |
+
inr = np.nan
|
158 |
+
elif float(inr) < 0.92:
|
159 |
+
inr_woe = -0.000131790754127941
|
160 |
+
elif (float(inr) >= 0.92) and (float(inr) < 0.95):
|
161 |
+
inr_woe = 0.383156538484155
|
162 |
+
elif (float(inr) >= 0.95) and (float(inr) < 0.98):
|
163 |
+
inr_woe = 0.282044225138759
|
164 |
+
elif (float(inr) >= 0.98) and (float(inr) < 1.03):
|
165 |
+
inr_woe = -0.104889279197154
|
166 |
+
elif float(inr) >= 1.03:
|
167 |
+
inr_woe = -0.769604383885953
|
168 |
+
inr = float(inr)
|
169 |
+
|
170 |
+
st.markdown('---')
|
171 |
+
submitted = st.form_submit_button('Predict')
|
172 |
+
|
173 |
+
# 构建预测样本(原始数据)
|
174 |
+
data1 = {
|
175 |
+
hypertension_zh: hypertension,
|
176 |
+
up_zh: up,
|
177 |
+
dm_zh: dm,
|
178 |
+
os_zh: os,
|
179 |
+
asa_zh: asa,
|
180 |
+
eot_zh: eot,
|
181 |
+
sccl_zh: sccl,
|
182 |
+
coovorbcdw_zh: coovorbcdw,
|
183 |
+
inr_zh: inr,
|
184 |
+
es_zh: es
|
185 |
+
}
|
186 |
+
X_train_1 = pd.DataFrame(data1, index=[0])
|
187 |
+
|
188 |
+
data2 = {
|
189 |
+
hypertension_zh: hypertension_woe,
|
190 |
+
up_zh: up_woe,
|
191 |
+
dm_zh: dm_woe,
|
192 |
+
os_zh: os_woe,
|
193 |
+
asa_zh: asa_woe,
|
194 |
+
eot_zh: eot_woe,
|
195 |
+
sccl_zh: sccl_woe,
|
196 |
+
coovorbcdw_zh: coovorbcdw_woe,
|
197 |
+
inr_zh: inr_woe,
|
198 |
+
es_zh: es_woe
|
199 |
+
}
|
200 |
+
X_train = pd.DataFrame(data2, index=[0])
|
201 |
+
|
202 |
+
if submitted:
|
203 |
+
# Predict
|
204 |
+
y_prob_train = model1.predict_proba(X_train)
|
205 |
+
|
206 |
+
value = y_prob_train[0][0]
|
207 |
+
with st.container():
|
208 |
+
st.write('### The possibility of xx is \n'+ str(value))
|
209 |
+
st.write('*Threshold is xx*')
|
210 |
+
st.markdown('---')
|
211 |
+
with st.container():
|
212 |
+
st.write('## SHAP force plot for this patient')
|
213 |
+
|
214 |
+
explainer = shap.TreeExplainer(model1)
|
215 |
+
shap_values = explainer.shap_values(X_train) # 这里的X_train替换成输进来的值,要woe版的数据,不是原始版数据,有个对应文件用来映射数值与woe
|
216 |
+
print(shap_values.shape)
|
217 |
+
X1_ = X_train_1.fillna(0) # 这里替换成输进来的值的原始数据
|
218 |
+
# 替换英文名
|
219 |
+
X1_.columns = [hypertension_en, up_en, dm_en, os_en, asa_en, eot_en, sccl_en, coovorbcdw_en, inr_en, es_en]
|
220 |
+
|
221 |
+
# Visualize SHAP values
|
222 |
+
# Visualize SHAP values
|
223 |
+
st_shap(shap.force_plot(explainer.expected_value, shap_values[0], X1_.iloc[0]), height=400, width=1000)
|
saved_model/model1.pkl
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:ddc52af2cc3e719e73b40648f9022163329649d9d32131ac2c6ec299a78f802a
|
3 |
+
size 72508
|