顶刊APP部署复现——基于XGBoost模型的心脏病风险预测与解释:Streamlit应用程序开发

机器学习关系型数据库数据安全

picture.image

背景

在当前的科学研究中,顶级期刊(如Nature、Science、柳叶刀等)所发表的文章不仅要求研究内容具有前沿性和创新性,同时也越来越强调研究结果的实际应用性和可复现性。近年来,随着机器学习和人工智能技术的迅猛发展,越来越多的研究者选择将他们的模型以应用程序(App)的形式进行部署,从而使审稿人和其他研究者可以通过简单的界面,输入相关数据来验证模型的性能和应用价值

这种趋势在医学领域尤为显著,例如,研究人员可以开发基于机器学习的诊断模型,并将其部署为App,审稿人只需输入病人的特征数据,App就能够返回病人患病的概率,这种应用不仅提高了研究成果的可操作性,也为医学研究中的实际诊断提供了有力支持,然而,如何在自己的研究中复现这些顶刊的App部署过程,仍然是许多研究者面临的挑战

本篇文章旨在探讨如何有效地复现顶刊中的App部署过程,包括从模型训练、优化到最终的App开发和部署,我们将深入剖析每一个关键步骤,结合实际案例,为研究者提供一条清晰的路径,以确保其研究成果能够顺利转化为实用的应用工具

相关期刊

picture.image

picture.image

picture.image

这是几篇相关文献, 模型都被以应用程序(App)的形式进行部署,在这里我将对第三篇文献的APP进行部署,当然我没有这篇文章的原始数据,于是将采用 Heart Disease UCI数据集(有小变动),来代替接下来的所有步骤,最后部署和其功能一模一样的Heart Disease Predictor在线访问APP,APP链接如下:


        
            

          https://7mmyfowsw5biqikcpmjlvd.streamlit.app/
        
      

数据特征描述

  1. age

  2. sex

  3. cp:chest pain type(4 values) 胸痛类型

    ---Value 1: typical angina 典型心绞痛

    ---Value 2: atypical angina 非典型心绞痛

    ---Value 3: non-anginal pain 非心绞痛

    ---Value 4: asymptomatic 无症状

  4. trestbps:resting blood pressure 静息血压

  5. chol:serum cholestoral in mg/dl 血清胆固醇

  6. fbs:fasting blood sugar >120 mg/dl 空腹血糖

  7. restecg:resting electrocardiographic results 静息心电图

    ---Value 0:normal 正常

    ---Value 1:having ST-T wave abnormality ST-T波异常

(T波倒转和/或ST仰角或俯角大于0.05 mV)

---Value 2:showing probable or definite left ventricular hypertrophy by Estes' cri teria 根据Estes标准显 示可能或确定存在左心室肥大

  1. thalach:maximum heart rate achieved 达到最大心率

  2. exang:exercise induced angina 运动性心绞痛

  3. oldpeak:ST depression induced by exercise relative to rest

    运动相对于休息引起的ST段压低

  4. solp:the slope of the peak exercise ST segment

    运动峰ST段的坡度

  5. ca:number of major vessels(0-3) colored by flourosopy

    用荧光染色的主要血管数

  6. thal: 1=normal; 2=fixed defect; 3 = reversable defect

    1=正常;2=固定缺陷;3=可逆转缺陷

14)target:Heart disease(0 = no, 1=yes)

代码实现

数据读取并分割


          
import pandas as pd
          
import numpy as np
          
import matplotlib.pyplot as plt
          
from sklearn.model_selection import train_test_split
          
df = pd.read_csv('Dataset.csv')
          
# 划分特征和目标变量
          
X = df.drop(['target'], axis=1)
          
y = df['target']
          
# 划分训练集和测试集
          
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, 
          
                                                    random_state=42, stratify=df['target'])
          
df.head()
      

picture.image

模型构建


          
import xgboost as xgb
          
from sklearn.model_selection import GridSearchCV
          

          
# XGBoost模型参数
          
