简介:这份资源面向机器学习入门与进阶学习者,聚焦心脏病数据集的分析与预测建模实战,帮助读者在真实医疗数据上完成从数据清洗到多模型对比的完整流程。包内共14个文件,以11个Python源代码为主,另含2个CSV数据集与1个说明文档,压缩包约46KB,代码手工整理、无语法错误且可直接运行。内容覆盖数据预处理、特征工程与可视化,并系统实现逻辑回归、KNN、高斯朴素贝叶斯、决策树、SVM、随机森林、XGBoost、MLP等多种分类模型,同时涉及MinMaxScaler、StandardScaler、KNNImputer、Pipeline、ColumnTransformer等特征处理工具,以及混淆矩阵、分类报告、ROC曲线、AUC、学习曲线、排列重要性等评估与解释手段,还包含dtreeviz决策树可视化与安德鲁斯曲线、平行坐标等探索性图表。已有98人学习,适合希望系统掌握分类建模与模型评估的读者参考。
1. 心脏病预测这套源码包,为什么值得你花一个下午跑一遍
拿到一个「AI实战」压缩包,多数人的第一反应是解压、看文件名、然后扔进硬盘吃灰。这套心脏病数据集分析预测实例不太一样:它把 11 个独立脚本按学习曲线排好了序,从最基础的逻辑回归一路铺到 MLP 分类器和 XGBoost,配两个 CSV 数据文件,总共 150.96 KB。你不需要自己去找数据、不用纠结字段含义,解压就能从第一个脚本开始跑。
它解决的核心问题是:给你一条从原始脏数据到模型评估的完整链路,而不是一个孤立的 demo。适合刚学完 sklearn 基础 API、想找一个真实医疗数据集练手的人;也适合已经会调参、但想看看别人怎么组织多模型对比代码的从业者。数据集本身是心脏病二分类任务,特征包括年龄、性别、胸痛类型、静息血压、胆固醇、最大心率等常规临床指标,标签是是否患病。11 个脚本覆盖了逻辑回归、KNN、朴素贝叶斯、决策树、SVM、随机森林、MLP、XGBoost,还有专门做可视化和特征重要性的脚本。换句话说,这是一个可以当「机器学习分类任务模板库」用的资源包。
我拆过不少类似的实战包,大部分要么代码跑不通,要么数据路径写死,要么版本对不上。这套的 readme.txt 虽然简单,但脚本命名有明确序号,依赖模块在摘要里列得清楚,属于「手工整理过」的那一类。下面按实际复现顺序,把环境、数据、代码、坑点逐个拆开。
2. 环境搭建与数据加载:从 Colab 路径到本地 CSV 的迁移
2.1 依赖清单与版本选择
摘要里列出的模块基本覆盖了这套代码的全部依赖。核心是 scikit-learn、pandas、numpy、matplotlib、seaborn,外加 xgboost、tqdm、dtreeviz。注意google.colab.drive这个模块——说明原始代码是在 Google Colab 上写的,数据加载路径大概率是/content/drive/MyDrive/...这种形式。你在本地跑,第一件事就是改路径。
我一般会建一个干净的虚拟环境,避免和系统里的老版本 sklearn 冲突。xgboost 和 dtreeviz 这两个是容易出问题的,单独装。
python -m venv heart_env source heart_env/bin/activate # Windows 用 heart_env\Scripts\activate pip install pandas numpy matplotlib seaborn scikit-learn xgboost tqdm dtreeviz参数说明:scikit-learn建议 1.0 以上,因为permutation_importance和ColumnTransformer在旧版本里行为有差异。dtreeviz依赖 graphviz,如果只跑分类模型不跑决策树可视化,可以先不装,省得配系统级依赖。
2.2 两个 CSV 的区别与加载方式
数据文件夹里有两个文件:raw_merged_heart_dataset.csv和cleaned_merged_heart_dataset.csv。从命名和脚本对应关系看,raw 是原始合并数据,cleaned 是做过缺失值处理和异常值清洗的版本。脚本 11 专门用 raw 数据集做预测,说明作者有意让你对比「脏数据直接喂模型」和「清洗后再喂」的差异。
加载代码很标准,但要注意编码和分隔符。医疗数据集常见的问题是列名带空格、缺失值用?或空字符串表示。
import pandas as pd import numpy as np # 加载清洗后的数据集 df_clean = pd.read_csv('cleaned_merged_heart_dataset.csv') print(df_clean.shape) print(df_clean.head()) print(df_clean.isnull().sum()) # 加载原始数据集做对比 df_raw = pd.read_csv('raw_merged_heart_dataset.csv') print(df_raw.shape) print(df_raw.dtypes)逻辑说明:先看 shape 确认行列数,再看 head 确认列名和数据类型,最后用isnull().sum()统计每列缺失值。raw 数据集大概率有缺失,cleaned 版本应该接近零缺失。如果 cleaned 版本还有大量缺失,说明清洗逻辑不完整,需要自己补 KNNImputer 或中位数填充。
参数说明:pd.read_csv如果报UnicodeDecodeError,加encoding='latin-1'或encoding='gbk'试。如果列名有前后空格,用df.columns = df.columns.str.strip()处理。
2.3 特征与标签的拆分
这套代码里标签列名需要你实际打开 CSV 确认。常见命名是target、heart_disease、num或condition。拆分逻辑在所有脚本里基本一致:
# 假设标签列名为 'target',实际以 CSV 列名为准 X = df_clean.drop('target', axis=1) y = df_clean['target'] # 如果标签是 0-4 的多分类,需要二值化 # y = (y > 0).astype(int) from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y )逻辑说明:stratify=y保证训练集和测试集的类别比例一致,医疗数据里患病样本通常少于非患病样本,不加分层可能导致测试集里正样本极少,评估指标失真。random_state=42是固定随机种子,保证你跑出来的结果和脚本里一致。
参数说明:test_size=0.2是常见选择,数据量小的时候可以调到 0.3 让测试集更有统计意义。如果标签是多分类,先确认业务上是否需要合并成二分类,这套代码的评估部分主要用二分类指标。
3. 多模型对比实战:从逻辑回归到 XGBoost 的脚本拆解
3.1 脚本 1 和脚本 4:逻辑回归与基础预测流程
脚本 1Heart Risk Disease Prediction Using ML Models.py和脚本 4Heart Attack Prediction.py是入门级,用逻辑回归和 KNN 跑通完整流程。核心步骤是:标准化 → 训练 → 预测 → 混淆矩阵 → 分类报告。
from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.metrics import confusion_matrix, classification_report, accuracy_score scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) lr = LogisticRegression(max_iter=1000, random_state=42) lr.fit(X_train_scaled, y_train) y_pred = lr.predict(X_test_scaled) print(confusion_matrix(y_test, y_pred)) print(classification_report(y_test, y_pred)) print('Accuracy:', accuracy_score(y_test, y_pred))逻辑说明:标准化必须用fit_transform在训练集上拟合,再用transform应用到测试集。如果对全量数据做fit_transform,测试集的信息会泄露到训练过程,评估结果虚高。max_iter=1000是因为逻辑回归在未标准化或特征量纲差异大时可能不收敛,默认 100 会报ConvergenceWarning。
参数说明:classification_report输出 precision、recall、f1-score。医疗场景下 recall 比 accuracy 更重要——漏诊的代价远大于误诊。如果 recall 偏低,可以调class_weight='balanced'让模型更关注少数类。
3.2 脚本 7 和脚本 10:随机森林与决策树分类器
脚本 7Heart Attack Prediction RandomForestClassifier.py和脚本 10Heart Attack Prediction Using DT Classifier.py分别用随机森林和决策树。这两个模型对特征缩放不敏感,可以跳过标准化,但决策树容易过拟合,需要控制深度。
from sklearn.ensemble import RandomForestClassifier from sklearn.tree import DecisionTreeClassifier rf = RandomForestClassifier( n_estimators=100, max_depth=10, min_samples_split=5, random_state=42 ) rf.fit(X_train, y_train) y_pred_rf = rf.predict(X_test) dt = DecisionTreeClassifier( max_depth=5, min_samples_leaf=10, random_state=42 ) dt.fit(X_train, y_train) y_pred_dt = dt.predict(X_test) # 特征重要性 import pandas as pd feat_imp = pd.Series(rf.feature_importances_, index=X.columns) print(feat_imp.sort_values(ascending=False).head(10))逻辑说明:随机森林的n_estimators=100是起点,数据量小的时候 100 到 300 足够。max_depth=10防止每棵树长得太深。决策树的max_depth=5和min_samples_leaf=10是强正则,医疗数据特征不多,树太深会记住训练集的噪声。特征重要性输出可以直接告诉你哪些临床指标对预测贡献最大,常见结果是胸痛类型、最大心率、胆固醇。
参数说明:min_samples_split控制节点分裂的最小样本数,调大可以防止过拟合。min_samples_leaf控制叶节点最小样本数,同样起正则作用。如果特征重要性里某个特征占比超过 0.3,检查一下是不是 ID 类列混进去了。
3.3 脚本 9 和脚本 6:MLP 分类器与 SVR 的边界
脚本 9Heart Attack Prediction Using MLP Classifier.py用神经网络,脚本 66-83 accuracy Raw Heart Disease Prediction SVR.py用支持向量回归。注意 SVR 是回归模型,用在分类任务上需要把标签当连续值处理,再阈值化。这个脚本名字里的83 accuracy说明作者跑出了 83% 的准确率。
from sklearn.neural_network import MLPClassifier from sklearn.svm import SVR from sklearn.metrics import accuracy_score # MLP 分类器 mlp = MLPClassifier( hidden_layer_sizes=(64, 32), activation='relu', max_iter=500, random_state=42 ) mlp.fit(X_train_scaled, y_train) y_pred_mlp = mlp.predict(X_test_scaled) print('MLP Accuracy:', accuracy_score(y_test, y_pred_mlp)) # SVR 做分类:预测连续值后阈值化 svr = SVR(kernel='rbf', C=1.0, epsilon=0.1) svr.fit(X_train_scaled, y_train) y_pred_svr = (svr.predict(X_test_scaled) > 0.5).astype(int) print('SVR Accuracy:', accuracy_score(y_test, y_pred_svr))逻辑说明:MLP 对特征缩放敏感,必须用标准化后的数据。hidden_layer_sizes=(64, 32)是两层结构,数据量小的时候不要堆太多层。SVR 输出连续值,用 0.5 做阈值切分成 0 和 1,这个阈值可以根据业务需求调整——如果更看重 recall,阈值可以降到 0.3。
参数说明:max_iter=500是 MLP 的迭代上限,如果报ConvergenceWarning,要么增加迭代次数,要么调小学习率。SVR 的C控制正则强度,C越大越容易过拟合;epsilon控制容忍误差带,分类任务里影响不大。
3.4 脚本 2 和脚本 5:F1 优化与可视化建模
脚本 22-81 F1 Heart Dataset.py名字里的81 F1暗示作者在优化 F1 分数到 0.81 左右。脚本 55-Detailed Visualization Modeling of Heart Disease.py做详细可视化,包括 Andrews 曲线、平行坐标图、学习曲线。
from sklearn.metrics import f1_score, roc_curve, auc import matplotlib.pyplot as plt # F1 优化:调整阈值 y_prob = lr.predict_proba(X_test_scaled)[:, 1] thresholds = np.arange(0.3, 0.7, 0.05) f1_scores = [f1_score(y_test, (y_prob > t).astype(int)) for t in thresholds] best_threshold = thresholds[np.argmax(f1_scores)] print('Best threshold:', best_threshold, 'Best F1:', max(f1_scores)) # ROC 曲线 fpr, tpr, _ = roc_curve(y_test, y_prob) roc_auc = auc(fpr, tpr) plt.plot(fpr, tpr, label=f'AUC = {roc_auc:.2f}') plt.plot([0, 1], [0, 1], 'k--') plt.xlabel('False Positive Rate') plt.ylabel('True Positive Rate') plt.legend() plt.show()逻辑说明:默认阈值 0.5 不一定最优,遍历 0.3 到 0.7 找 F1 最大的阈值是常见做法。ROC 曲线的 AUC 衡量模型整体排序能力,AUC 0.9 以上说明模型区分度很好。学习曲线用learning_curve看训练集和验证集的分数随样本量变化,判断是过拟合还是欠拟合。
参数说明:predict_proba返回概率,[:, 1]取正类概率。如果模型没有predict_proba(比如 SVC 默认不输出概率),需要设probability=True或改用decision_function。
4. 避坑与排查:路径、版本、数据泄露的五个血泪教训
4.1 现象:FileNotFoundError: raw_merged_heart_dataset.csv
原因:原始代码在 Colab 里用drive.mount挂载 Google Drive,路径是/content/drive/MyDrive/...。本地跑的时候相对路径不对。
解决:把所有pd.read_csv的路径改成脚本所在目录的相对路径,或者用os.path.dirname(__file__)动态获取。最省事的办法是把两个 CSV 和脚本放同一目录,直接写文件名。
4.2 现象:ModuleNotFoundError: No module named 'google.colab'
原因:脚本开头有from google.colab import drive和drive.mount('/content/drive'),本地环境没有这个模块。
解决:把这两行注释掉,同时把后续依赖/content/drive的路径全部改掉。如果脚本里有!pip install这种 Colab 魔法命令,也要删掉,改用终端安装。
4.3 现象:模型准确率异常高,超过 0.95
原因:数据泄露。常见情况是先对全量数据做了标准化或缺失值填充,再拆分训练测试集;或者特征里混入了和标签强相关的列(比如某个后验指标)。
解决:严格按「拆分 → 训练集 fit → 测试集 transform」的顺序。检查特征列,把明显是结果类的列删掉。用train_test_split的stratify参数保证分布一致。
4.4 现象:ConvergenceWarning: lbfgs failed to converge
原因:逻辑回归或 MLP 在未标准化数据上迭代不够,或者特征量纲差异太大。
解决:先做StandardScaler或MinMaxScaler,再把max_iter调到 1000 以上。如果还报,检查是否有常数列或高度共线的特征,用df.nunique()看每列唯一值数量,唯一值只有 1 的列直接删。
4.5 现象:dtreeviz导入报错或绘图空白
原因:dtreeviz 依赖 graphviz 系统库,pip 装了 Python 包但没装系统级 graphviz,或者 Jupyter 环境里字体渲染有问题。
解决:Ubuntu 下sudo apt-get install graphviz,Mac 下brew install graphviz。如果只是跑模型评估,不跑决策树可视化,可以直接跳过脚本 10 里的 dtreeviz 部分,用 sklearn 自带的plot_tree替代。
5. 进阶技巧:用 ColumnTransformer 和 Pipeline 把预处理焊死
这套代码里脚本 8Unlocking Heart Disease Secrets with Data Science.py用到了ColumnTransformer和Pipeline,这是把预处理和模型训练串成一条流水线的关键。很多人跑单个脚本没问题,但一换数据就翻车,原因就是预处理步骤散落在各处,改一个地方漏一个地方。Pipeline 的价值在于:你 fit 一次,整个预处理加模型一起拟合,预测的时候直接喂原始数据,不会出现「忘了标准化」这种低级错误。
from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler, PowerTransformer from sklearn.impute import KNNImputer from sklearn.linear_model import LogisticRegression # 假设数值列和类别列 num_cols = ['age', 'trestbps', 'chol', 'thalach', 'oldpeak'] cat_cols = ['sex', 'cp', 'fbs', 'restecg', 'exang', 'slope', 'ca', 'thal'] num_pipeline = Pipeline([ ('imputer', KNNImputer(n_neighbors=5)), ('power', PowerTransformer(method='yeo-johnson')), ('scaler', StandardScaler()) ]) cat_pipeline = Pipeline([ ('imputer', KNNImputer(n_neighbors=5)), ('scaler', StandardScaler()) ]) preprocessor = ColumnTransformer([ ('num', num_pipeline, num_cols), ('cat', cat_pipeline, cat_cols) ]) full_pipeline = Pipeline([ ('prep', preprocessor), ('clf', LogisticRegression(max_iter=1000, class_weight='balanced')) ]) full_pipeline.fit(X_train, y_train) y_pred = full_pipeline.predict(X_test)逻辑说明:KNNImputer用近邻样本填充缺失值,比均值填充更合理,但计算量大,数据量小的时候用。PowerTransformer的 yeo-johnson 方法可以把偏态分布拉成接近正态,医疗指标里胆固醇、血压经常右偏。ColumnTransformer把数值列和类别列分开处理,避免对类别列做无意义的标准化。整个 Pipeline 可以存成 pickle,部署的时候直接加载,不用重新写预处理代码。
参数说明:KNNImputer的n_neighbors默认 5,数据量小可以调到 3。PowerTransformer的method选yeo-johnson支持负值,box-cox只支持正值。class_weight='balanced'在类别不平衡时自动调整权重,医疗数据里正样本少的时候必加。
验证 Pipeline 是否生效,用交叉验证跑一遍:
from sklearn.model_selection import cross_val_score scores = cross_val_score(full_pipeline, X, y, cv=5, scoring='f1') print('Cross-val F1:', scores.mean(), '+/-', scores.std())cv=5做五折交叉验证,scoring='f1'关注 F1 分数。如果交叉验证的 F1 和单次拆分的 F1 差距很大,说明数据划分不稳定,需要增大数据量或调整分层策略。
从那以后我每次拿到新的分类数据集,都强制先搭一个 Pipeline 再调模型,哪怕只是跑个基线。因为一旦预处理和模型分离,后面换特征、换算法、换数据版本的时候,总有一个角落会漏掉标准化或者漏掉缺失值处理,然后你对着一个虚高的准确率排查半天,最后发现是测试集泄露。这套心脏病代码包里的脚本 8 已经开了个好头,你可以把它当模板,把其他脚本的模型逐个塞进 Pipeline 里对比,比单独跑脚本更接近真实工程。希望帮到你。
本文还有配套的精品资源,点击获取