151-基于Python的心衰疾病数据可视化分析系统

发布于:2025-08-19 ⋅ 阅读:(19) ⋅ 点赞:(0)

心衰疾病数据可视化分析系统:从数据到洞察的端到端实践

面向医学数据入门与可视化分析的完整示例项目,覆盖用户认证、数据管理、统计分析到前端可视化展示的端到端流程。本文将从目录结构、技术栈、数据库设计、核心功能与代码、可视化方案、部署与快速开始等方面进行全面说明,并提供可直接复用的代码片段与可视化占位。


功能总览

  • 用户与账号管理
    • 注册、登录、登出
    • 个人资料编辑、修改密码
    • 用户列表分页与搜索、编辑、删除
  • 心衰病例数据管理
    • 病例列表分页与多字段搜索
    • 新增、编辑、删除
  • 首页与统计看板
    • 用户总数、病例总数、死亡事件数、平均年龄等指标
  • 数据可视化分析
    • 年龄分布、性别占比、死亡事件分析
    • 健康状况统计(高血压、糖尿病、贫血、吸烟)
    • 射血分数、血小板、血清钠/肌酐、随访时间分布
    • 生存曲线(Kaplan-Meier)
    • 斯皮尔曼相关矩阵
    • 混淆矩阵、特征重要性(基于随机森林+过采样)

项目目录结构

code/
  app.py
  manage.py
  config.py
  ext.py
  models.py
  dependency.txt
  blueprints/
    index.py
    chart.py
    data.py
  model/
    __init__.py
    check_login.py
    check_regist.py
  util/
    analyze.py
    insert.py
    heart_failure_clinical_records.csv
  templates/
    base.html
    index.html
    login.html
    register.html
    edit_profile.html
    change_password.html
    user_list.html
    heart_failure_list.html
    age_distribution.html
    sex_distribution.html
    death_event_distribution.html
    condition_distribution.html
    cpk_distribution.html
    ejection_fraction_distribution.html
    platelets_distribution.html
    serum_sodium_distribution.html
    serum_creatinine_distribution.html
    follow_up_time_distribution.html
    survival_curve.html
    spearman_correlation.html
    confusion_matrix_view.html
    feature_importance.html
  static/
    ...(前端资源:CSS/JS/图片/字体)