params_xgb = {
          
    'learning_rate': 0.02,            # 学习率,控制每一步的步长,用于防止过拟合。典型值范围:0.01 - 0.1
          
    'booster': 'gbtree',              # 提升方法,这里使用梯度提升树(Gradient Boosting Tree)
          
    'objective': 'binary:logistic',   # 损失函数,这里使用逻辑回归,用于二分类任务
          
    'max_leaves': 127,                # 每棵树的叶子节点数量,控制模型复杂度。较大值可以提高模型复杂度但可能导致过拟合
          
    'verbosity': 1,                   # 控制 XGBoost 输出信息的详细程度,0表示无输出,1表示输出进度信息
          
    'seed': 42,                       # 随机种子,用于重现模型的结果
          
    'nthread': -1,                    # 并行运算的线程数量,-1表示使用所有可用的CPU核心
          
    'colsample_bytree': 0.6,          # 每棵树随机选择的特征比例,用于增加模型的泛化能力
          
    'subsample': 0.7,                 # 每次迭代时随机选择的样本比例,用于增加模型的泛化能力
          
    'eval_metric': 'logloss'          # 评价指标,这里使用对数损失(logloss)
          
}
          

          

          
# 初始化XGBoost分类模型
          
model_xgb = xgb.XGBClassifier(**params_xgb)
          

          

          
# 定义参数网格,用于网格搜索
          
param_grid = {
          
    'n_estimators': [100, 200, 300, 400, 500],  # 树的数量
          
    'max_depth': [3, 4, 5, 6, 7],               # 树的深度
          
    'learning_rate': [0.01, 0.02, 0.05, 0.1],   # 学习率
          
}
          

          

          
# 使用GridSearchCV进行网格搜索和k折交叉验证
          
grid_search = GridSearchCV(
          
    estimator=model_xgb,
          
    param_grid=param_grid,
          
    scoring='neg_log_loss',  # 评价指标为负对数损失
          
    cv=5,                    # 5折交叉验证
          
    n_jobs=-1,               # 并行计算
          
    verbose=1                # 输出详细进度信息
          
)
          

          
# 训练模型
          
grid_search.fit(X_train, y_train)
          

          
# 输出最优参数
          
print("Best parameters found: ", grid_search.best_params_)
          
print("Best Log Loss score: ", -grid_search.best_score_)
          

          
# 使用最优参数训练模型
          
best_model = grid_search.best_estimator_
      

picture.image

这部分代码理解参考文章 优化XGBoost分类模型:网格搜索与K折交叉验证实现

模型评价

详细指标


          
from sklearn.metrics import classification_report
          
# 预测测试集
          
y_pred = best_model.predict(X_test)
          
# 输出模型报告, 查看评价指标
          
print(classification_report(y_test, y_pred))
      

picture.image

ROC曲线


          
from sklearn.metrics import roc_curve, auc
          
# 预测概率
          
y_score = best_model.predict_proba(X_test)[:, 1]
          
# 计算ROC曲线
          
fpr_logistic, tpr_logistic, _ = roc_curve(y_test, y_score)
          
roc_auc_logistic = auc(fpr_logistic, tpr_logistic)
          
# 绘制ROC曲线
          
plt.figure()
          
plt.plot(fpr_logistic, tpr_logistic, color='darkorange', lw=2, label='ROC curve (area = %0.2f)' % roc_auc_logistic)
          
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
          
plt.xlim([0.0, 1.0])
          
plt.ylim([0.0, 1.05])
          
plt.xlabel('False Positive Rate')
          
plt.ylabel('True Positive Rate')
          
plt.title('Receiver Operating Characteristic')
          
plt.legend(loc="lower right")
          
plt.show()
      

picture.image

模型保存


          
import joblib
          
# 保存模型
          
joblib.dump(best_model , 'XGBoost.pkl')
      

使用 joblib.dump 将训练好的模型 best_model 保存为名为 'XGBoost.pkl' 的文件,以便后续加载和使用,以此部署APP

Streamlit应用程序开发


          
import streamlit as st
          
import joblib
          
import numpy as np
          
import pandas as pd
          
import shap
          
import matplotlib.pyplot as plt
          

          
# Load the model
          
model = joblib.load('XGBoost.pkl')
          

          
# Define feature options
          
cp_options = {
          
    1: 'Typical angina (1)',
          
    2: 'Atypical angina (2)',
          
    3: 'Non-anginal pain (3)',
          
    4: 'Asymptomatic (4)'
          
}
          

          
restecg_options = {
          
    0: 'Normal (0)',
          
    1: 'ST-T wave abnormality (1)',
          
    2: 'Left ventricular hypertrophy (2)'
          
}
          

          
slope_options = {
          
    1: 'Upsloping (1)',
          
    2: 'Flat (2)',
          
    3: 'Downsloping (3)'
          
}
          

          
thal_options = {
          
    1: 'Normal (1)',
          
    2: 'Fixed defect (2)',
          
    3: 'Reversible defect (3)'
          
}
          

          
# Define feature names
          
