尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

心脏病预测源码实战:逻辑回归与PHP调用Python模型

心脏病预测源码实战:逻辑回归与PHP调用Python模型 简介这份资源是面向机器学习与Web开发初学者的实战案例包围绕逻辑回归二分类算法构建心脏病预测模型帮助读者理解从数据处理到模型部署的完整链路。包内共8个文件以xml配置、csv数据集、py脚本和md说明为主另有iml工程文件压缩包约7KB体量轻便便于快速解压研读。已有245人学习下载适合希望将Python模型集成到PHP网页应用中的开发者参考。案例中Python侧负责数据清洗、特征缩放、模型训练与准确率等指标评估PHP侧则承担用户界面与前后端交互把预测结果返回给使用者预测正确率超过84%。通过分析数据文件与模型脚本读者可掌握逻辑回归的sigmoid原理、超参数选择与交叉验证思路并借鉴前后端调用方式完成一次从算法到Web落地的完整实践。1. 从一份 84% 准确率的心脏病预测源码说起一份标称预测准确率超过 84% 的心脏病预测源码包技术栈是 Python 做逻辑回归二分类、PHP 做 Web 界面这个组合在课程设计和入门级落地项目里其实相当典型。很多人第一次拿到这类压缩包第一反应是「逻辑回归这么简单的东西能有什么好看的」但真正拆开跑一遍就会发现坑不在算法本身而在数据清洗、前后端数据格式对齐、以及 PHP 调用 Python 的那一层胶水代码上。这份资源适合三类人想找一个完整二分类项目练手的 Python 初学者、需要把模型塞进 Web 页面给非技术人员用的开发者、以及正在做数据挖掘课程作业、需要一个能跑通全流程参考实现的学生。它不追求 SOTA 指标追求的是「从 CSV 到网页预测结果」这条链路完整可复现这一点比很多只丢一个 notebook 的项目实在得多。2. 逻辑回归做心脏病二分类数据、特征与训练链路2.1 为什么心脏病预测适合用逻辑回归而不是别的心脏病预测本质上是一个二分类问题给定一组医疗指标判断患者是否患病。逻辑回归的输出经过 sigmoid 函数压缩到 0 到 1 之间天然就是一个概率值这对医疗场景很友好——医生不只需要「是/否」还需要知道「有多大可能是」。相比决策树容易过拟合、SVM 在小数据集上调参麻烦逻辑回归在几百到几千条样本的表格数据上表现稳定系数还能直接解释特征影响方向这在课程答辩或者给非技术同事讲结果时是实打实的优势。这份源码用的 heart.csv 是典型的表格型医疗数据特征一般包括年龄、性别、胸痛类型、静息血压、胆固醇、空腹血糖、最大心率、运动诱发心绞痛等。逻辑回归的假设是特征与对数几率呈线性关系所以连续特征年龄、血压、胆固醇和类别特征性别、胸痛类型需要区别对待。源码里 Python 部分大概率用 scikit-learn 的 LogisticRegression配合 StandardScaler 做特征缩放因为逻辑回归对特征尺度敏感——血压数值在 100 到 200 之间而性别是 0/1不缩放的话梯度下降会震荡得厉害。2.2 数据预处理缺失值、异常值和特征缩放拿到 heart.csv 之后第一步不是直接喂模型而是先看清楚数据长什么样。常见做法是用 pandas 做一轮体检import pandas as pd import numpy as np # 读取数据先看基本信息和缺失情况 df pd.read_csv(data/heart.csv) print(df.shape) # 行列数 print(df.isnull().sum()) # 每列缺失值数量 print(df[target].value_counts()) # 标签分布检查是否严重不平衡 # 连续特征做描述性统计找异常值 print(df[[age, trestbps, chol, thalach]].describe()) # 简单异常值处理胆固醇为 0 或血压为 0 的样本通常是录入错误 df df[df[chol] 0] df df[df[trestbps] 0]这段代码的逻辑是先摸清数据规模和缺失情况再针对医疗数据里常见的「0 值异常」做过滤。参数上df.isnull().sum()返回每列缺失数量如果某列缺失超过 20%就要考虑填充还是丢弃describe()给出的 min 和 max 能帮你快速定位不合理值。注意过滤异常值之后要重新检查样本量别把数据删得太狠导致训练集不够。特征缩放用 StandardScaler 或者 MinMaxScaler 都行前者适合梯度下降后者适合需要固定范围的场景。我一般会先划分训练集和测试集再缩放避免数据泄漏from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler X df.drop(target, axis1) y df[target] # 先划分再在训练集上 fit scaler测试集只 transform X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test)stratifyy保证训练集和测试集的标签比例一致这在医疗数据里很重要否则可能测试集里正样本特别少准确率虚高。random_state42是为了结果可复现换个数结果会变但不会差太多。2.3 模型训练、评估与 84% 准确率的来源训练逻辑回归的核心代码很短但评估不能只看准确率from sklearn.linear_model import LogisticRegression from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score # C 是正则化强度的倒数越小正则化越强 model LogisticRegression(C1.0, max_iter1000, solverlbfgs) model.fit(X_train_scaled, y_train) y_pred model.predict(X_test_scaled) y_prob model.predict_proba(X_test_scaled)[:, 1] print(Accuracy:, accuracy_score(y_test, y_pred)) print(Precision:, precision_score(y_test, y_pred)) print(Recall:, recall_score(y_test, y_pred)) print(F1:, f1_score(y_test, y_pred)) print(AUC:, roc_auc_score(y_test, y_prob))C1.0是默认值调小比如 0.1 会增强正则化防止过拟合max_iter1000是防止默认迭代次数不够导致不收敛警告。84% 的准确率在心脏病数据集上属于正常水平但要注意如果正负样本比例是 6:4 左右一个全预测为正的模型也能有 60% 准确率所以必须看 recall 和 AUC。医疗场景下 recall 往往比 precision 更重要漏诊的代价比误诊大。评估之后可以把模型和 scaler 一起保存供 PHP 调用import joblib joblib.dump(model, model/logistic_model.pkl) joblib.dump(scaler, model/scaler.pkl)保存成 pkl 文件是为了后面 PHP 通过 Python 脚本加载时不用重新训练直接推理。3. PHP 调用 Python 模型接口层怎么搭才不翻车3.1 PHP 和 Python 的三种对接方式及选型PHP 本身不能直接跑逻辑回归所以必须通过某种方式调用 Python。常见做法有三种一是 PHP 用exec()或shell_exec()直接执行 Python 脚本把用户输入当参数传进去Python 输出 JSON 结果二是 PHP 用 cURL 请求一个独立的 Python Flask/FastAPI 服务三是用消息队列异步处理。这份源码大概率用的是第一种因为简单、不需要额外起服务适合课程设计和小型部署。exec()方式的优点是部署简单PHP 和 Python 在同一台机器上就行缺点是每次请求都要启动 Python 解释器并发高了会慢而且输入参数需要严格转义否则有命令注入风险。cURL 方式适合模型服务独立部署的场景但要多维护一个进程。选哪种取决于你的使用场景如果只是本地演示或者低并发内部工具exec()够用如果要给多人同时用建议走 HTTP 接口。3.2 用 exec() 打通 PHP 到 Python 的推理链路先写一个 Python 推理脚本接收命令行参数输出 JSON# predict.py import sys import json import joblib import numpy as np # 加载训练好的模型和 scaler model joblib.load(model/logistic_model.pkl) scaler joblib.load(model/scaler.pkl) # 从命令行参数读取特征值顺序要和训练时一致 features [float(x) for x in sys.argv[1:]] features np.array(features).reshape(1, -1) features_scaled scaler.transform(features) prob model.predict_proba(features_scaled)[0][1] result { probability: round(prob, 4), prediction: int(prob 0.5) } print(json.dumps(result))PHP 端这样调用?php // 接收表单提交的特征值做基本校验 $features [ floatval($_POST[age]), floatval($_POST[sex]), floatval($_POST[cp]), // ... 其他特征 ]; // 转义参数防止命令注入 $args implode( , array_map(escapeshellarg, $features)); $cmd python3 predict.py . $args; $output shell_exec($cmd); $result json_decode($output, true); if ($result null) { echo json_encode([error 模型调用失败]); } else { echo json_encode($result); } ?escapeshellarg是必须的它会把每个参数用单引号包起来防止用户输入; rm -rf这种恶意内容。shell_exec返回的是字符串用json_decode转成数组再返回给前端。注意 Python 脚本里的特征顺序必须和训练时X的列顺序完全一致否则 scaler 和模型都会算错。3.3 前端表单与结果展示的最小实现前端不需要太复杂一个 HTML 表单加一段 JavaScript 就行form idpredictForm input typenumber nameage placeholder年龄 required select namesex option value1男/option option value0女/option /select !-- 其他字段省略 -- button typesubmit预测/button /form div idresult/div script document.getElementById(predictForm).addEventListener(submit, async function(e) { e.preventDefault(); const formData new FormData(this); const resp await fetch(predict.php, { method: POST, body: formData }); const data await resp.json(); document.getElementById(result).innerText 患病概率 (data.probability * 100).toFixed(2) %; }); /script这段代码用 fetch 提交表单拿到 JSON 后把概率显示出来。注意 PHP 返回的 probability 是 0 到 1 之间的小数前端乘以 100 显示成百分比更直观。4. 避坑与排查这份源码跑不起来时先看这几条4.1 现象Python 脚本单独跑正常PHP 调用返回空原因通常是 PHP 执行环境的工作目录和 Python 脚本里的相对路径不一致。joblib.load(model/logistic_model.pkl)是相对路径PHP 的shell_exec默认工作目录可能是/var/www/html而不是脚本所在目录。解决在 Python 脚本里用绝对路径或者在 PHP 里先chdir()到脚本目录import os BASE_DIR os.path.dirname(os.path.abspath(__file__)) model joblib.load(os.path.join(BASE_DIR, model, logistic_model.pkl))4.2 现象预测结果每次都不一样或者概率明显不合理原因一般是特征顺序错位或者 scaler 没有正确加载。训练时X的列顺序是固定的如果 PHP 传参顺序和训练时不一致scaler 会把年龄当成性别来缩放结果自然离谱。解决在 Python 脚本里显式定义特征顺序并在 PHP 端按同样顺序组装参数。可以在 README 里写清楚每个位置对应哪个特征或者改成用 JSON 传参、Python 端按 key 取值减少顺序依赖。4.3 现象准确率只有 60% 多达不到标称的 84%原因可能是数据没有做异常值过滤或者训练集测试集划分时没有 stratify导致测试集分布偏移。另外如果 heart.csv 本身有重复行也会影响评估。解决先跑一遍df.duplicated().sum()看有没有重复有就去重再检查value_counts()确认标签比例最后确认 scaler 是在训练集上 fit 的不是在全量数据上 fit 的。4.4 现象PHP 页面提交后报 500 错误日志显示 python3 找不到原因Web 服务器运行用户如 www-data的 PATH 环境变量里没有 python3或者 Python 依赖没有装在这个用户下。解决在 PHP 里用 Python 的绝对路径比如/usr/bin/python3同时确认joblib、scikit-learn、numpy这些库在对应 Python 环境下都装了。可以用sudo -u www-data /usr/bin/python3 -c import sklearn测试。4.5 现象并发请求时预测变慢甚至超时原因每次请求都启动一个 Python 进程加载模型和 scaler 需要时间并发高了 CPU 扛不住。解决如果只是演示可以接受如果要优化把模型加载改成常驻内存的 HTTP 服务PHP 用 cURL 调用这样模型只加载一次。或者用 PHP 的缓存机制把相同输入的预测结果缓存起来。5. 进阶技巧把模型推理从 exec 改成常驻服务exec()方式在课程设计里够用但如果你想让这个心脏病预测页面稍微像样一点建议把 Python 推理改成 Flask 常驻服务。这样 PHP 只负责转发请求模型加载一次就一直在内存里响应速度会快很多。先写一个最小的 Flask 接口# app.py from flask import Flask, request, jsonify import joblib import numpy as np app Flask(__name__) model joblib.load(model/logistic_model.pkl) scaler joblib.load(model/scaler.pkl) app.route(/predict, methods[POST]) def predict(): data request.get_json() features np.array(data[features]).reshape(1, -1) features_scaled scaler.transform(features) prob model.predict_proba(features_scaled)[0][1] return jsonify({ probability: round(prob, 4), prediction: int(prob 0.5) }) if __name__ __main__: app.run(host127.0.0.1, port5000)PHP 端改成 cURL 调用?php $payload json_encode([features $features]); $ch curl_init(http://127.0.0.1:5000/predict); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); curl_setopt($ch, CURLOPT_HTTPHEADER, [Content-Type: application/json]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response curl_exec($ch); curl_close($ch); echo $response; ?这样改完之后模型只在 Flask 启动时加载一次后续请求都是内存推理延迟从几百毫秒降到几毫秒。注意 Flask 默认是单线程的如果要处理并发可以用 gunicorn 起多个 worker但模型内存会翻倍小机器上要权衡。验证服务是否正常可以用 curl 直接测curl -X POST http://127.0.0.1:5000/predict \ -H Content-Type: application/json \ -d {features: [55, 1, 2, 130, 250, 0, 1, 150, 0, 1.5, 2, 0, 2]}返回的 JSON 里 probability 应该在 0 到 1 之间prediction 是 0 或 1。如果返回 500先看 Flask 控制台的报错大概率是特征数量对不上——训练时用了 13 个特征你只传了 12 个reshape 就会失败。还有一个容易忽略的点Flask 服务默认只监听 127.0.0.1如果 PHP 和 Python 不在同一台机器上需要改成0.0.0.0并配置防火墙规则。但生产环境不建议直接暴露 Flask 开发服务器应该用 gunicorn 或 uWSGI 加 Nginx 反向代理。从那以后我每次拿到这种前后端加模型的源码包都会先把 Python 部分单独跑通、确认模型文件能加载、再测 PHP 调用链路最后才看前端页面。顺序反了的话出了问题根本分不清是模型错了还是接口错了。希望帮到你。本文还有配套的精品资源点击获取
返回列表