import gradio as gr import shap import matplotlib.pyplot as plt import pandas as pd import numpy as np import io import joblib import os # Установка бэкенда matplotlib plt.switch_backend('Agg') # Загрузка моделей model_dir = './models' xgb_reg_model = joblib.load(os.path.join(model_dir, 'xgb_reg_model.joblib')) xgb_clf_model = joblib.load(os.path.join(model_dir, 'xgb_clf_model.joblib')) umap_reducer = joblib.load(os.path.join(model_dir, 'umap_reducer.joblib')) hdbscan_clusterer = joblib.load(os.path.join(model_dir, 'hdbscan_clusterer.joblib')) # Определение колонок (ВАЖНО: должны совпадать с обучением) feature_columns = [ 'RIDAGEYR', 'RIAGENDR', 'BMXBMI', 'BMXWAIST', 'BPXSY1', 'BPXDI1', 'LBXGH', 'LBXHSCRP', 'LBDTCSI', 'LBDHDD', 'LBXIN', 'SLQ050', 'HSQ510', 'PHQ9_score', 'LBXBPB', 'LBXBCD', 'LBXTHG', 'URXMHH' ] # Списки признаков для конкретных моделей X_reg_features_cols = feature_columns X_clf_features_cols_without_AL_score = feature_columns # Медианы для заполнения пропусков x_train_medians_values = { 'RIDAGEYR': 31.0, 'RIAGENDR': 2.0, 'BMXBMI': 25.8, 'BMXWAIST': 91.2, 'BPXSY1': 118.0, 'BPXDI1': 70.0, 'LBXGH': 5.5, 'LBXHSCRP': 1.35, 'LBDTCSI': 4.55, 'LBDHDD': 51.0, 'SLQ050': 2.0, 'HSQ510': 2.0, 'LBXIN': 10.04, 'PHQ9_score': 0.0, 'LBXBPB': 0.76, 'LBXBCD': 0.22, 'LBXTHG': 0.51, 'URXMHH': 5.5 } X_train_medians = pd.Series(x_train_medians_values) thresholds_recommendation = { 'LBXHSCRP': 2.71, 'SLQ050': 2.0, 'PHQ9_score': 2.0, 'HSQ510': 2.0, 'LBXBPB': 1.07, 'LBXBCD': 0.35, 'LBXTHG': 0.91, 'URXMHH': 5.5 } def generate_recommendations(participant_data): recommendations = [] stage = participant_data.get('stage_label', 0) if stage == 3.0: recommendations.append("🔴 Уровень адаптационной нагрузки крайне высокий. Необходима немедленная консультация врача.") elif stage == 2.0: recommendations.append("🟠 Уровень адаптационной нагрузки высокий. Рекомендуется изменение образа жизни.") elif stage == 1.0: recommendations.append("🟡 Наблюдается повышенная адаптационная нагрузка. Следите за здоровьем.") if participant_data.get('LBXHSCRP', 0) > thresholds_recommendation['LBXHSCRP']: recommendations.append(f"⚠️ Повышен уровень C-реактивного белка ({participant_data['LBXHSCRP']:.2f}).") # Сбор симптомов symptoms = [] if participant_data.get('SLQ050', 0) > thresholds_recommendation['SLQ050']: symptoms.append("сонливость") if participant_data.get('PHQ9_score', 0) > thresholds_recommendation['PHQ9_score']: symptoms.append("высокий стресс (PHQ-9)") if symptoms: recommendations.append(f"💡 Обратите внимание на: {', '.join(symptoms)}.") if not recommendations: recommendations.append("✅ Ваши показатели в норме.") return recommendations def predict_and_recommend(*args): # Создание DataFrame input_df = pd.DataFrame([args], columns=feature_columns) # Заполнение пропусков for col in feature_columns: if pd.isna(input_df[col]).any(): input_df[col] = input_df[col].fillna(X_train_medians.get(col, 0)) # Предсказание AL Score predicted_al_score = xgb_reg_model.predict(input_df[X_reg_features_cols])[0] # Подготовка для классификатора и UMAP input_df_clf = input_df[X_clf_features_cols_without_AL_score].copy() input_df_clf.insert(0, 'AL_score', predicted_al_score) predicted_stage_label = xgb_clf_model.predict(input_df_clf)[0] # UMAP и Кластеризация umap_emb = umap_reducer.transform(input_df_clf) cluster = hdbscan_clusterer.predict(umap_emb)[0] # SHAP explainer = shap.TreeExplainer(xgb_reg_model) shap_vals = explainer.shap_values(input_df[X_reg_features_cols]) plt.figure(figsize=(10, 3)) shap.force_plot(explainer.expected_value, shap_vals[0], input_df.iloc[0], matplotlib=True, show=False) buf = io.BytesIO() plt.savefig(buf, format='png', bbox_inches='tight') plt.close() # Рекомендации diag_data = input_df.iloc[0].to_dict() diag_data['stage_label'] = predicted_stage_label recs = generate_recommendations(diag_data) return ( round(float(predicted_al_score), 2), int(predicted_stage_label), f"{umap_emb[0,0]:.2f}, {umap_emb[0,1]:.2f}", str(cluster), buf.getvalue(), "\n".join(recs) ) # Описание интерфейса Gradio feature_labels = { 'RIDAGEYR': 'Возраст', 'RIAGENDR': 'Пол (1=М, 2=Ж)', 'BMXBMI': 'ИМТ', 'BMXWAIST': 'Талия', 'BPXSY1': 'Сист. АД', 'BPXDI1': 'Диаст. АД', 'LBXGH': 'HbA1c', 'LBXHSCRP': 'hsCRP', 'LBDTCSI': 'Холестерин', 'LBDHDD': 'ЛПВП', 'LBXIN': 'Инсулин', 'SLQ050': 'Сонливость', 'HSQ510': 'Боль', 'PHQ9_score': 'PHQ-9', 'LBXBPB': 'Свинец', 'LBXBCD': 'Кадмий', 'LBXTHG': 'Ртуть', 'URXMHH': 'Фталаты' } with gr.Blocks() as demo: gr.Markdown("# Система оценки адаптационной нагрузки") inputs = [] with gr.Row(): with gr.Column(): for col in feature_columns[:9]: inputs.append(gr.Number(label=feature_labels[col], value=X_train_medians[col])) with gr.Column(): for col in feature_columns[9:]: inputs.append(gr.Number(label=feature_labels[col], value=X_train_medians[col])) btn = gr.Button("Рассчитать") with gr.Row(): al_out = gr.Textbox(label="AL Score") stage_out = gr.Textbox(label="Стадия") coords_out = gr.Textbox(label="UMAP Координаты") cluster_out = gr.Textbox(label="Кластер") shap_out = gr.Image(label="Влияние признаков (SHAP)") recs_out = gr.Textbox(label="Рекомендации", lines=5) btn.click(predict_and_recommend, inputs=inputs, outputs=[al_out, stage_out, coords_out, cluster_out, shap_out, recs_out]) demo.launch()