xgboost 多分类(六段age predict)

本文介绍了一个使用XGBoost进行年龄预测的案例。主要内容包括数据预处理、模型训练、预测与评估等步骤。通过参数调整提高模型准确率,并展示了特征重要性分析。

1. 相关包导入

# -*- coding: utf-8 -*-
import numpy as np
import xgboost as xgb
from xgboost import plot_importance
from sklearn import preprocessing
from sklearn.model_selection import train_test_split
from sklearn import metrics
from matplotlib import pyplot as plt

2. 数据预处理
2.1 加载数据

# 数据文件不要带表头
data = pd.read_csv('../data/data.csv', header=None, sep=',')
data.columns = all_names  # 赋值表头
X = data.loc[:, feature_names]  # hive中以int存储,则此处读出来也是int,不需要转换
Y = data.loc[:, 'monthly_income'] - 1  # 多标签从0开始

2.1 数据处理

# 1.load data
data = np.loadtxt('/data/zz/age_predict/data.txt', delimiter=',')
data_num, feature_num = data.shape
print("data_num:   ", data_num)
print("feature_num:   ", feature_num)
# 2.shuffle data
# data = data.sample(frac=1, random_state=1024)
rng = np.random.RandomState(2021)
index = list(range(data_num))
rng.shuffle(index)
data = data[index]
# 3.split data
X, Y = data[:, 0:feature_num-1], data[:, feature_num-1]
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.3, random_state=0)
# 4.transmfer data
xg_train = xgb.DMatrix(X_train, label=y_train)
xg_test = xgb.DMatrix(X_test, label=y_test)

查看数据集切分后,测试集分布是否变化(一般不会变化)

test_data_new = pd.concat([X_test, y_test], axis=1, ignore_index=True)
test_data_new.columns = feature_names + ["label"]
print(test_data_new.loc[:, 'label'].value_counts())

3. 模型训练及预测

params = {
    'booster': 'gbtree',
    'objective': 'multi:softmax',
    'num_class': 6, 
    'learning_rate': 0.2,
    'gamma': 0.1,
    'max_depth': 8,
    'lambda': 2,
    'subsample': 0.85,
    'colsample_bytree': 0.85,
    'min_child_weight': 3,
    'silent': 1,
    'eta': 0.05,
    'seed': 1000,
    'nthread': 4,
}

num_round = 20
watchlist = [(xg_train, 'train'), (xg_test, 'test')]
bst = xgb.train(params, xg_train, num_round, watchlist)
pred = bst.predict(xg_test)

4. 模型评估

print('predicting, classification error=%f'
       % (sum(int(pred[i]) != y_test[i] for i in range(len(y_test))) / float(len(y_test))))

print('Accuracy: %.4f' % metrics.accuracy_score(y_test, pred))
print(metrics.confusion_matrix(y_test, pred))

5. 重要特征打印