feature_names = [
          
    "Age", "Sex", "Chest Pain Type", "Resting Blood Pressure", "Serum Cholesterol",
          
    "Fasting Blood Sugar", "Resting ECG", "Max Heart Rate", "Exercise Induced Angina",
          
    "ST Depression", "Slope", "Number of Vessels", "Thal"
          
]
          

          
# Streamlit user interface
          
st.title("Heart Disease Predictor")
          

          
# age: numerical input
          
age = st.number_input("Age:", min_value=1, max_value=120, value=50)
          

          
# sex: categorical selection
          
sex = st.selectbox("Sex (0=Female, 1=Male):", options=[0, 1], format_func=lambda x: 'Female (0)' if x == 0 else 'Male (1)')
          

          
# cp: categorical selection
          
cp = st.selectbox("Chest pain type:", options=list(cp_options.keys()), format_func=lambda x: cp_options[x])
          

          
# trestbps: numerical input
          
trestbps = st.number_input("Resting blood pressure (trestbps):", min_value=50, max_value=200, value=120)
          

          
# chol: numerical input
          
chol = st.number_input("Serum cholesterol in mg/dl (chol):", min_value=100, max_value=600, value=200)
          

          
# fbs: categorical selection
          
fbs = st.selectbox("Fasting blood sugar > 120 mg/dl (fbs):", options=[0, 1], format_func=lambda x: 'False (0)' if x == 0 else 'True (1)')
          

          
# restecg: categorical selection
          
restecg = st.selectbox("Resting electrocardiographic results:", options=list(restecg_options.keys()), format_func=lambda x: restecg_options[x])
          

          
# thalach: numerical input
          
thalach = st.number_input("Maximum heart rate achieved (thalach):", min_value=50, max_value=250, value=150)
          

          
# exang: categorical selection
          
exang = st.selectbox("Exercise induced angina (exang):", options=[0, 1], format_func=lambda x: 'No (0)' if x == 0 else 'Yes (1)')
          

          
# oldpeak: numerical input
          
oldpeak = st.number_input("ST depression induced by exercise relative to rest (oldpeak):", min_value=0.0, max_value=10.0, value=1.0)
          

          
# slope: categorical selection
          
slope = st.selectbox("Slope of the peak exercise ST segment (slope):", options=list(slope_options.keys()), format_func=lambda x: slope_options[x])
          

          
# ca: numerical input
          
ca = st.number_input("Number of major vessels colored by fluoroscopy (ca):", min_value=0, max_value=4, value=0)
          

          
# thal: categorical selection
          
thal = st.selectbox("Thal (thal):", options=list(thal_options.keys()), format_func=lambda x: thal_options[x])
          

          
# Process inputs and make predictions
          
feature_values = [age, sex, cp, trestbps, chol, fbs, restecg, thalach, exang, oldpeak, slope, ca, thal]
          
features = np.array([feature_values])
          

          
if st.button("Predict"):
          
    # Predict class and probabilities
          
    predicted_class = model.predict(features)[0]
          
    predicted_proba = model.predict_proba(features)[0]
          

          
    # Display prediction results
          
    st.write(f"**Predicted Class:** {predicted_class}")
          
    st.write(f"**Prediction Probabilities:** {predicted_proba}")
          

          
    # Generate advice based on prediction results
          
    probability = predicted_proba[predicted_class] * 100
          

          
    if predicted_class == 1:
          
        advice = (
          
            f"According to our model, you have a high risk of heart disease. "
          
            f"The model predicts that your probability of having heart disease is {probability:.1f}%. "
          
            "While this is just an estimate, it suggests that you may be at significant risk. "
          
            "I recommend that you consult a cardiologist as soon as possible for further evaluation and "
          
            "to ensure you receive an accurate diagnosis and necessary treatment."
          
        )
          
    else:
          
        advice = (
          
            f"According to our model, you have a low risk of heart disease. "
          
            f"The model predicts that your probability of not having heart disease is {probability:.1f}%. "
          
            "However, maintaining a healthy lifestyle is still very important. "
          
            "I recommend regular check-ups to monitor your heart health, "
          
            "and to seek medical advice promptly if you experience any symptoms."
          
        )
          

          
    st.write(advice)
          

          
    # Calculate SHAP values and display force plot
          
    explainer = shap.TreeExplainer(model)
          
    shap_values = explainer.shap_values(pd.DataFrame([feature_values], columns=feature_names))
          

          
    shap.force_plot(explainer.expected_value, shap_values[0], pd.DataFrame([feature_values], columns=feature_names), matplotlib=True)
          
    plt.savefig("shap_force_plot.png", bbox_inches='tight', dpi=1200)
          

          
    st.image("shap_force_plot.png")
      

