Mykes commited on
Commit
b5f54c4
·
verified ·
1 Parent(s): 35ff942

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +259 -77
app.py CHANGED
@@ -3,21 +3,85 @@ import pandas as pd
3
  import numpy as np
4
  import pickle
5
  import json
 
 
6
 
7
- # Загрузка сохраненной модели и других необходимых объектов
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  @st.cache_resource
9
  def load_model():
10
  with open('model.pkl', 'rb') as file:
11
  model = pickle.load(file)
12
-
13
  with open('scaler.pkl', 'rb') as file:
14
  scaler = pickle.load(file)
15
-
16
  with open('data.json', 'r', encoding='utf-8') as f:
17
  data = json.load(f)
18
-
19
  return model, scaler, data
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  model, scaler, data = load_model()
22
  feature_list = data['features']
23
  categorical_features = data['categorical_features']
@@ -27,91 +91,209 @@ group_names = data['group_names']
27
  numeric_defaults = data['numeric_defaults']
28
  categorical_defaults = data['categorical_defaults']
29
 
 
30
  st.title('Классификатор пациентов')
31
 
32
- # Создание формы ввода для всех необходимых признаков
33
- def get_user_input():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  input_data = {}
35
 
36
- # Числовые признаки
37
- st.subheader('Числовые параметры')
38
- for feature in feature_list:
39
- if feature in numeric_features:
40
- default_value = float(numeric_defaults[feature])
41
- min_val = default_value - abs(default_value)
42
- max_val = default_value + abs(default_value)
43
- input_data[feature] = st.number_input(
44
- f'{feature}',
45
- value=default_value,
46
- min_value=min_val,
47
- max_value=max_val,
48
- help=f"Среднее значение: {default_value:.2f}"
49
- )
 
 
 
 
 
 
 
 
 
 
50
 