技术栈

  • 后端
    • Flask 3、Blueprints 分模块(app.py + blueprints/*
    • Flask-SQLAlchemy(ORM)、Flask-Migrate(迁移)、Flask-WTF(表单)
    • Flask-CORS、Flask-Mail、Werkzeug(密码哈希)
    • 数据分析/建模:pandas、numpy、scikit-learn、imbalanced-learn、lifelines
  • 前端
    • Jinja2 模板
    • Bootstrap 4、jQuery
    • ECharts(主要图表)
  • 数据库
    • MySQL(config.py 统一配置)

依赖示例(节选自 dependency.txt):

pip install flask==3.0.0
pip install flask-migrate==4.0.4
pip install flask-sqlalchemy==3.0.3
pip install flask-wtf==1.2.1
pip install pandas==1.1.5
pip install lifeline
pip install imbalanced-learn

项目演示

🦀 项目源码获取,码界筑梦坊各平台同名,博客底部含联系方式卡片,欢迎咨询!

基于Python的心衰疾病数据可视化分析系统

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

数据库与模型

模型定义(models.py):

class User(db.Model):
    __tablename__ = "user"
    id = db.Column("id", db.Integer, primary_key=True)
    username = db.Column(db.String(255), nullable=False, unique=True)
    password = db.Column(db.String(255), nullable=False)
    email = db.Column(db.String(255), nullable=False, unique=True)
    phone = db.Column(db.String(20), nullable=False)
    location = db.Column(db.String(255), nullable=False)
    image = db.Column(db.String(255))
    gender = db.Column(db.String(10), nullable=False)
    birthday = db.Column(db.Date)
    registration_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
    last_login_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)
    reset_token = db.Column(db.String(20))

class HeartFailure(db.Model):
    __tablename__ = 'heart_failure'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    age = db.Column(db.Integer)
    anaemia = db.Column(db.Boolean)
    high_blood_pressure = db.Column(db.Boolean)
    creatinine_phosphokinase = db.Column(db.Float)
    diabetes = db.Column(db.Boolean)
    ejection_fraction = db.Column(db.Integer)
    sex = db.Column(db.Boolean)
    platelets = db.Column(db.Float)
    serum_creatinine = db.Column(db.Float)
    serum_sodium = db.Column(db.Integer)
    smoking = db.Column(db.Boolean)
    time = db.Column(db.Integer)
    death_event = db.Column(db.Boolean)

数据库配置(config.py):

HOSTNAME = 'localhost'
DATABASE = 'design_151_heart'
PORT = 3306
USERNAME = 'root'
PASSWORD = '123456'
DB_URL = f'mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}'

SQLALCHEMY_DATABASE_URI = DB_URL
SQLALCHEMY_TRACK_MODIFICATIONS = False

核心功能与关键代码

1) 用户认证与账户管理(app.py

登录/注册/登出/资料与密码修改:

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        if is_null(username, password):
            return render_template('login.html', message="账号和密码是必填")
        elif is_existed(username, password):
            session['username'] = username
            return redirect(url_for('index.index', username=username))
        elif exist_user(username):
            return render_template('login.html', message="密码错误")
        else:
            return render_template('login.html', message="不存在该用户")
    return render_template('login.html')

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        # 参数略...
        add_user(username, password, email, phone, location, image, gender, birthday)
        return render_template('register.html', message="注册成功,请前往登录")
    return render_template('register.html')

@app.route('/logout')
def logout():
    session.pop('username', None)
    return redirect(url_for('login'))

密码安全说明:使用 werkzeug.securitygenerate_password_hashcheck_password_hash 进行密码哈希与验证。

2) 数据看板与指标(blueprints/index.py
def get_average_age():
    return int(db.session.query(db.func.avg(HeartFailure.age)).scalar())

def count_death_events():
    return db.session.query(db.func.count(HeartFailure.id))\
             .filter(HeartFailure.death_event == 1).scalar()

@bp.route('/')
def index():
    user_count = User.query.count()
    rank_count = HeartFailure.query.count()
    issuance_count = count_death_events()
    type_count = get_average_age()
    return render_template('index.html', ...)
3) 病例与用户管理(blueprints/data.py

分页与多字段搜索:

@bp.route('/heart_failure_list')
def heart_failure_list():
    search_term = request.args.get('search', '')
    query = HeartFailure.query
    if search_term:
        query = query.filter(
            (HeartFailure.age.like(f'%{search_term}%')) |
            (HeartFailure.sex.like(f'%{search_term}%')) |
            (HeartFailure.death_event.like(f'%{search_term}%')) |
            (HeartFailure.anaemia.like(f'%{search_term}%')) |
            (HeartFailure.high_blood_pressure.like(f'%{search_term}%')) |
            (HeartFailure.creatinine_phosphokinase.like(f'%{search_term}%')) |
            (HeartFailure.diabetes.like(f'%{search_term}%')) |
            (HeartFailure.ejection_fraction.like(f'%{search_term}%')) |
            (HeartFailure.platelets.like(f'%{search_term}%')) |
            (HeartFailure.serum_creatinine.like(f'%{search_term}%')) |
            (HeartFailure.serum_sodium.like(f'%{search_term}%')) |
            (HeartFailure.smoking.like(f'%{search_term}%')) |
            (HeartFailure.time.like(f'%{search_term}%'))
        )
    page = request.args.get('page', 1, type=int)
    heart_failures = query.paginate(page=page, per_page=10, error_out=False)
    return render_template('heart_failure_list.html', heart_failures=heart_failures, search_term=search_term)

用户列表分页与搜索、用户新增/编辑/删除接口均已实现,示例请见 blueprints/data.py

4) 数据分析辅助(util/analyze.py

典型统计函数:

def get_age_distribution():
    heart_failures = db.session.query(HeartFailure).all()
    ages = [hf.age for hf in heart_failures]
    df = pd.DataFrame({'age': ages})
    return {"average_age": df['age'].mean(), "data": df['age'].value_counts().to_dict()}

def get_death_event_counts():
    return {
        "death_count": db.session.query(HeartFailure).filter_by(death_event=True).count(),
        "survival_count": db.session.query(HeartFailure).filter_by(death_event=False).count()
    }
5) 可视化接口(blueprints/chart.py
  • 生存曲线(Kaplan-Meier):
@bp.route('/survival-curve')
def survival_curve():
    data = db.session.query(HeartFailure.time, HeartFailure.death_event).all()
    df = pd.DataFrame(data, columns=['time', 'death_event'])
    kmf = KaplanMeierFitter()
    kmf.fit(durations=df['time'], event_observed=df['death_event'])
    survival = kmf.survival_function_.reset_index()
    survival_data = survival[['timeline', 'KM_estimate']].values.tolist()
    return render_template('survival_curve.html', survival_data=survival_data)
  • 斯皮尔曼相关矩阵:
@bp.route('/spearman-correlation')
def spearman_correlation():
    data = db.session.query( ... HeartFailure.death_event ).all()
    columns = ['年龄','贫血','高血压','肌酸激酶','糖尿病','射血分数','性别','血小板','血清肌酐','血清钠','吸烟','时间','死亡事件']
    df = pd.DataFrame(data, columns=columns)
    corr = df.corr(method='spearman')
    return render_template('spearman_correlation.html',
                           correlation_matrix=corr.values.tolist(),
                           correlation_labels=corr.columns.tolist())
  • 混淆矩阵与特征重要性(过采样 + 随机森林):
oversampler = RandomOverSampler()
rf = RandomForestClassifier(random_state=15)
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=15)
x_train, y_train = oversampler.fit_resample(x_train, y_train)
rf.fit(x_train, y_train)
cm = confusion_matrix(y_test, rf.predict(x_test)).tolist()
importance = rf.feature_importances_

前端可视化占位(ECharts 示例)

可视化模板位于 templates/*_distribution.htmlsurvival_curve.htmlspearman_correlation.html 等。以下为一个可直接复用的 ECharts 占位示例:

<div id="chart" style="width:100%;height:420px;"></div>
<script src="/static/js/echarts.min.js"></script>
<script>
  const chart = echarts.init(document.getElementById('chart'));
  const option = {
    title: { text: '示例-年龄分布' },
    tooltip: {},
    xAxis: { type: 'category', data: Object.keys({{ age_data['data']|tojson }}) },
    yAxis: { type: 'value' },
    series: [{ type: 'bar', data: Object.values({{ age_data['data']|tojson }}) }]
  };
  chart.setOption(option);
  window.addEventListener('resize', () => chart.resize());
</script>

可在对应模板中替换 title 与数据变量,即可快速预览。


系统架构(Mermaid)

ORM
Analysis
Browser: Bootstrap + jQuery + ECharts
Flask App: app.py + Blueprints
Flask-SQLAlchemy
pandas / numpy / sklearn / imbalanced-learn / lifelines
MySQL

快速开始

  1. 环境与依赖
python -m venv venv
venv\Scripts\activate  # Windows
pip install -r dependency.txt  # 或逐条安装依赖
  1. 数据库配置
  • 创建 MySQL 数据库:design_151_heart
  • 修改 config.py 中的连接信息(用户名/密码/端口)
  1. 导入示例数据(可选)
python util/insert.py
  1. 启动项目
python app.py
# 访问 http://127.0.0.1:5000

路由速览

  • 认证与账号:
    • GET/POST /login 登录
    • GET/POST /register 注册
    • GET /logout 登出
    • GET/POST /edit_profile 编辑资料
    • GET/POST /change_password 修改密码
    • GET/POST /request_reset_password 重置请求,GET/POST /reset_password/<token> 重置密码
  • 总览与图表入口:
    • GET /(登录后)
    • GET /chart/(登录后)
  • 可视化分析(节选):
    • /chart/age_distribution/chart/sex_distribution/chart/death_event_distribution
    • /chart/condition_distribution/chart/cpk_distribution/chart/ejection_fraction_distribution
    • /chart/platelets_distribution/chart/serum_sodium_distribution/chart/serum_creatinine_distribution
    • /chart/follow_up_time_distribution/chart/survival-curve/chart/spearman-correlation
    • /chart/confusion_matrix_view/chart/feature-importance
  • 数据管理:
    • GET /data/user_list(分页、搜索)、POST /data/add_userPOST /data/edit_user<int:id>POST /data/delete_user<int:id>
    • GET /data/heart_failure_list(分页、搜索)、POST /data/add_heart_failurePOST /data/edit_heart_failure<int:id>POST /data/delete_heart_failure<int:id>

部署建议

  • 使用 waitress/gunicorn 等 WSGI 服务配合 Nginx 反向代理
  • 配置 MySQL 生产库与只读账号,启用慢查询日志
  • 开启 SECRET_KEY 与 CSRF 保护(Flask-WTF)
  • 日志与监控:接入 logging、反向代理访问日志与指标

FAQ(选摘)

  • 看不到图表?
    • 确认登录态是否存在;模板依赖的 static/ 资源路径是否正确;浏览器控制台是否报错
  • 数据为空?
    • 导入 util/insert.py 或自行写入病例数据;检查数据库连接配置

许可与贡献

  • 许可:开源学习用途(可按自身需求调整 License)
  • 贡献:欢迎提交 PR/Issue 以完善分析方法与可视化效果

联系方式

码界筑梦坊各大平台同名


网站公告

今日签到

点亮在社区的每一天
去签到