使用 Streamlit 构建心脏病风险预测应用程序,加载前文代码训练最好的 XGBoost 模型,接受用户输入的多种健康指标,通过模型预测用户是否存在患心脏病的风险,并给出相应的建议,此外,还使用 SHAP力图可视化来解释模型的预测结果,以此来达到论文复现

APP部署

准备项目文件

确保你的项目文件夹中包含以下文件

  • Python脚本文件 (your_script.py):这是包含 Streamlit 代码的文件
  • requirements.txt:列出所有依赖库的文件

上传项目到Github

如果还没有 GitHub 仓库,你需要创建一个并将项目推送到仓库中

创建 GitHub 仓库

  • 登录到 GitHub
  • 点击右上角的“New”按钮创建一个新仓库
  • 选择仓库的名字并初始化 README 文件
  • 将项目文件推送到这个仓库中,以下是推送代码的步骤(假设你已经在本地初始化了 Git)

          
git init
          
git add .
          
git commit -m "Initial commit"
          
git branch -M main
          
git remote add origin https://github.com/yourusername/your-repo-name.git
          
git push -u origin main
      

部署到 Streamlit Cloud

treamlit Cloud 提供了一个简单的界面来托管 Streamlit 应用程序

a. 登录 Streamlit Cloud

访问 Streamlit Cloud

使用 GitHub 账户登录(因为你需要访问 GitHub 仓库)

b. 部署应用

登录后,点击页面右上角的 "Create app" 按钮

在弹出的对话框中,选择你刚刚上传到 GitHub 的项目仓库

选择分支(一般为 main)和要运行的 Python 脚本文件(如 your_script.py)

点击 "Deploy" 按钮

Streamlit Cloud 会开始构建和部署你的应用,这个过程可能需要几分钟

picture.image

这就是你需要选择的界面,部署完成后就可以 访问你的应用了, Streamlit 会生成一个唯一的 URL,通过这个 URL,你和其他用户可以访问你的应用, 例如我们这里生成的URL为:


        
            

          https://7mmyfowsw5biqikcpmjlvd.streamlit.app/
        
      

当然这里是一种部署APP的方法读者可以自行选择部署方法,以及相关配置

APP演示

picture.image

当你访问以上这个网址时会出现这个界面Heart Disease Predictor此时你只需要输入每个特征相关的值即可,然后点击Predict按钮,APP就会自动给出模型预测结果为那个类比,每个类别的概率,相关建议以及力图,具体输出如下:

picture.image

picture.image

到这里就完美复现了第三篇顶刊文章的APP部署,考虑到相关读者可能对于代码上传Github,模型部署到Streamlit Cloud会存在很多问题,作者考虑会找一个机会,录制这个过程的相关视频以供读者学习,当然也支持读者定制相关APP

往期推荐

利用XGBoost模型进行多分类任务下的SHAP解释附代码讲解及GUI展示

利用SHAP解释二分类模型的四种机器学习GUI工具

SVM多分类分析:SHAP解释各类别下各特征对模型的影响力

快速选择最佳模型:轻松上手LightGBM、XGBoost、CatBoost和NGBoost!

基于CatBoost回归预测模型的多种可解释性图表绘制

小白轻松上手:一键生成SHAP解释图的GUI应用,支持多种梯度提升模型选择

综合多种梯度提升模型:LightGBM、XGBoost、CatBoost与NGBoost的集成预测

优化XGBoost回归模型:网格搜索与K折交叉验证实现

picture.image

picture.image

picture.image

微信号|deep_ML

欢迎添加作者微信进入Python、ChatGPT群

进群请备注Python或AI进入相关群
无需科学上网、同步官网所有功能、使用无限制

如果你对类似于这样的文章感兴趣。

欢迎关注、点赞、转发~

个人观点,仅供参考

0
0
0
0
关于作者

文章

0

获赞

0

收藏

0

相关资源
大规模高性能计算集群优化实践
随着机器学习的发展,数据量和训练模型都有越来越大的趋势,这对基础设施有了更高的要求,包括硬件、网络架构等。本次分享主要介绍火山引擎支撑大规模高性能计算集群的架构和优化实践。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论