51
- # Категориальные признаки
52
- st.subheader('Категориальные параметры')
53
- for feature in categorical_features:
54
- options = categorical_options[feature]
55
- default_idx = options.index(categorical_defaults[feature]) if categorical_defaults[feature] in options else 0
56
- input_data[feature] = st.selectbox(
57
- f'{feature}',
58
- options,
59
- index=default_idx,
60
- help=f"Наиболее частое значение: {categorical_defaults[feature]}"
61
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
- return input_data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
- # Добавим описание
66
- st.markdown("""
67
- ## Описание
68
- Это приложение помогает классифицировать пациентов по группам на основе введенных параметров.
69
 
70
- ### Инструкция:
71
- 1. Заполните все поля формы (установлены средние значения по умолчанию)
72
- 2. Нажмите кнопку "Выполнить классификацию"
73
- 3. Получите результат с вероятностями принадлежности к каждой группе
74
- """)
75
-
76
- # Получение данных от пользователя
77
- user_input = get_user_input()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
- # Кнопка для выполнения предсказания
80
- if st.button('Выполнить классификацию'):
81
- # Преобразование входных данных
82
- input_df = pd.DataFrame([user_input])
83
 
84
- # One-hot encoding для категориальных признаков
85
- input_df_encoded = pd.get_dummies(input_df, columns=categorical_features)
 
 
 
86
 
87
- # Масштабирование числовых признаков
88
- if numeric_features:
89
- input_df_encoded[numeric_features] = scaler.transform(input_df_encoded[numeric_features])
 
 
 
90
 
91
- # Убедитесь, что все необходимые столбцы присутствуют
92
- for col in feature_list:
93
- if col not in input_df_encoded.columns:
94
- input_df_encoded[col] = 0
 
 
95
 
96
- # Получение предсказания
97
- X_pred = input_df_encoded[feature_list]
98
- prediction = model.predict(X_pred)
99
- probabilities = model.predict_proba(X_pred)[0]
100
 
101
- # Отображение результата
102
- st.success(f'Предсказанная группа: {group_names[str(prediction[0])]}')
103
-
104
- # Вывод вероятностей
105
- st.write('Вероятности для каждой группы:')
106
- for i, prob in enumerate(probabilities):
107
- st.write(f'{group_names[str(i)]}: {prob:.2f}')
108
-
109
- # Добавим вывод введенных данных для проверки
110
- st.write("\nВведенные данные:")
111
- st.write(input_df)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
- # Добавим информацию о модели
114
- with st.expander("Информация о модели"):
115
- st.write(f"Количество признаков: {len(feature_list)}")
116
- st.write(f"Числовые признаки: {len(numeric_features)}")
117
- st.write(f"Категориальные признаки: {len(categorical_features)}")
 
 
 
3
  import numpy as np
4
  import pickle
5
  import json
6
+ import plotly.graph_objects as go
7
+ import plotly.express as px
8
 
9
+ # Настройка страницы
10
+ st.set_page_config(
11
+ page_title="Классификатор пациентов",
12
+ layout="wide",
13
+ initial_sidebar_state="expanded",
14
+ menu_items={
15
+ 'About': "Классификатор пациентов для определения группы лечения"
16
+ }
17
+ )
18
+
19
+ # Применяем кастомный CSS
20
+ st.markdown("""
21
+ <style>
22
+ .stNumberInput input {
23
+ width: 150px;
24
+ }
25
+ .stSelectbox select {
26
+ width: 150px;
27
+ }
28
+ .main .block-container {
29
+ padding-top: 2rem;
30
+ padding-bottom: 2rem;
31
+ }
32
+ div[data-testid="stSidebarNav"] {
33
+ padding-top: 0rem;
34
+ }
35
+ .sidebar .sidebar-content {
36
+ width: 300px;
37
+ }
38
+ .metric-card {
39
+ background-color: #f0f2f6;
40
+ border-radius: 0.5rem;
41
+ padding: 1rem;
42
+ margin: 0.5rem 0;
43
+ }
44
+ .small-font {
45
+ font-size: 0.8rem;
46
+ }
47
+ </style>
48
+ """, unsafe_allow_html=True)
49
+
50
+ # Загрузка модели и данных
51
  @st.cache_resource
52
  def load_model():
53
  with open('model.pkl', 'rb') as file:
54
  model = pickle.load(file)
 
55
  with open('scaler.pkl', 'rb') as file:
56
  scaler = pickle.load(file)
 
57
  with open('data.json', 'r', encoding='utf-8') as f:
58
  data = json.load(f)
 
59
  return model, scaler, data
60
 
61
+ def create_gauge_chart(value, title):
62
+ fig = go.Figure(go.Indicator(
63
+ mode = "gauge+number",
64
+ value = value * 100,
65
+ domain = {'x': [0, 1], 'y': [0, 1]},
66
+ title = {'text': title},
67
+ gauge = {
68
+ 'axis': {'range': [None, 100]},
69
+ 'bar': {'color': "darkblue"},
70
+ 'steps': [
71
+ {'range': [0, 33], 'color': "lightgray"},
72
+ {'range': [33, 66], 'color': "gray"},
73
+ {'range': [66, 100], 'color': "darkgray"}
74
+ ],
75
+ 'threshold': {
76
+ 'line': {'color': "red", 'width': 4},
77
+ 'thickness': 0.75,
78
+ 'value': value * 100
79
+ }
80
+ }
81
+ ))
82
+ fig.update_layout(height=200)
83
+ return fig
84
+
85
  model, scaler, data = load_model()
86
  feature_list = data['features']
87
  categorical_features = data['categorical_features']
 
91
  numeric_defaults = data['numeric_defaults']
92
  categorical_defaults = data['categorical_defaults']
93
 
94
+ # Основной заголовок
95
  st.title('Классификатор пациентов')
96
 
97
+ # Описание в основной части
98
+ with st.container():
99
+ st.markdown("""
100
+ ### О системе
101
+ Данная система помогает классифицировать пациентов по группам на основе введенных параметров.
102
+
103
+ #### Как использовать:
104
+ 1. Заполните все поля в форме слева
105
+ 2. Нажмите кнопку "Выполнить классификацию"
106
+ 3. Получите результат с вероятностями принадлежности к каждой группе
107
+
108
+ #### Группы классификации:
109
+ - Контрольная группа
110
+ - Группа топирамата
111
+ - Группа леветирацетама
112
+ """)
113
+
114
+ # Боковая панель для ввода данных
115
+ with st.sidebar:
116
+ st.header('Ввод данных')
117
+
118
+ # Создаем вкладки для разных типов параметров
119
+ tab1, tab2 = st.tabs(["📊 Числовые", "📋 Категориальные"])
120
+
121
  input_data = {}
122
 
123
+ with tab1:
124
+ # Числовые признаки
125
+ for i in range(0, len(numeric_features), 2):
126
+ col1, col2 = st.columns(2)
127
+ with col1:
128
+ if i < len(numeric_features):
129
+ feature = numeric_features[i]
130
+ default_value = float(numeric_defaults[feature])
131
+ input_data[feature] = st.number_input(
132
+ f'{feature}',
133
+ value=default_value,
134
+ format="%.2f",
135
+ help=f"Среднее: {default_value:.2f}"
136
+ )
137
+ with col2:
138
+ if i + 1 < len(numeric_features):
139
+ feature = numeric_features[i + 1]
140
+ default_value = float(numeric_defaults[feature])
141
+ input_data[feature] = st.number_input(
142
+ f'{feature}',
143
+ value=default_value,
144
+ format="%.2f",
145
+ help=f"Среднее: {default_value:.2f}"
146
+ )
147
 
148
+ with tab2:
149
+ # Категориальные признаки
150
+ for i in range(0, len(categorical_features), 2):
151
+ col1, col2 = st.columns(2)
152
+ with col1:
153
+ if i < len(categorical_features):
154
+ feature = categorical_features[i]
155
+ options = categorical_options[feature]
156
+ default_idx = options.index(categorical_defaults[feature]) if categorical_defaults[feature] in options else 0
157
+ input_data[feature] = st.selectbox(
158
+ f'{feature}',
159
+ options,
160
+ index=default_idx,
161
+ help=f"Типичное: {categorical_defaults[feature]}"
162
+ )
163
+ with col2:
164
+ if i + 1 < len(categorical_features):
165
+ feature = categorical_features[i + 1]
166
+ options = categorical_options[feature]
167
+ default_idx = options.index(categorical_defaults[feature]) if categorical_defaults[feature] in options else 0
168
+ input_data[feature] = st.selectbox(
169
+ f'{feature}',
170
+ options,
171
+ index=default_idx,
172
+ help=f"Типичное: {categorical_defaults[feature]}"
173
+ )
174
 
175
+ # Кнопка классификации
176
+ if st.button('Выполнить классификацию', use_container_width=True):
177
+ with st.spinner('Выполняется классификация...'):
178
+ # Преобразование входных данных
179
+ input_df = pd.DataFrame([input_data])
180
+
181
+ # One-hot encoding для категориальных признаков
182
+ input_df_encoded = pd.get_dummies(input_df, columns=categorical_features)
183
+
184
+ # Масштабирование числовых признаков
185
+ if numeric_features:
186
+ input_df_encoded[numeric_features] = scaler.transform(input_df_encoded[numeric_features])
187
+
188
+ # Убедитесь, что все необходимые столбцы присутствуют
189
+ for col in feature_list:
190
+ if col not in input_df_encoded.columns:
191
+ input_df_encoded[col] = 0
192
+
193
+ X_pred = input_df_encoded[feature_list]
194
+ prediction = model.predict(X_pred)
195
+ probabilities = model.predict_proba(X_pred)[0]
196
+
197
+ # Сохраняем результаты в session state
198
+ st.session_state['prediction'] = prediction[0]
199
+ st.session_state['probabilities'] = probabilities
200
+ st.session_state['input_data'] = input_df
201
 
202
+ # Отображение результатов в основной части
203
+ if 'prediction' in st.session_state:
204
+ st.header('Результаты классификации')
 
205
 
206
+ # Создаем контейнер для основных метрик
207
+ with st.container():
208
+ col1, col2, col3 = st.columns(3)
209
+
210
+ with col1:
211
+ st.markdown("""
212
+ <div class="metric-card">
213
+ <h3>Предсказанная группа</h3>
214
+ <h2 style="color: darkblue;">{}</h2>
215
+ </div>
216
+ """.format(group_names[str(st.session_state['prediction'])]), unsafe_allow_html=True)
217
+
218
+ with col2:
219
+ max_prob = max(st.session_state['probabilities'])
220
+ st.markdown("""
221
+ <div class="metric-card">
222
+ <h3>Уверенность модели</h3>
223
+ <h2 style="color: darkblue;">{:.1%}</h2>
224
+ </div>
225
+ """.format(max_prob), unsafe_allow_html=True)
226
+
227
+ with col3:
228
+ second_best_prob = sorted(st.session_state['probabilities'])[-2]
229
+ st.markdown("""
230
+ <div class="metric-card">
231
+ <h3>Вторая вероятная группа</h3>
232
+ <h2 style="color: darkblue;">{:.1%}</h2>
233
+ </div>
234
+ """.format(second_best_prob), unsafe_allow_html=True)
235
 
236
+ # Визуализация вероятностей
237
+ st.subheader('Распределение вероятностей по группам')
 
 
238
 
239
+ # График вероятностей
240
+ prob_df = pd.DataFrame({
241
+ 'Группа': [group_names[str(i)] for i in range(len(group_names))],
242
+ 'Вероятность': st.session_state['probabilities']
243
+ })
244
 
245
+ fig = px.bar(prob_df,
246
+ x='Группа',
247
+ y='Вероятность',
248
+ color='Вероятность',
249
+ color_continuous_scale='Blues',
250
+ text=prob_df['Вероятность'].apply(lambda x: f'{x:.1%}'))
251
 
252
+ fig.update_layout(
253
+ height=400,
254
+ yaxis_range=[0, 1],
255
+ yaxis_tickformat='.0%',
256
+ showlegend=False
257
+ )
258
 
259
+ st.plotly_chart(fig, use_container_width=True)
 
 
 
260
 
261
+ # Детальная информация
262
+ with st.expander("Детальная информация"):
263
+ tab1, tab2 = st.tabs(["📊 Введенные данные", "ℹ️ Пояснение"])
264
+
265
+ with tab1:
266
+ # Отображаем введенные данные в виде двух таблиц
267
+ col1, col2 = st.columns(2)
268
+
269
+ with col1:
270
+ st.subheader("Числовые параметры")
271
+ numeric_data = st.session_state['input_data'][numeric_features]
272
+ st.dataframe(numeric_data.T.style.format("{:.2f}"))
273
+
274
+ with col2:
275
+ st.subheader("Категориальные параметры")
276
+ categorical_data = st.session_state['input_data'][categorical_features]
277
+ st.dataframe(categorical_data.T)
278
+
279
+ with tab2:
280
+ st.markdown("""
281
+ ### Как интерпретировать результаты:
282
+
283
+ - **Предсказанная группа** - основная рекомендованная группа для пациента
284
+ - **Уверенность модели** - вероятность принадлежности к предсказанной группе
285
+ - **Вторая вероятная группа** - вероятность принадлежности ко второй наиболее вероятной группе
286
+
287
+ ### Примечания:
288
+ - Чем выше уверенность модели, тем надежнее предсказание
289
+ - При уверенности ниже 50% рекомендуется дополнительное обследование
290
+ - Результаты модели носят рекомендательный характер
291
+ """)
292
 
293
+ # Добавляем footer
294
+ st.markdown("""
295
+ ---
296
+ <div class="small-font">
297
+ © 2023 Классификатор пациентов | Версия 1.0
298
+ </div>
299
+ """, unsafe_allow_html=True)