基于Python的康复评估系统:从数据集到源码实战
发布时间:2026/10/20 15:26:26 锦皓数字建站

简介这份资源是面向计算机相关专业学生、教师及企业开发者的康复评估系统完整项目包适合用作毕业设计、课程设计、作业或项目初期立项演示也可供初学者进阶学习。包内共157个文件以70个csv数据表、68个bvh骨骼动作文件、11个Python源码脚本为主另含Jupyter Notebook实验记录与说明文档压缩包约16.18MB目录结构清晰便于按数据、算法与实验模块分别查阅。资源围绕康复动作数据的采集、处理与评估展开csv与bvh文件可用于动作序列分析与特征提取Python脚本则串联起评估流程的核心逻辑读者可据此理解康复评估系统的整体实现思路并在此基础上修改扩展出新的功能。目前已有260人学习下载代码经过测试运行功能正常可直接用于毕设、课设或二次开发参考。1. 康复评估系统到底在评什么从一套 Python 源码与数据集说起康复评估这件事外行看是打分内行看是「把治疗师的眼睛和手翻译成可复现的数字」。一个偏瘫患者抬手够杯子治疗师能看出他肩关节代偿、躯干旋转不足、动作启动延迟但这些判断很难量化不同治疗师给的分数能差出一大截。基于 Python 实现的康复评估系统要解决的就是这个「主观打分不可复现」的问题用摄像头或传感器采集动作数据用算法算出关节角度、动作完成度、对称性、耗时这些客观指标再映射到临床量表上。它适合两类人——做康复数字化产品的开发者以及想把手头评估流程自动化的治疗师和科研人员。标题里带源码和数据集意味着这不是纯理论而是能跑起来、能改、能拿自己数据重训的一套东西。下面我按「数据长什么样 → 指标怎么算 → 系统怎么搭 → 坑在哪」的顺序把这条路走一遍。2. 先看懂数据集康复动作数据的三种常见形态与字段含义拿到一份康复评估数据集第一件事不是急着跑模型而是搞清楚它到底记录了什么。康复场景的数据形态和通用动作识别数据集差别很大通用数据集追求动作类别多、场景杂康复数据集追求的是同一个动作在病理状态下的细微差异样本量往往很小标注却要求很细。常见的有三种形态选型时先对号入座。2.1 骨骼关键点序列最主流也最好上手的一类多数基于视觉的康复评估数据集存的是人体骨骼关键点序列。典型结构是一个 CSV 或 JSON每帧记录若干关键点的二维或三维坐标外加一个时间戳和受试者编号。常见关键点布局是 17 点或 25 点覆盖肩、肘、腕、髋、膝、踝这些评估核心关节。字段命名各家不同但逻辑一致frame_id、timestamp、joint_name、x、y、z、confidence。confidence这一列最容易被忽略它表示该关键点的检测置信度低于阈值时坐标基本是猜的直接拿去算角度会得到离谱结果。我一般会先写一段脚本做数据体检看每个受试者有多少帧、关键点缺失率多高、置信度分布如何。这一步不做后面算出来的角度全是玄学。import pandas as pd import numpy as np # 读取骨骼关键点数据假设长表结构每行一个关键点 df pd.read_csv(rehab_pose_data.csv) # 1. 每个受试者的帧数分布判断采集是否完整 frames_per_subject df.groupby(subject_id)[frame_id].nunique() print(帧数统计:\n, frames_per_subject.describe()) # 2. 关键点缺失率坐标为空或置信度过低都算缺失 df[valid] df[confidence] 0.3 missing_rate 1 - df.groupby(joint_name)[valid].mean() print(各关键点缺失率:\n, missing_rate.sort_values(ascendingFalse)) # 3. 置信度分布低于0.3的帧建议整帧丢弃而不是插值 print(置信度分位数:\n, df[confidence].quantile([0.1, 0.25, 0.5, 0.75, 0.9]))这段代码做三件事统计每个受试者的有效帧数判断采集是否被中途打断统计每个关键点的缺失率找出哪些关节在特定动作下总被遮挡看置信度分位数决定阈值卡在哪。参数上confidence阈值我一般设 0.3 作为「可用下限」0.5 以上才算「可信」。阈值设太高会丢掉大量病理动作样本设太低会把噪声当信号。缺失率超过 30% 的关键点比如腕关节在抬手动作里常被躯干挡住就要考虑换视角或换采集方案而不是硬插值。2.2 惯性传感器时序三轴加速度与角速度另一类数据集来自可穿戴惯性传感器字段是ax、ay、az、gx、gy、gz即三轴加速度和三轴角速度采样率常见 50Hz 到 100Hz。这类数据的优势是不受遮挡影响适合评估步态、平衡这类大范围动作劣势是传感器佩戴位置稍有偏移数据分布就变了跨受试者泛化差。处理时通常先做低通滤波去抖动再切窗提取时域特征均值、方差、过零率和频域特征FFT 主频。选型建议很直接评估上肢精细动作、关节角度优先骨骼关键点评估步态周期、平衡晃动优先惯性传感器。两者都有最好做多模态融合但小团队先跑通一种再说。2.3 量表标签评估系统的「标准答案」从哪来数据集里最关键的往往不是动作数据而是标签。康复评估的标签通常是临床量表得分比如 Fugl-Meyer 上肢部分、Berg 平衡量表、Barthel 指数。这些分数由治疗师人工评定是监督学习的 ground truth。这里有个血泪经验量表分数是离散的整数且分布极不均匀大量受试者集中在中间分段直接做回归会欠拟合做分类又会类别不平衡。常见做法是先做二分类如「是否达到某功能阈值」或者用有序回归ordinal regression保留等级信息。标签质量直接决定系统上限如果标签本身是两三个治疗师各打一遍取平均一致性系数低于 0.7那模型再花哨也没意义。3. 核心指标怎么算关节角度、动作完成度与对称性数据看懂了接下来是把原始坐标变成有临床意义的指标。这一步是康复评估系统的灵魂算错了后面全白搭。我按三个最常用的指标拆开讲每个都给可复现的算法和参数。3.1 关节角度用向量夹角算但别忽略坐标系关节角度本质是两个相邻骨段向量的夹角。以肘关节为例取肩、肘、腕三个关键点构造向量肘→肩和肘→腕用反余弦求夹角。听起来简单坑在坐标系二维关键点的角度会随拍摄视角变化正面拍和侧面拍算出的肘角能差 20 度以上。所以要么用三维关键点要么固定拍摄视角并在文档里写死。import numpy as np def joint_angle(p_proximal, p_joint, p_distal): 计算以 p_joint 为顶点的夹角输入为 (x, y) 或 (x, y, z) v1 np.array(p_proximal) - np.array(p_joint) v2 np.array(p_distal) - np.array(p_joint) # 防止零向量导致除零 norm np.linalg.norm(v1) * np.linalg.norm(v2) if norm 1e-6: return np.nan cos_theta np.clip(np.dot(v1, v2) / norm, -1.0, 1.0) return np.degrees(np.arccos(cos_theta)) # 示例计算肘关节角度序列 angles [] for frame in frames: angle joint_angle(frame[shoulder], frame[elbow], frame[wrist]) angles.append(angle) # 平滑处理滑动平均窗口5帧抑制关键点抖动带来的角度跳变 def smooth(seq, window5): seq np.array(seq, dtypefloat) kernel np.ones(window) / window return np.convolve(seq, kernel, modesame) angles_smooth smooth(angles, window5)joint_angle里用np.clip把余弦值卡在 [-1, 1]是因为浮点误差可能让它略微越界导致arccos返回 NaN。smooth的窗口大小是关键参数窗口太小3 帧压不住抖动窗口太大15 帧会把快速动作的峰值削平评估「动作速度」时失真。我一般用 5 帧采样率 30fps 时对应约 0.17 秒既能去抖又保留动作细节。角度序列算出来后通常还要提取峰值角度动作最大活动范围、角速度峰值附近一阶差分、到达峰值的时间这三个才是量表里真正对应的指标。3.2 动作完成度用动态时间规整对齐标准动作同一个动作不同人做的快慢、幅度都不同直接逐帧比对没意义。常见做法是用动态时间规整DTW把受试者动作序列和标准模板对齐算累积距离作为「完成度」的负向指标。距离越小动作越接近标准。标准模板可以取健康受试者多次动作的平均也可以取治疗师示范的那一次。from dtaidistance import dtw import numpy as np def completion_score(seq, template): seq 和 template 都是归一化后的角度序列 # 先做 z-score 归一化消除个体幅度差异 seq_n (seq - np.mean(seq)) / (np.std(seq) 1e-6) tpl_n (template - np.mean(template)) / (np.std(template) 1e-6) distance dtw.distance(seq_n, tpl_n) # 映射到 0-100 分距离越大分越低系数需按数据集标定 score max(0, 100 - distance * 10) return score这里dtw.distance返回的是累积对齐距离量纲取决于序列长度和归一化方式所以那个* 10的系数不能照抄必须拿一批已知量表得分的样本去标定让分数和临床评分尽量线性对应。归一化用 z-score 而不是 min-max是因为 min-max 对异常峰值太敏感一个检测跳变就能把整段序列压扁。DTW 的缺点是计算复杂度 O(N²)长序列要加 Sakoe-Chiba 带宽约束一般设带宽为序列长度的 10%。3.3 对称性左右侧对比别用简单比值评估偏瘫患者时健侧和患侧的对称性是核心指标。常见错误是直接算「患侧角度 / 健侧角度」分母接近零时结果爆炸。稳妥做法是算对称指数SI |健侧 - 患侧| / (0.5 * (健侧 患侧))取值范围 0 到 20 表示完全对称。或者用对数形式ln(健侧 / 患侧)在统计上更接近正态分布方便做组间比较。对称性通常按动作周期算比如步态里每个步态周期算一次再取多个周期的均值单次结果波动太大不可信。4. 系统怎么搭从数据加载到评估输出的最小可运行链路指标算法有了接下来把它们串成一个能跑的系统。我不建议一上来就搞微服务、搞前端先用一个 Python 包把核心链路跑通验证指标和量表的相关性再谈工程化。下面这条链路是我常用的最小结构。4.1 目录结构与模块划分一个能维护的康复评估系统目录大致这样分data/放原始数据和标注preprocess/放清洗和归一化features/放角度、DTW、对称性这些指标计算models/放量表映射模型evaluate/放验证脚本config.yaml统一管参数。关键原则是所有阈值、窗口大小、路径都进配置文件不写死在代码里。康复评估的参数经常要按科室、按病种调写死了改一次就要翻代码迟早翻车。# config.yaml 示例 preprocess: confidence_threshold: 0.3 smooth_window: 5 features: dtw_bandwidth_ratio: 0.1 symmetry_method: log # 可选 ratio / log / si model: task: ordinal # 可选 binary / ordinal / regression n_splits: 54.2 量表映射模型小样本下别硬上深度学习康复数据集普遍小几十到几百个受试者是常态。这种规模下梯度提升树如 LightGBM或带正则的线性模型往往比深度网络稳。输入特征就是前面算的角度峰值、角速度、DTW 距离、对称指数这些维度控制在 20 以内多了必然过拟合。验证必须用受试者级别的交叉划分GroupKFold不能按帧随机分否则同一个人的帧同时进训练和测试分数虚高得离谱这是新手最常踩的坑。from sklearn.model_selection import GroupKFold, cross_val_score from lightgbm import LGBMClassifier import numpy as np # X: 特征矩阵, y: 量表二分类标签, groups: 受试者ID gkf GroupKFold(n_splits5) model LGBMClassifier( n_estimators200, max_depth3, # 小样本必须浅树 learning_rate0.05, subsample0.8, colsample_bytree0.8, random_state42 ) scores cross_val_score(model, X, y, groupsgroups, cvgkf, scoringroc_auc) print(受试者级交叉验证 AUC: %.3f ± %.3f % (scores.mean(), scores.std()))max_depth3和n_estimators200是小样本的保守配置树太深必然记住训练集里的人。GroupKFold保证同一个受试者只出现在一个折里AUC 才是对新人有效的估计。如果 AUC 只有 0.6 出头先别调模型回去查标签一致性和特征是否泄漏了受试者身份信息比如某个受试者的采集设备不同特征分布整体偏移模型学的是设备不是病情。4.3 评估报告输出让治疗师看得懂才有价值系统算完指标输出不能是一堆数字。治疗师要的是「这个患者肩关节活动范围比上次提升 15 度但对称性仍差建议加强患侧主动训练」这种结论。所以报告模块要做两件事一是把本次指标和历史基线对比算变化量和变化率二是把指标映射回量表分段的语言描述。输出格式用结构化 JSON 加一份可读文本方便对接 HIS 系统或直接打印。5. 避坑与排查康复评估系统落地时最容易翻车的五件事这一章是我踩过的坑里挑出来最费时间的五条每条按现象、原因、解决写。新手照着排查能省掉大量返工。5.1 现象模型离线 AUC 很高上线后治疗师说「不准」原因几乎总是数据泄漏。最常见的是按帧随机划分数据集同一个受试者的不同帧进了训练和测试模型实际上在「认人」而不是「认病情」。另一个隐蔽来源是预处理阶段用了全局统计量做归一化测试集的均值和方差泄漏进了训练。解决所有划分按受试者分组归一化参数只在训练折上拟合再应用到验证折。上线前拿一批完全没参与训练的新受试者做一次盲测AUC 掉 0.1 以上就说明泄漏没清干净。5.2 现象关节角度在某些帧突然跳到 180 度原因是关键点检测在遮挡时把左右侧搞反了或者置信度骤降导致坐标乱飞。解决先按置信度过滤低于阈值的帧标记为无效而不是插值再做左右侧一致性检查如果某一帧左肩和右肩的 x 坐标顺序和前后帧相反判定为翻转并丢弃。别用插值硬补补出来的角度会污染峰值统计。5.3 现象DTW 完成度分数和临床评分几乎不相关原因通常是没做幅度归一化或者标准模板选得不对。如果模板取自健康人而受试者是病理动作两者时间尺度差异大DTW 对齐后距离仍然很大分数全挤在低位。解决模板按病种和严重程度分层每层一个模板归一化用 z-score 而非 min-maxDTW 加带宽约束避免过度扭曲对齐。标定阶段画散点图看分数和量表分的相关性皮尔逊系数低于 0.5 就回去改特征。5.4 现象对称性指数出现无穷大或负值原因是分母接近零或者健侧患侧标反了。解决改用对称指数公式|健-患| / (0.5*(健患))天然有界在数据加载阶段强制校验健侧患侧标签用配置文件写死哪侧是患侧不靠字段名猜。出现异常值时记录受试者 ID 和帧号回溯原始数据多半是标签录入错误。5.5 现象换一台摄像头或换一个采集房间指标整体偏移原因是关键点检测模型对视角、光照、背景敏感坐标尺度变了角度虽然理论上与尺度无关但检测精度下降会系统性影响角度。解决采集协议里固定摄像头高度、距离、角度用同一套标定流程上线前做一次跨设备校准让同一受试者在两套设备下各做一次动作比较指标差异差异超过临床最小可检测变化MDC就要重新标定。MDC 这个值必须查对应量表的文献不能拍脑袋定。6. 进阶技巧用少量标注做半监督把数据集榨干康复数据标注贵一个受试者的量表评分要治疗师花二三十分钟所以标注样本永远不够。我最后分享一个实际用过的技巧半监督自训练加一致性正则能在标注样本只有几十个时把 AUC 再抬几个点。思路是先用标注数据训一个初始模型对未标注数据预测伪标签只保留高置信度的样本加入训练集迭代两三轮。关键是每轮都要在受试者级别的验证集上确认没退化一旦退化立刻停。import numpy as np from sklearn.metrics import roc_auc_score def self_training(model, X_labeled, y_labeled, X_unlabeled, X_val, y_val, rounds3, threshold0.9): best_auc 0 best_model None for r in range(rounds): model.fit(X_labeled, y_labeled) # 验证集监控退化就停 val_prob model.predict_proba(X_val)[:, 1] auc roc_auc_score(y_val, val_prob) print(第 %d 轮验证 AUC: %.3f % (r 1, auc)) if auc best_auc: print(验证退化回退到上一轮模型) return best_model best_auc, best_model auc, model # 对未标注数据打伪标签只取高置信度 prob model.predict_proba(X_unlabeled)[:, 1] confident (prob threshold) | (prob 1 - threshold) pseudo_X X_unlabeled[confident] pseudo_y (prob[confident] 0.5).astype(int) if len(pseudo_X) 0: break X_labeled np.vstack([X_labeled, pseudo_X]) y_labeled np.concatenate([y_labeled, pseudo_y]) return best_modelthreshold0.9是伪标签的置信度门槛设低了会把噪声引进训练集设高了几乎选不出样本我一般从 0.9 起调。每轮必须用独立的受试者验证集监控这是后悔药——没有它自训练很容易在第二轮就开始自我强化错误。另外伪标签样本的权重可以调低比如 0.5让真实标注主导梯度。这套方法在标注样本少于 100 时收益最明显超过几百个标注后提升就有限了别指望它替代标注。我自己的习惯是任何康复评估模型上线前一定找两位治疗师对同一批新数据独立打分算一致性系数只有系统输出和他们的共识相关性达标才敢放到临床流程里。算法再漂亮过不了治疗师这一关就是自嗨。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。