# 打印特征重要度
# plot_importance(bst)
# plt.show()
importance = bst.get_score(importance_type='gain')
sorted_importance = sorted(importance.items(), key=lambda x: x[1], reverse=True)
print('feature importances[gain]: ', sorted_importance)
# 毕业设计:基于随机森林、XGBoost 和 LightGBM 的心脏病症状预测数据分析系统 --- ## 一、项目背景与意义 心血管疾病是全球死亡率最高的疾病之一,早期发现和干预至关重要。通过机器学习模型对患者临床数据进行分析,可以有效预测其是否患有心脏病,辅助医生做出诊断决策。 本毕业设计旨在构建一个**基于随机森林(Random Forest)、XGBoost 和 LightGBM 的多模型对比预测系统**,使用公开的心脏病数据集(如 UCI Heart Disease Dataset),实现数据预处理、特征工程、模型训练、评估与可视化,并开发一个简易 Web 系统供用户输入信息后获得预测结果。 --- ## 二、技术栈 - **编程语言**:Python - **机器学习库**: - `scikit-learn`(随机森林) - `xgboost` - `lightgbm` - **数据处理**:`pandas`, `numpy` - **可视化**:`matplotlib`, `seaborn` - **Web 后端框架**:Flask - **前端界面**:HTML/CSS/JavaScript(简单表单) - **部署方式**:本地运行或轻量级服务器 --- ## 三、数据集介绍 我们使用 [UCI Machine Learning Repository - Heart Disease Dataset](https://archive.ics.uci.edu/ml/datasets/Heart+Disease) ### 数据来源: > https://archive.ics.uci.edu/ml/machine-learning-databases/heart-disease/ ### 字段说明(共14个字段): | 特征 | 描述 | |------|------| | age | 年龄 | | sex | 性别 (0=女性, 1=男性) | | cp | 胸痛类型 (0-3) | | trestbps | 静息血压 (mm Hg) | | chol | 血清胆固醇 (mg/dl) | | fbs | 空腹血糖 > 120 mg/dl (0=否, 1=是) | | restecg | 静息心电图 (0-2) | | thalach | 最大心率 | | exang | 运动诱发心绞痛 (0=无, 1=有) | | oldpeak | 相对于休息的 ST 抑制程度 | | slope | ST 段斜率 (0-2) | | ca | 主要血管数量(荧光染色)(0-3) | | thal | 地中海贫血(3=正常; 6=固定缺陷; 7=可逆缺陷) | | target | 是否患心脏病 (0=否, 1=是) | > 注:原始数据来自四个数据库(Cleveland, Hungary, Switzerland, Long Beach VA),通常只用 Cleveland 子集(303 条记录,14 字段) --- ## 四、完整代码实现 我们将分模块编写代码: ``` project/ │ ├── data/ │ └── heart.csv ├── models/ │ ├── rf_model.pkl │ ├── xgb_model.pkl │ └── lgb_model.pkl ├── app.py # Flask 主程序 ├── train.py # 模型训练脚本 ├── utils.py # 工具函数(绘图等) └── templates/ └── index.html # 前端页面 ``` --- ### ✅ 第一步:安装依赖 ```bash pip install flask pandas numpy scikit-learn xgboost lightgbm matplotlib seaborn joblib ``` --- ### ✅ 第二步:`train.py` —— 数据加载 + 模型训练 + 保存 ```python # train.py import pandas as pd import numpy as np from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from xgboost import XGBClassifier from lightgbm import LGBMClassifier from sklearn.metrics import accuracy_score, classification_report, confusion_matrix from sklearn.preprocessing import StandardScaler import joblib import os # 创建目录 os.makedirs("models", exist_ok=True) # 加载数据(假设已下载为 heart.csv) df = pd.read_csv("data/heart.csv") # 查看基本信息 print("数据形状:", df.shape) print(df.head()) print("缺失值:\n", df.isnull().sum()) # 分离特征与标签 X = df.drop(columns=['target']) y = df['target'] # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y) # 标准化数值型特征(可选,对树模型影响较小但有助于比较) scaler = StandardScaler() num_cols = ['age', 'trestbps', 'chol', 'thalach', 'oldpeak'] X_train[num_cols] = scaler.fit_transform(X_train[num_cols]) X_test[num_cols] = scaler.transform(X_test[num_cols]) # 保存标准化器 joblib.dump(scaler, "models/scaler.pkl") # 初始化三个模型 rf_model = RandomForestClassifier(n_estimators=100, random_state=42) xgb_model = XGBClassifier(use_label_encoder=False, eval_metric='logloss', random_state=42) lgb_model = LGBMClassifier(random_state=42) # 训练模型 print("\n开始训练模型...") rf_model.fit(X_train, y_train) xgb_model.fit(X_train, y_train) lgb_model.fit(X_train, y_train) # 测试集预测 rf_pred = rf_model.predict(X_test) xgb_pred = xgb_model.predict(X_test) lgb_pred = lgb_model.predict(X_test) # 输出性能指标 def evaluate_model(name, y_true, y_pred): acc = accuracy_score(y_true, y_pred) print(f"\n{name} 准确率: {acc:.4f}") print(f"{name} 分类报告:") print(classification_report(y_true, y_pred)) return acc acc_rf = evaluate_model("随机森林", y_test, rf_pred) acc_xgb = evaluate_model("XGBoost", y_test, xgb_pred) acc_lgb = evaluate_model("LightGBM", y_test, lgb_pred) # 选择最佳模型保存为主模型(这里以准确率为标准) best_acc = max(acc_rf, acc_xgb, acc_lgb) if best_acc == acc_rf: best_model = rf_model best_name = "RandomForest" elif best_acc == acc_xgb: best_model = xgb_model best_name = "XGBoost" else: best_model = lgb_model best_name = "LightGBM" print(f"\n✅ 最佳模型: {best_name}, 准确率: {best_acc:.4f}") # 保存所有模型 joblib.dump(rf_model, "models/rf_model.pkl") joblib.dump(xgb_model, "models/xgb_model.pkl") joblib.dump(lgb_model, "models/lgb_model.pkl") joblib.dump(best_model, "models/best_model.pkl") # 特征重要性可视化准备 import matplotlib.pyplot as plt import seaborn as sns plt.figure(figsize=(10,6)) feat_importance = pd.Series(best_model.feature_importances_, index=X.columns).sort_values(ascending=False) sns.barplot(x=feat_importance.values, y=feat_importance.index) plt.title("特征重要性排序(基于最佳模型)") plt.xlabel("重要性") plt.tight_layout() plt.savefig("static/feature_importance.png") plt.close() print("✅ 所有模型训练完成并保存!") ``` #### 🔍 代码解释: - 使用 `pandas` 加载 CSV 数据。 - 自动识别缺失值并划分训练/测试集。 - 对连续变量进行标准化(虽然树模型不敏感,但保持一致性)。 - 训练三种模型并输出分类报告。 - 将模型使用 `joblib` 保存到磁盘以便后续调用。 - 绘制特征重要性图用于展示。 --- ### ✅ 第三步:`utils.py` —— 可视化工具 ```python # utils.py import matplotlib.pyplot as plt import seaborn as sns import pandas as pd from sklearn.metrics import confusion_matrix import os def plot_confusion_matrices(y_test, rf_pred, xgb_pred, lgb_pred): models = ["Random Forest", "XGBoost", "LightGBM"] preds = [rf_pred, xgb_pred, lgb_pred] fig, axes = plt.subplots(1, 3, figsize=(15, 5)) for i, (name, pred) in enumerate(zip(models, preds)): cm = confusion_matrix(y_test, pred) sns.heatmap(cm, annot=True, fmt="d", ax=axes[i], cmap="Blues") axes[i].set_title(f"{name} 混淆矩阵") axes[i].set_ylabel("真实") axes[i].set_xlabel("预测") plt.tight_layout() os.makedirs("static", exist_ok=True) plt.savefig("static/confusion_matrices.png") plt.close() def plot_accuracy_comparison(acc_rf, acc_xgb, acc_lgb): df_acc = pd.DataFrame({ 'Model': ['Random Forest', 'XGBoost', 'LightGBM'], 'Accuracy': [acc_rf, acc_xgb, acc_lgb] }) plt.figure(figsize=(8, 5)) sns.barplot(data=df_acc, x='Model', y='Accuracy', palette='viridis') plt.title('各模型准确率对比') plt.ylim(0.7, 1.0) for idx, row in df_acc.iterrows(): plt.text(idx, row.Accuracy + 0.005, f"{row.Accuracy:.3f}", ha='center') plt.tight_layout() plt.savefig("static/accuracy_comparison.png") plt.close() ``` > 在 `train.py` 中最后添加以下内容来生成图表: ```python # 添加在 train.py 末尾 from utils import plot_confusion_matrices, plot_accuracy_comparison plot_confusion_matrices(y_test, rf_pred, xgb_pred, lgb_pred) plot_accuracy_comparison(acc_rf, acc_xgb, acc_lgb) ``` --- ### ✅ 第四步:`app.py` —— Flask Web 接口 ```python # app.py from flask import Flask, request, render_template, jsonify import joblib import numpy as np import pandas as pd import os app = Flask(__name__) app.config['SECRET_KEY'] = 'heart_disease_2025' # 全局变量存储模型和 scaler model_rf = None model_xgb = None model_lgb = None best_model = None scaler = None model_names = { 'rf': '随机森林', 'xgb': 'XGBoost', 'lgb': 'LightGBM' } @app.before_first_request def load_models(): global model_rf, model_xgb, model_lgb, best_model, scaler try: model_rf = joblib.load("models/rf_model.pkl") model_xgb = joblib.load("models/xgb_model.pkl") model_lgb = joblib.load("models/lgb_model.pkl") best_model = joblib.load("models/best_model.pkl") scaler = joblib.load("models/scaler.pkl") print("✅ 模型加载成功") except Exception as e: print("❌ 模型加载失败:", str(e)) @app.route('/') def index(): return render_template('index.html') @app.route('/predict', methods=['POST']) def predict(): try: # 获取前端传来的 JSON 数据 data = request.get_json() # 构造输入 DataFrame input_data = pd.DataFrame([{ 'age': float(data['age']), 'sex': int(data['sex']), 'cp': int(data['cp']), 'trestbps': float(data['trestbps']), 'chol': float(data['chol']), 'fbs': int(data['fbs']), 'restecg': int(data['restecg']), 'thalach': float(data['thalach']), 'exang': int(data['exang']), 'oldpeak': float(data['oldpeak']), 'slope': int(data['slope']), 'ca': int(data['ca']), 'thal': int(data['thal']) }]) # 标准化数值列 num_cols = ['age', 'trestbps', 'chol', 'thalach', 'oldpeak'] input_data[num_cols] = scaler.transform(input_data[num_cols]) # 多模型预测 pred_rf = model_rf.predict(input_data)[0] prob_rf = model_rf.predict_proba(input_data)[0].tolist() pred_xgb = model_xgb.predict(input_data)[0] prob_xgb = model_xgb.predict_proba(input_data)[0].tolist() pred_lgb = model_lgb.predict(input_data)[0] prob_lgb = model_lgb.predict_proba(input_data)[0].tolist() result = { 'success': True, 'predictions': [ { 'model': '随机森林', 'prediction': int(pred_rf), 'probability': [round(p, 3) for p in prob_rf] }, { 'model': 'XGBoost', 'prediction': int(pred_xgb), 'probability': [round(p, 3) for p in prob_xgb] }, { 'model': 'LightGBM', 'prediction': int(pred_lgb), 'probability': [round(p, 3) for p in prob_lgb] } ], 'final_decision': int(best_model.predict(input_data)[0]), 'final_prob': best_model.predict_proba(input_data)[0].max().round(3) } return jsonify(result) except Exception as e: return jsonify({'success': False, 'error': str(e)}) if __name__ == '__main__': if not os.path.exists("models/best_model.pkl"): print("⚠️ 请先运行 train.py 训练模型!") else: app.run(debug=True) ``` #### 🔍 解释: - 使用 `@before_first_request` 加载所有模型一次。 - `/predict` 接收 JSON 请求,执行三个模型预测并返回概率。 - 返回最终决策基于“最佳模型”的预测结果。 - 支持错误捕获。 --- ### ✅ 第五步:`templates/index.html` —— 用户交互界面 ```html <!-- templates/index.html --> <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8" /> <title>心脏病预测系统</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <style> body { font-family: Arial, sans-serif; margin: 40px; background: #f4f6f9; } .container { max-width: 800px; margin: auto; background: white; padding: 30px; border-radius: 10px; box-shadow: 0 4px 10px rgba(0,0,0,0.1); } h1 { text-align: center; color: #d9534f; } label { display: block; margin-top: 15px; font-weight: bold; } input, select { width: 100%; padding: 8px; margin-top: 5px; border: 1px solid #ccc; border-radius: 4px; } button { margin-top: 20px; padding: 10px 20px; background: #0275d8; color: white; border: none; border-radius: 4px; cursor: pointer; } button:hover { background: #014a8f; } .result { margin-top: 20px; padding: 15px; border: 1px solid #ddd; border-radius: 5px; background: #f9f9f9; } .danger { color: #d9534f; font-weight: bold; } .safe { color: #5cb85c; font-weight: bold; } </style> </head> <body> <div id="app" class="container"> <h1>❤️ 心脏病风险预测系统</h1> <form @submit.prevent="predict"> <label>年龄:</label> <input v-model.number="age" type="number" required /> <label>性别 (0=女, 1=男):</label> <select v-model.number="sex" required> <option :value="0">女</option> <option :value="1">男</option> </select> <label>胸痛类型 (0-3):</label> <input v-model.number="cp" type="number" min="0" max="3" required /> <label>静息血压 (mm Hg):</label> <input v-model.number="trestbps" type="number" required /> <label>血清胆固醇 (mg/dl):</label> <input v-model.number="chol" type="number" required /> <label>空腹血糖 >120mg/dl (0=否, 1=是):</label> <select v-model.number="fbs"> <option :value="0">否</option> <option :value="1">是</option> </select> <label>静息心电图 (0-2):</label> <input v-model.number="restecg" type="number" min="0" max="2" required /> <label>最大心率:</label> <input v-model.number="thalach" type="number" required /> <label>运动诱发心绞痛 (0=无, 1=有):</label> <select v-model.number="exang"> <option :value="0">无</option> <option :value="1">有</option> </select> <label>ST 抑制程度 (oldpeak):</label> <input v-model.number="oldpeak" type="number" step="0.1" required /> <label>ST 斜率 (0-2):</label> <input v-model.number="slope" type="number" min="0" max="2" required /> <label>主要血管数 (0-3):</label> <input v-model.number="ca" type="number" min="0" max="3" required /> <label>地中海贫血 (3=正常, 6=固定, 7=可逆):</label> <input v-model.number="thal" type="number" required /> <button type="submit">预测心脏病风险</button> </form> <div v-if="result" class="result"> <h3>📊 预测结果</h3> <p><strong>最终判断:</strong> <span v-if="result.final_decision" class="danger">高风险 ⚠️</span> <span v-else class="safe">低风险 ✅</span> </p> <p>患病概率: {{ result.final_prob * 100 }}%</p> <table border="1" cellpadding="8" style="width:100%; margin-top:10px;"> <tr><th>模型</th><th>预测</th><th>健康概率</th><th>患病概率</th></tr> <tr v-for="p in result.predictions"> <td>{{ p.model }}</td> <td>{{ p.prediction ? '高风险' : '低风险' }}</td> <td>{{ p.probability[0].toFixed(3) }}</td> <td>{{ p.probability[1].toFixed(3) }}</td> </tr> </table> </div> </div> <script> new Vue({ el: '#app', data() { return { age: 60, sex: 1, cp: 1, trestbps: 140, chol: 250, fbs: 0, restecg: 1, thalach: 160, exang: 0, oldpeak: 1.5, slope: 1, ca: 1, thal: 3, result: null } }, methods: { predict() { fetch('/predict', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(this.$data) }) .then(res => res.json()) .then(data => { if (data.success) { this.result = data; } else { alert("预测失败:" + data.error); } }) .catch(err => { alert("请求出错:" + err.message); }); } } }); </script> </body> </html> ``` #### 🔍 功能特点: - 使用 Vue.js 实现动态表单绑定。 - 提交后发送 AJAX 请求到 `/predict`。 - 显示每个模型的预测结果及概率。 - 最终结论由最优模型决定。 --- ## 五、运行步骤 1. 下载数据集并放入 `data/heart.csv` - 可从 [Kaggle Heart Disease Dataset](https://www.kaggle.com/datasets/johnsmith88/heart-disease-dataset) 获取清理好的版本 2. 安装依赖 3. 运行训练: ```bash python train.py ``` 4. 启动 Web 服务: ```bash python app.py ``` 5. 浏览器访问:`http://localhost:5000` --- ## 六、预期成果截图(描述) - **首页**:美观的表单界面 - **预测结果页**:显示三大模型预测结果表格 + 最终建议 - **后台图表**: - 特征重要性图(thalach、ca、oldpeak 最重要) - 准确率对比柱状图 - 混淆矩阵热力图 --- ## 七、创新点与扩展建议 ### ✅ 创新点: - 多模型集成对比 + 可视化分析 - 支持实时在线预测 - 使用应用工厂思想便于部署 - 提供概率输出而非单一判断 ### 🔧 扩展方向: - 添加模型解释(SHAP 值分析) - 支持 CSV 批量上传预测 - 增加用户注册/历史记录功能 - 部署为 Docker 容器 + Nginx + Gunicorn - 移动端适配(响应式设计) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值