1. 项目概述在神经退行性疾病的研究与临床实践中早期识别是延缓疾病进展、改善患者预后的关键。其中快速眼动睡眠行为障碍RBD因其与帕金森病、路易体痴呆等α-突触核蛋白病的强关联性已成为一个极具价值的早期生物标志物。然而诊断RBD的“金标准”——视频多导睡眠图vPSG——因其高昂的设备成本、复杂的操作流程和对专业人员的依赖难以在社区筛查或长期监测中大规模应用。临床问卷虽然简便但其主观性强准确性有限。因此寻找一种客观、可量化、可扩展且成本可控的筛查工具成为了领域内一个迫切的需求。近年来随着可穿戴设备的普及腕动仪Actigraphy因其无创、连续监测和成本低廉的特点在睡眠研究和运动障碍评估中展现出巨大潜力。它通过记录手腕的加速度数据能够捕捉到夜间异常的运动模式理论上非常适合用于RBD的筛查。但早期的研究多依赖于人工提取的简单特征如总活动量或单一队列的模型其结果的稳定性和在不同设备、不同人群中的泛化能力一直是个问号。这背后是数据异质性带来的巨大挑战不同品牌的设备其传感器特性、采样精度、佩戴方式各异直接使用原始数据训练模型无异于“盲人摸象”。正是在这样的背景下我们开发了ActiTect。它不仅仅是一个机器学习模型更是一个完整的、面向工程化部署的解决方案。其核心设计哲学是“先标准化再智能化”。我们首先构建了一个强大的数据预处理模块旨在将来自不同设备、不同中心的“五花八门”的原始加速度数据转化为干净、一致、具有可比性的信号。在此基础上我们才引入机器学习模型从标准化的数据中提取与RBD病理生理相关的复杂运动特征。更重要的是我们从一开始就采用了多中心数据集进行训练和验证确保模型学到的不是某个特定数据集的“ idiosyncrasy”特质而是RBD本身的核心生物信号。最终我们将整个流程打包成一个开源工具希望它能成为一个“即插即用”的基石推动基于可穿戴设备的RBD筛查从实验室走向更广阔的应用场景。2. 核心设计思路与工程挑战开发一个具有临床实用价值的RBD筛查工具远不止是调优一个分类算法那么简单。它需要系统性地解决从数据采集到结果输出的全链路问题。ActiTect的设计正是围绕这些核心工程挑战展开的。2.1 核心挑战数据异质性与模型泛化腕动仪数据用于机器学习面临的首要也是最大的挑战就是数据的异质性。这种异质性来源于多个层面设备层面不同厂商如Axivity, GENEActiv, ActiGraph的传感器在灵敏度、量程、噪声特性和坐标系定义上存在差异。即使采样率都设为100Hz原始加速度值的分布也可能天差地别。受试者层面佩戴松紧度、手腕粗细、主导手左/右等因素会影响信号的基线水平和动态范围。采集协议层面各研究中心可能采用不同的佩戴时长如5天 vs 7天、不同的起始时间甚至不同的数据导出格式。如果直接将原始数据喂给模型模型很可能会学到这些与疾病无关的“伪特征”例如某个品牌设备特有的噪声模式从而导致在训练集上表现优异但应用到新设备或新中心的数据时性能急剧下降。这就是机器学习中经典的“过拟合”问题在医疗跨中心应用中尤为致命。2.2 ActiTect的解决方案标准化预处理管道为了解决上述问题ActiTect将重心前置设计了一个鲁棒的、自动化的预处理管道。这个管道的目标是将所有输入数据“拉”到同一个度量空间其流程主要包括以下几个关键步骤它们共同作用为后续的特征提取和模型推理奠定了可靠的基础。2.2.1 重采样与时钟漂移校正腕动仪内置的时钟晶振并非绝对精确会产生微小的漂移。长时间如连续7天记录后累积的漂移可能达到数秒甚至数十秒。这对于需要精确计算事件频率和时域特征的分析来说是致命的。我们的管道首先检测并校正这种漂移通过插值将信号重新对齐到绝对时间轴上确保不同记录之间的时间尺度一致。2.2.2 自动校准从“歪斜”的数据到“标准球体”这是预处理中最关键的一步。理想的加速度计在静止时三轴矢量和应等于重力加速度1g。但由于制造公差和佩戴角度实际数据点会偏离这个“单位球体”。我们实现了van Hees等人提出的自动校准算法。其原理是识别出低活动期通常为睡眠中相对静止的时段计算这些点与理论球体的偏差然后通过加权最小二乘回归迭代求解出每个轴的增益Gain和偏移Offset校正参数。经过校准后数据被“拉回”以重力加速度为基准的物理空间。如图2b所示这一步骤能将平均校准误差从几十毫克大幅降低至约3毫克显著提升了数据的物理一致性和可比性。2.2.3 带通滤波聚焦生理相关频段原始加速度信号包含各种噪声如设备本身的电子噪声、日常活动产生的高频抖动等。RBD相关的异常运动有其特定的频域特征。我们应用了一个0.8-20 Hz的带通滤波器。选择0.8 Hz作为下限是为了滤除由身体翻身等缓慢移动产生的低频成分而20 Hz的上限则能有效去除高频噪声同时保留快速、爆发性动作的信号。如图2c所示滤波后目标频段外的噪声被显著抑制而频段内的信号功率得以保留为后续特征提取提供了更“干净”的输入。2.2.4 自动化睡眠窗口与非佩戴期检测在无PSG的居家监测场景中确定“睡眠期”是计算夜间运动特征的前提。依赖患者手写的睡眠日记不仅增加负担而且存在回忆偏差和不准确性。ActiTect集成了HDCZA算法这是一种基于活动计数和零交叉分析的启发式算法能够从多日的活动数据中自动识别出最可能的睡眠起始和结束时间。我们将算法结果与睡眠日记及PSG金标准进行对比验证图2d结果显示其相关性极高Pearson r 0.99平均绝对误差在35分钟左右。虽然存在轻微低估睡眠时长的倾向但这对于RBD筛查而言可能是有益的因为它减少了将清醒期活动误判为异常睡眠运动的可能性。同时管道还能自动检测设备未被佩戴的时段非佩戴期并在分析中排除这些无效数据进一步保证了数据质量。实操心得预处理管道的每个步骤都至关重要且顺序不能随意调换。例如必须先进行重采样和校准再进行滤波和睡眠检测。因为滤波可能会扭曲信号的直流分量影响校准的准确性而睡眠检测依赖于校准后具有物理意义的信号幅度。在实际部署中我们将这一整套流程封装为一个独立的Python模块它能够兼容多种常见腕动仪设备的原始数据文件如.cwa, .gt3x, .bin输出标准化后的加速度时间序列和标注好的睡眠/非佩戴区间这本身就是一个非常有价值的通用腕动仪分析工具。3. 特征工程将夜间活动转化为数字指纹经过预处理我们得到了干净、标准化的夜间睡眠期加速度数据。下一步是如何将这些高维的时间序列数据转化为能够有效区分RBD患者与健康照的、具有可解释性的特征。这是连接数据与模型的关键桥梁也是ActiTect科学性的核心体现。3.1 特征设计理念从临床经验到量化指标我们的特征设计并非“黑箱”式的自动编码而是在睡眠医学专家M.S.的深度参与下完成的。我们聚焦于RBD在腕动仪信号上可能呈现的几种核心运动模式运动强度与爆发性RBD患者的异常运动往往是突然、猛烈、短暂的。我们不仅计算整夜的平均活动量更关注运动的“爆发”特性例如计算活动事件的峰值加速度、平均功率、以及超过特定阈值的运动比例。运动的周期性与节律某些神经系统疾病会表现出刻板的节律性运动。我们通过计算加速度信号的自相关函数、提取主导频率等特征来量化运动的周期性。频谱特性快速、抽搐样的运动与缓慢、翻身的运动在频域上有明显区别。我们计算信号在不同频带如0.8-4Hz 4-8Hz的能量比例、频谱熵等以区分运动的“速度”特性。运动的复杂性与碎片化健康的睡眠运动相对平滑而RBD的运动可能更“杂乱”。我们引入如样本熵、去趋势波动分析等非线性动力学指标来度量运动的复杂性。同时计算运动事件的次数、平均持续时间、以及睡眠期间“动-静”转换的频率来量化睡眠的碎片化程度。聚类行为RBD的异常运动是否在时间上聚集发生例如是否更多地集中在REM睡眠期我们通过分析运动事件间隔时间的分布如是否服从泊松分布以及计算时间序列的“聚集指数”来评估运动的时空分布模式。3.2 两级特征体系从局部事件到全局描述为了更精细地刻画运动模式我们采用了“局部-全局”两级特征提取策略图1b局部特征针对检测到的每一个独立的“运动片段”Activity Bout计算上述各类指标。一个运动片段通常定义为加速度幅度连续超过某个阈值的一段时间。全局特征将一个晚上所有运动片段的局部特征进行聚合如计算均值、标准差、偏度、峰度、分位数等形成描述整夜运动模式的“全局描述符”。例如“中位运动片段持续时间”和“频谱熵的标准差”就是两个关键的全局特征。如图3a所示这两个特征在RBD患者和健康对照中表现出显著的分布差异。RBD患者的运动片段持续时间更短更零碎且频谱熵的波动更大运动模式更不稳定、复杂这与RBD的临床表现——短暂、剧烈、多样的梦境演绎行为——是高度吻合的。这种基于临床理解的、可解释的特征工程不仅提升了模型的性能也使得模型的决策过程对医生和研究人员而言更具可信度。注意事项特征的计算依赖于精确的运动片段检测。阈值设置过高会漏掉微小的异常运动过低则会将噪声或正常翻身误判为活动。我们通过分析大量数据的加速度分布并结合生理学知识设定了自适应的阈值策略。此外所有特征在输入模型前都进行了标准化Z-score以消除量纲影响确保模型优化过程的稳定性。4. 模型构建、训练与验证策略有了高质量、标准化的特征接下来就是构建一个既强大又稳健的分类模型。我们的目标不是追求在单一数据集上的最高分数而是构建一个在未知数据上依然可靠的“泛化能手”。4.1 模型选择为什么是XGBoost我们选择了梯度提升决策树Gradient Boosting Decision Trees具体实现是XGBoost库。这个选择基于以下几点考量处理异构特征我们的特征集合包含连续变量如平均幅度、计数变量如运动事件次数和统计分布变量如偏度。树模型天然擅长处理这种混合类型的特征无需复杂的特征变换。非线性关系捕捉RBD与运动特征之间的关系很可能是非线性的。决策树通过递归分割可以自动捕捉这些复杂的交互作用。内置正则化与防过拟合XGBoost提供了丰富的正则化参数如max_depth,min_child_weight,gamma,subsample,colsample_bytree能够有效控制模型复杂度这对于防止在有限医疗数据上过拟合至关重要。可解释性相比深度神经网络树模型能提供特征重要性排序帮助我们理解哪些运动模式对区分RBD贡献最大这与我们追求可解释性的目标一致。计算效率XGBoost的工程优化做得非常好训练和预测速度快内存占用相对较小有利于未来在嵌入式设备或在线系统中的部署。4.2 训练与调优嵌套交叉验证我们使用CogTrAiL-RBD单中心数据集78人524夜进行初始模型的开发和训练。为了获得无偏的性能估计并优化超参数我们采用了嵌套交叉验证策略外层循环将数据分成K折如5折用于评估模型性能。内层循环在每一轮外层训练集中再次进行交叉验证用于选择最优的超参数组合如树的最大深度、学习率等和进行特征选择。这种方法确保了用于报告性能的测试数据从未参与过模型选择或调参的任何步骤从而得到更真实、更保守的泛化能力估计。在单中心数据上经过多夜数据聚合到患者层面后模型达到了AUROC 0.96 F1分数0.92的优异性能图3b这证明了我们特征和模型框架的有效性。4.3 从单中心到多中心泛化能力验证单中心的高性能是第一步但远非终点。真正的考验在于外部验证。我们准备了三个独立的测试集本地前瞻性测试集来自同一中心但未参与训练的新招募受试者。外部队列一来自英国牛津的OPDC队列包含iRBD、PD伴RBD及健康对照。外部队列二来自丹麦的PACE队列人群构成更为复杂。我们将仅在CogTrAiL-RBD数据上训练好的最终模型直接应用于这三个测试集。结果表2显示模型在所有外部队列上都保持了良好的判别能力AUROC在0.84-0.97之间。特别值得注意的是在PACE队列的iRBD vs HC任务中AUROC高达0.97这表明模型捕捉到的是RBD的核心生物信号而非特定人群的噪音。当然我们也观察到了一些性能波动例如在OPDC队列上平衡准确率略有下降。这恰恰反映了真实世界数据的复杂性不同中心的患者人群、设备使用细微差别、甚至临床评估标准都可能存在差异。模型性能的轻微变化是正常的关键在于它没有“崩溃”依然保持了强大的基础判别力。4.4 构建统一的多中心模型与稳定性分析在验证了单中心模型具备泛化潜力后我们更进一步将多个中心的数据CogTrAiL-RBD, OPDC, PACE合并训练一个统一的、预训练好的多中心模型。这个模型旨在作为最终交付给社区使用的“开箱即用”版本。为了评估这个统一模型在面对全新中心数据时的表现我们采用了留一数据集交叉验证。即每次训练时留出一个完整的数据集作为测试集用其余有数据集训练模型如此循环。如图4a所示LODO验证在各数据集上都取得了稳定且较高的AUROC这强有力地证明了我们管道和模型在面对数据分布变化时的鲁棒性。我们进一步深入分析了模型的稳定性图4b-d特征排名稳性在不同LODO折叠中特征的重要性排序具有高度相关性Spearman相关系数最高达0.94说明模型 consistently 认为某些特征如运动片段持续时间、频谱熵是重要的。特征选择稳定性尽管每次运行自动选出的特征子集有部分波动Jaccard相似度约0.41但存在一个由10个特征组成的“核心集”在所有的折叠中都被选中。我们的消融实验表明仅使用这10个核心特征就能达到接近峰值性能的水平加入更多特征最终模型约30个能带来轻微但稳定的提升。超参数稳定性我们重复运行LODO 20次以观察超参数选择是否收敛。结果显示大部分关键超参数如选择的特征数非常稳定。一些存在波动的参数如学习率、树的数量往往存在此消彼长的补偿关系这意味着不同的参数组合可以达到相似的模型性能这并不损害模型的鲁棒性。这些稳定性分析从多个维度证实ActiTect的建模流程是可靠的它收敛到的解是一致且可复现的而非偶然结果。5. 结果解读与临床意义探讨ActiTect在多个独立队列上验证的成功不仅仅是一组漂亮的数字其背后蕴含着对临床筛查实践的深刻启示。5.1 性能指标的临床解读在评估二元分类模型时我们通常关注AUROC综合判别能力、精确率、召回率、F1分数精确率与召回率的调和平均和平衡准确率兼顾正负类的准确率。在疾病筛查的语境下这些指标有不同的权重高召回率敏感性至关重要筛查的核心目的是“宁可错杀不可放过”即尽可能少地漏诊真正的患者假阴性。在我们的结果中模型在多个测试集上表现出召回率高于精确率的趋势例如Local Test集召回率0.99精确率0.83这是一个非常理想的特性。这意味着它倾向于将可疑案例标记出来后续可以通过更精确但昂贵的vPSG进行确诊从而实现了“粗筛-精诊”的漏斗式流程。多夜数据聚合的价值对比图3b中的夜间水平预测和患者水平预测可以清晰看到将单个患者多晚的数据进行聚合我们采用均值概率和多数投票结合的策略性能有显著提升AUROC从0.87升至0.96。这有力地说明了为了克服夜间运动模式的自然波动收集至少5-7夜的连续数据对于提高筛查可靠性是必要的。概率校准的意义一个好的分类器不仅要有区分能力其输出的概率也应反映真实患病的可能性。我们使用Brier分数评估了概率校准度。单中心模型在内部验证中Brier分数较低0.12说明概率输出较准。在多中心模型中Brier分数略有上升提示概率校准在面对新数据分布时存在挑战这是未来可以改进的方向。但在二元决策通过阈值分类层面模型性能依然稳健。5.2 工具优势与潜在应用场景ActiTect的核心优势在于其工程完备性和泛化能力。端到端解决方案它提供了一个从原始数据到风险评分的完整管道解决了跨设备数据兼容性这一工程难题。即开即用预训练的多中心模型允许研究人员或临床医生在获得新数据后无需重新训练直接进行预测极大地降低了使用门槛。适用于多种场景流行病学研究在大规模社区人群中快速筛查RBD高危个体用于疾病风险分层和队列构建。临床试验入组筛选高效地从大量潜在参与者中初步识别出可能符合条件的iRBD患者节省PSG筛查成本。疾病进展监测对于已确诊的iRBD患者定期进行腕动仪监测量化夜间运动症状的变化可能为神经保护治疗的疗效评估提供客观指标。初级保健机构作为神经科或睡眠门诊的一线筛查工具对主诉有异常睡眠行为的患者进行快速、客观的初步评估。5.3 局限性与未来方向没有任何工具是完美的清醒地认识局限性是推动其发展的前提。数据依赖与标注模型的训练和验证仍然依赖于PSG确诊的“金标准”标签。获取大量高质量的、标注好的多中心数据成本高昂。未来探索半监督或无监督学习利用大量未标注数据是一个重要方向。共病与混淆因素其他睡眠障碍如周期性肢体运动障碍、睡眠呼吸暂停也可能引起夜间活动增多。当前模型在区分这些共病方面的特异性有待在更复杂的人群中进一步验证。从筛查到诊断ActiTect定位是“筛查工具”而非“诊断工具”。其高敏感性有助于发现疑似病例但最终诊断仍需结合临床评估和vPSG。它应该被看作是临床决策的支持工具而非替代工具。计算特征的可解释性深化虽然我们设计了可解释的特征但模型最终的决策仍是这些特征的复杂组合。未来可与深度学习结合尝试直接从原始信号中学习更具判别力的表示并与临床视频进行对齐分析或许能发现新的、人类未曾总结过的RBD生物标志物。实时性与嵌入式部署目前流程是离线的。未来的工作可以探索模型轻量化将其部署在腕动仪设备或智能手机端实现近实时的风险预警。6. 实践指南如何使用ActiTect为了让读者能真正用起来我将分享如何在实际环境中部署和运行ActiTect的核心步骤与经验。项目代码已开源在GitHub以下指南基于最新版本。6.1 环境准备与安装ActiTect基于Python生态。建议使用Conda或venv创建独立的虚拟环境以避免依赖冲突。# 1. 克隆仓库 git clone https://github.com/bozeklab/actitect.git cd actitect # 2. 创建并激活虚拟环境以Conda为例 conda create -n actitect_env python3.9 conda activate actitect_env # 3. 安装核心依赖 pip install -r requirements.txt # 关键依赖包括numpy, pandas, scipy, scikit-learn, xgboost, matplotlib, seaborn等 # 此外需要安装用于读取特定腕动仪数据格式的库如 pyActigraphy (用于GENEActiv/Axivity的CWA文件) pip install pyActigraphy避坑提示pyActigraphy的安装有时会因依赖的bitstruct库在Windows上编译失败而卡住。如果遇到此问题可以尝试先通过pip install bitstruct安装预编译的wheel或者使用conda install -c conda-forge pyActigraphy。务必确保能成功导入pyActigraphy。6.2 数据准备与预处理假设你有一批来自Axivity AX6设备的.cwa格式数据文件存储在一个目录中并且有一个CSV文件metadata.csv记录了每个文件对应的受试者ID和标签如iRBD或HC。import pandas as pd from actitect.preprocessing import StandardPreprocessingPipeline from actitect.utils import load_actigraphy_data # 1. 加载元数据 meta_df pd.read_csv(path/to/your/metadata.csv) # 2. 初始化预处理管道 # 参数说明target_sampling_rate100Hz, filter_range(0.8, 20)Hz preprocessor StandardPreprocessingPipeline( target_fs100.0, filter_range(0.8, 20.0), use_auto_calibrationTrue, use_auto_sleep_detectionTrue ) processed_data_list [] for idx, row in meta_df.iterrows(): subject_id row[subject_id] file_path fpath/to/raw_data/{subject_id}.cwa label row[diagnosis] # e.g., RBD, HC # 3. 加载原始数据使用pyActigraphy raw_data load_actigraphy_data(file_path, device_typeaxivity) # 4. 运行完整预处理流程 # 这一步将执行重采样、校准、滤波、非佩戴检测、睡眠窗口检测 processed_nights preprocessor.process(raw_data) # processed_nights 是一个字典列表每个元素代表一晚处理后的数据 # 包含标准化后的加速度序列、睡眠区间起止时间、是否有效夜等 for night_data in processed_nights: night_data[subject_id] subject_id night_data[label] 1 if label RBD else 0 # 转换为二分类标签 processed_data_list.append(night_data) # 5. 将处理后的数据保存或转换为特征提取所需的格式 import pickle with open(processed_nights_data.pkl, wb) as f: pickle.dump(processed_data_list, f)实操心得预处理是最耗时但也最容易出错的环节。务必对每个受试者的处理结果进行可视化检查。可以简单绘制一两晚处理前后的加速度幅度图以及算法检测出的睡眠区间确保睡眠检测结果符合常识如夜间长时间低活动段被识别为睡眠。如果发现某个文件处理失败或结果异常检查原始文件是否损坏或尝试调整preprocessor中的参数如min_rest_period_duration用于校准的最小静止时长或sleep_detection_method的敏感度。6.3 特征提取与模型预测使用预处理后的数据调用特征提取器和预训练模型进行预测。from actitect.feature_extraction import NightlyFeatureExtractor from actitect.models import load_pretrained_model import numpy as np # 1. 加载预处理好的数据 with open(processed_nights_data.pkl, rb) as f: nights_data pickle.load(f) # 2. 初始化特征提取器 feature_extractor NightlyFeatureExtractor() # 3. 为每一晚数据提取特征 night_features [] valid_night_indices [] # 记录有效夜的索引 for i, night in enumerate(nights_data): if night[is_valid]: # 确保是有效夜非佩戴期短睡眠数据充足 features feature_extractor.extract(night[calibrated_signal], night[sleep_intervals]) features[subject_id] night[subject_id] night_features.append(features) valid_night_indices.append(i) # 4. 转换为模型输入格式 import pandas as pd features_df pd.DataFrame(night_features) # 确保特征列的顺序与模型训练时一致模型内部会处理 feature_columns [col for col in features_df.columns if col not in [subject_id, label]] X_night features_df[feature_columns].values # 5. 加载预训练的多中心模型 model load_pretrained_model(multicenter_xgboost_v1.pkl) # 6. 进行夜间水平预测 y_night_prob model.predict_proba(X_night)[:, 1] # 获取属于RBD类的概率 features_df[nightly_rbd_prob] y_night_prob # 7. 聚合到患者水平 patient_predictions features_df.groupby(subject_id).agg({ nightly_rbd_prob: [mean, lambda x: (x 0.5).mean()], # 平均概率 多数投票比例 label: first # 假设同一个受试者标签相同 }) patient_predictions.columns [mean_prob, majority_vote_ratio, true_label] # 8. 应用决策规则结合平均概率和多数投票 def aggregate_to_risk_score(row): alpha 0.7 # 可调参数权衡平均概率和多数投票的权重 risk_score alpha * row[mean_prob] (1 - alpha) * row[majority_vote_ratio] return risk_score patient_predictions[rbd_risk_score] patient_predictions.apply(aggregate_to_risk_score, axis1) patient_predictions[predicted_label] (patient_predictions[rbd_risk_score] 0.5).astype(int) # 9. 输出结果 print(patient_predictions[[mean_prob, majority_vote_ratio, rbd_risk_score, predicted_label, true_label]])6.4 模型再训练与调优高级如果你有自己的标注数据并希望在新的数据上微调或重新训练模型可以参考以下流程from actitect.models import RBDClassifier from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.metrics import classification_report, roc_auc_score # 1. 准备特征和标签 (患者水平) # 假设 patient_features 是患者水平的特征DataFrame patient_labels 是对应的标签 X patient_features.values y patient_labels.values # 2. 划分训练集和测试集 X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, stratifyy, random_state42) # 3. 初始化分类器并设置超参数搜索空间 clf RBDClassifier(model_typexgboost) param_grid { n_estimators: [100, 200, 300], max_depth: [3, 5, 7], learning_rate: [0.01, 0.05, 0.1], subsample: [0.7, 0.8, 0.9], colsample_bytree: [0.7, 0.8, 0.9], } # 4. 使用网格搜索进行超参数调优数据量小时可用交叉验证 grid_search GridSearchCV(clf, param_grid, cv5, scoringroc_auc, n_jobs-1, verbose1) grid_search.fit(X_train, y_train) # 5. 评估最佳模型 best_model grid_search.best_estimator_ y_pred_prob best_model.predict_proba(X_test)[:, 1] y_pred (y_pred_prob 0.5).astype(int) print(fBest Parameters: {grid_search.best_params_}) print(fTest AUROC: {roc_auc_score(y_test, y_pred_prob):.3f}) print(classification_report(y_test, y_pred)) # 6. 保存模型 best_model.save(my_custom_rbd_model.pkl)注意事项重新训练模型需要足够的数据量每个类别至少数十例且数据需具有代表性。直接在小数据集上训练极易过拟合。建议优先使用我们提供的预训练模型进行预测仅当你有大量高质量的新数据且确信数据分布与原有训练集有较大差异时才考虑重新训练或微调。7. 常见问题与排查实录在实际使用ActiTect或类似工具的过程中你可能会遇到以下典型问题。这里分享我的排查思路和解决方案。问题一预处理失败报错“无法检测到有效的睡眠区间”。可能原因1数据质量极差设备佩戴异常松动或夜间活动过于频繁导致算法找不到连续的低活动期。排查绘制原始数据加速度幅度图。观察是否有大段数据为0或恒定值设备未佩戴或整夜都处于高活动状态。解决检查设备佩戴日志排除无效数据。或尝试调整sleep_detection_method的参数如降低检测睡眠所需的最低静止时长阈值。可能原因2时区或时间戳错误。原始数据的时间戳不是本地时间或者存在巨大的跳变。排查检查raw_data对象的start_time和sampling_frequency属性。绘制24小时活动概览图看活动模式是否与昼夜节律相符。解决在加载数据时使用load_actigraphy_data(file_path, tzEurope/Berlin)明确指定时区。如有时间戳跳变需联系数据提供方确认。问题二特征提取后输入模型预测所有样本的输出概率都接近0.5没有区分度。可能原因1预处理步骤未正确执行特别是自动校准失败导致信号仍处于未校准的“原始值”范围与模型训练时见过的分布完全不同。排查检查校准前后的加速度矢量幅度。校准后静止期的幅度应紧密围绕1g9.81 m/s²分布。可以计算校准误差。解决确保use_auto_calibrationTrue已启用。如果自动校准失败可尝试手动提供校准参数或检查数据中是否有足够的低活动期用于校准。可能原因2提取的特征列名或顺序与预训练模型期望的不匹配。排查打印出feature_columns列表并与模型文件如果可查看或项目文档中声明的特征列表进行比对。解决使用模型自带的feature_names_in_属性如果为sklearn/xgboost格式来获取正确的特征顺序并据此对X_night进行排序。问题三在自己的小数据集上性能远低于论文报告的水平。可能原因1数据分布差异。你的患者人群、设备型号、采集协议可能与训练集存在较大差异。排查进行简单的数据探索性分析EDA。比较你的数据与训练集如提供描述性统计在年龄、性别、活动量分布上的差异。解决这是外部验证的常态。可以尝试使用我们提供的多中心模型因为它涵盖了更广的数据分布。如果条件允许收集更多样化的数据并考虑对模型进行微调需谨慎避免小数据过拟合。可能原因2标签噪声。你的“金标准”诊断vPSG可能存在误判或者RBD与其他睡眠障碍如PLMD共病影响了标签的纯净度。排查回顾诊断流程。是否所有患者都经过了严格的vPSG判读是否有共病信息解决清理数据确保标签准确。对于共病案例可以尝试在特征层面进行分析看是否能找到区分模式或将其作为单独的类别处理。问题四运行速度慢处理大量数据时内存不足。可能原因默认设置下特征提取可能计算了所有高维特征如全频段频谱且数据未进行批处理。排查使用内存监控工具。特征提取步骤通常是计算瓶颈。解决并行化利用Python的multiprocessing或joblib库将不同受试者或不同夜晚的数据分配到多个进程进行预处理和特征提取。简化特征如果只是进行筛查可以尝试只使用核心的10个特征见论文这能大幅减少计算量。可以在NightlyFeatureExtractor初始化时传入一个feature_subset参数如果支持。流式处理对于极大数据集考虑编写脚本每次只加载和处理一个文件提取特征后立即保存或聚合然后释放内存。开发ActiTect的过程是一个不断在理想高精度模型与现实嘈杂、异构的真实世界数据之间寻找平衡的过程。最大的体会是在医疗机器学习项目中数据工程的质量往往比模型算法的复杂度更重要。一个精心设计的、能够处理现实世界混乱数据的预处理管道其价值不亚于一个新颖的神经网络架构。其次泛化能力必须通过严格的多中心、前瞻性验证来证明任何仅在内部数据集上炫技的模型其临床价值都是存疑的。最后开源和易用性是工具能否被广泛采纳的关键。我们花了大量时间封装代码、编写文档、提供示例就是希望降低使用门槛让更多研究者能在此基础上进行验证、改进和应用。这个工具只是一个起点期待社区的力量能推动它不断进化最终为神经退行性疾病的早期防控带来切实的改变。
ActiTect:基于可穿戴设备与机器学习实现RBD早期筛查的工程化方案
发布时间:2026/5/26 11:28:03
1. 项目概述在神经退行性疾病的研究与临床实践中早期识别是延缓疾病进展、改善患者预后的关键。其中快速眼动睡眠行为障碍RBD因其与帕金森病、路易体痴呆等α-突触核蛋白病的强关联性已成为一个极具价值的早期生物标志物。然而诊断RBD的“金标准”——视频多导睡眠图vPSG——因其高昂的设备成本、复杂的操作流程和对专业人员的依赖难以在社区筛查或长期监测中大规模应用。临床问卷虽然简便但其主观性强准确性有限。因此寻找一种客观、可量化、可扩展且成本可控的筛查工具成为了领域内一个迫切的需求。近年来随着可穿戴设备的普及腕动仪Actigraphy因其无创、连续监测和成本低廉的特点在睡眠研究和运动障碍评估中展现出巨大潜力。它通过记录手腕的加速度数据能够捕捉到夜间异常的运动模式理论上非常适合用于RBD的筛查。但早期的研究多依赖于人工提取的简单特征如总活动量或单一队列的模型其结果的稳定性和在不同设备、不同人群中的泛化能力一直是个问号。这背后是数据异质性带来的巨大挑战不同品牌的设备其传感器特性、采样精度、佩戴方式各异直接使用原始数据训练模型无异于“盲人摸象”。正是在这样的背景下我们开发了ActiTect。它不仅仅是一个机器学习模型更是一个完整的、面向工程化部署的解决方案。其核心设计哲学是“先标准化再智能化”。我们首先构建了一个强大的数据预处理模块旨在将来自不同设备、不同中心的“五花八门”的原始加速度数据转化为干净、一致、具有可比性的信号。在此基础上我们才引入机器学习模型从标准化的数据中提取与RBD病理生理相关的复杂运动特征。更重要的是我们从一开始就采用了多中心数据集进行训练和验证确保模型学到的不是某个特定数据集的“ idiosyncrasy”特质而是RBD本身的核心生物信号。最终我们将整个流程打包成一个开源工具希望它能成为一个“即插即用”的基石推动基于可穿戴设备的RBD筛查从实验室走向更广阔的应用场景。2. 核心设计思路与工程挑战开发一个具有临床实用价值的RBD筛查工具远不止是调优一个分类算法那么简单。它需要系统性地解决从数据采集到结果输出的全链路问题。ActiTect的设计正是围绕这些核心工程挑战展开的。2.1 核心挑战数据异质性与模型泛化腕动仪数据用于机器学习面临的首要也是最大的挑战就是数据的异质性。这种异质性来源于多个层面设备层面不同厂商如Axivity, GENEActiv, ActiGraph的传感器在灵敏度、量程、噪声特性和坐标系定义上存在差异。即使采样率都设为100Hz原始加速度值的分布也可能天差地别。受试者层面佩戴松紧度、手腕粗细、主导手左/右等因素会影响信号的基线水平和动态范围。采集协议层面各研究中心可能采用不同的佩戴时长如5天 vs 7天、不同的起始时间甚至不同的数据导出格式。如果直接将原始数据喂给模型模型很可能会学到这些与疾病无关的“伪特征”例如某个品牌设备特有的噪声模式从而导致在训练集上表现优异但应用到新设备或新中心的数据时性能急剧下降。这就是机器学习中经典的“过拟合”问题在医疗跨中心应用中尤为致命。2.2 ActiTect的解决方案标准化预处理管道为了解决上述问题ActiTect将重心前置设计了一个鲁棒的、自动化的预处理管道。这个管道的目标是将所有输入数据“拉”到同一个度量空间其流程主要包括以下几个关键步骤它们共同作用为后续的特征提取和模型推理奠定了可靠的基础。2.2.1 重采样与时钟漂移校正腕动仪内置的时钟晶振并非绝对精确会产生微小的漂移。长时间如连续7天记录后累积的漂移可能达到数秒甚至数十秒。这对于需要精确计算事件频率和时域特征的分析来说是致命的。我们的管道首先检测并校正这种漂移通过插值将信号重新对齐到绝对时间轴上确保不同记录之间的时间尺度一致。2.2.2 自动校准从“歪斜”的数据到“标准球体”这是预处理中最关键的一步。理想的加速度计在静止时三轴矢量和应等于重力加速度1g。但由于制造公差和佩戴角度实际数据点会偏离这个“单位球体”。我们实现了van Hees等人提出的自动校准算法。其原理是识别出低活动期通常为睡眠中相对静止的时段计算这些点与理论球体的偏差然后通过加权最小二乘回归迭代求解出每个轴的增益Gain和偏移Offset校正参数。经过校准后数据被“拉回”以重力加速度为基准的物理空间。如图2b所示这一步骤能将平均校准误差从几十毫克大幅降低至约3毫克显著提升了数据的物理一致性和可比性。2.2.3 带通滤波聚焦生理相关频段原始加速度信号包含各种噪声如设备本身的电子噪声、日常活动产生的高频抖动等。RBD相关的异常运动有其特定的频域特征。我们应用了一个0.8-20 Hz的带通滤波器。选择0.8 Hz作为下限是为了滤除由身体翻身等缓慢移动产生的低频成分而20 Hz的上限则能有效去除高频噪声同时保留快速、爆发性动作的信号。如图2c所示滤波后目标频段外的噪声被显著抑制而频段内的信号功率得以保留为后续特征提取提供了更“干净”的输入。2.2.4 自动化睡眠窗口与非佩戴期检测在无PSG的居家监测场景中确定“睡眠期”是计算夜间运动特征的前提。依赖患者手写的睡眠日记不仅增加负担而且存在回忆偏差和不准确性。ActiTect集成了HDCZA算法这是一种基于活动计数和零交叉分析的启发式算法能够从多日的活动数据中自动识别出最可能的睡眠起始和结束时间。我们将算法结果与睡眠日记及PSG金标准进行对比验证图2d结果显示其相关性极高Pearson r 0.99平均绝对误差在35分钟左右。虽然存在轻微低估睡眠时长的倾向但这对于RBD筛查而言可能是有益的因为它减少了将清醒期活动误判为异常睡眠运动的可能性。同时管道还能自动检测设备未被佩戴的时段非佩戴期并在分析中排除这些无效数据进一步保证了数据质量。实操心得预处理管道的每个步骤都至关重要且顺序不能随意调换。例如必须先进行重采样和校准再进行滤波和睡眠检测。因为滤波可能会扭曲信号的直流分量影响校准的准确性而睡眠检测依赖于校准后具有物理意义的信号幅度。在实际部署中我们将这一整套流程封装为一个独立的Python模块它能够兼容多种常见腕动仪设备的原始数据文件如.cwa, .gt3x, .bin输出标准化后的加速度时间序列和标注好的睡眠/非佩戴区间这本身就是一个非常有价值的通用腕动仪分析工具。3. 特征工程将夜间活动转化为数字指纹经过预处理我们得到了干净、标准化的夜间睡眠期加速度数据。下一步是如何将这些高维的时间序列数据转化为能够有效区分RBD患者与健康照的、具有可解释性的特征。这是连接数据与模型的关键桥梁也是ActiTect科学性的核心体现。3.1 特征设计理念从临床经验到量化指标我们的特征设计并非“黑箱”式的自动编码而是在睡眠医学专家M.S.的深度参与下完成的。我们聚焦于RBD在腕动仪信号上可能呈现的几种核心运动模式运动强度与爆发性RBD患者的异常运动往往是突然、猛烈、短暂的。我们不仅计算整夜的平均活动量更关注运动的“爆发”特性例如计算活动事件的峰值加速度、平均功率、以及超过特定阈值的运动比例。运动的周期性与节律某些神经系统疾病会表现出刻板的节律性运动。我们通过计算加速度信号的自相关函数、提取主导频率等特征来量化运动的周期性。频谱特性快速、抽搐样的运动与缓慢、翻身的运动在频域上有明显区别。我们计算信号在不同频带如0.8-4Hz 4-8Hz的能量比例、频谱熵等以区分运动的“速度”特性。运动的复杂性与碎片化健康的睡眠运动相对平滑而RBD的运动可能更“杂乱”。我们引入如样本熵、去趋势波动分析等非线性动力学指标来度量运动的复杂性。同时计算运动事件的次数、平均持续时间、以及睡眠期间“动-静”转换的频率来量化睡眠的碎片化程度。聚类行为RBD的异常运动是否在时间上聚集发生例如是否更多地集中在REM睡眠期我们通过分析运动事件间隔时间的分布如是否服从泊松分布以及计算时间序列的“聚集指数”来评估运动的时空分布模式。3.2 两级特征体系从局部事件到全局描述为了更精细地刻画运动模式我们采用了“局部-全局”两级特征提取策略图1b局部特征针对检测到的每一个独立的“运动片段”Activity Bout计算上述各类指标。一个运动片段通常定义为加速度幅度连续超过某个阈值的一段时间。全局特征将一个晚上所有运动片段的局部特征进行聚合如计算均值、标准差、偏度、峰度、分位数等形成描述整夜运动模式的“全局描述符”。例如“中位运动片段持续时间”和“频谱熵的标准差”就是两个关键的全局特征。如图3a所示这两个特征在RBD患者和健康对照中表现出显著的分布差异。RBD患者的运动片段持续时间更短更零碎且频谱熵的波动更大运动模式更不稳定、复杂这与RBD的临床表现——短暂、剧烈、多样的梦境演绎行为——是高度吻合的。这种基于临床理解的、可解释的特征工程不仅提升了模型的性能也使得模型的决策过程对医生和研究人员而言更具可信度。注意事项特征的计算依赖于精确的运动片段检测。阈值设置过高会漏掉微小的异常运动过低则会将噪声或正常翻身误判为活动。我们通过分析大量数据的加速度分布并结合生理学知识设定了自适应的阈值策略。此外所有特征在输入模型前都进行了标准化Z-score以消除量纲影响确保模型优化过程的稳定性。4. 模型构建、训练与验证策略有了高质量、标准化的特征接下来就是构建一个既强大又稳健的分类模型。我们的目标不是追求在单一数据集上的最高分数而是构建一个在未知数据上依然可靠的“泛化能手”。4.1 模型选择为什么是XGBoost我们选择了梯度提升决策树Gradient Boosting Decision Trees具体实现是XGBoost库。这个选择基于以下几点考量处理异构特征我们的特征集合包含连续变量如平均幅度、计数变量如运动事件次数和统计分布变量如偏度。树模型天然擅长处理这种混合类型的特征无需复杂的特征变换。非线性关系捕捉RBD与运动特征之间的关系很可能是非线性的。决策树通过递归分割可以自动捕捉这些复杂的交互作用。内置正则化与防过拟合XGBoost提供了丰富的正则化参数如max_depth,min_child_weight,gamma,subsample,colsample_bytree能够有效控制模型复杂度这对于防止在有限医疗数据上过拟合至关重要。可解释性相比深度神经网络树模型能提供特征重要性排序帮助我们理解哪些运动模式对区分RBD贡献最大这与我们追求可解释性的目标一致。计算效率XGBoost的工程优化做得非常好训练和预测速度快内存占用相对较小有利于未来在嵌入式设备或在线系统中的部署。4.2 训练与调优嵌套交叉验证我们使用CogTrAiL-RBD单中心数据集78人524夜进行初始模型的开发和训练。为了获得无偏的性能估计并优化超参数我们采用了嵌套交叉验证策略外层循环将数据分成K折如5折用于评估模型性能。内层循环在每一轮外层训练集中再次进行交叉验证用于选择最优的超参数组合如树的最大深度、学习率等和进行特征选择。这种方法确保了用于报告性能的测试数据从未参与过模型选择或调参的任何步骤从而得到更真实、更保守的泛化能力估计。在单中心数据上经过多夜数据聚合到患者层面后模型达到了AUROC 0.96 F1分数0.92的优异性能图3b这证明了我们特征和模型框架的有效性。4.3 从单中心到多中心泛化能力验证单中心的高性能是第一步但远非终点。真正的考验在于外部验证。我们准备了三个独立的测试集本地前瞻性测试集来自同一中心但未参与训练的新招募受试者。外部队列一来自英国牛津的OPDC队列包含iRBD、PD伴RBD及健康对照。外部队列二来自丹麦的PACE队列人群构成更为复杂。我们将仅在CogTrAiL-RBD数据上训练好的最终模型直接应用于这三个测试集。结果表2显示模型在所有外部队列上都保持了良好的判别能力AUROC在0.84-0.97之间。特别值得注意的是在PACE队列的iRBD vs HC任务中AUROC高达0.97这表明模型捕捉到的是RBD的核心生物信号而非特定人群的噪音。当然我们也观察到了一些性能波动例如在OPDC队列上平衡准确率略有下降。这恰恰反映了真实世界数据的复杂性不同中心的患者人群、设备使用细微差别、甚至临床评估标准都可能存在差异。模型性能的轻微变化是正常的关键在于它没有“崩溃”依然保持了强大的基础判别力。4.4 构建统一的多中心模型与稳定性分析在验证了单中心模型具备泛化潜力后我们更进一步将多个中心的数据CogTrAiL-RBD, OPDC, PACE合并训练一个统一的、预训练好的多中心模型。这个模型旨在作为最终交付给社区使用的“开箱即用”版本。为了评估这个统一模型在面对全新中心数据时的表现我们采用了留一数据集交叉验证。即每次训练时留出一个完整的数据集作为测试集用其余有数据集训练模型如此循环。如图4a所示LODO验证在各数据集上都取得了稳定且较高的AUROC这强有力地证明了我们管道和模型在面对数据分布变化时的鲁棒性。我们进一步深入分析了模型的稳定性图4b-d特征排名稳性在不同LODO折叠中特征的重要性排序具有高度相关性Spearman相关系数最高达0.94说明模型 consistently 认为某些特征如运动片段持续时间、频谱熵是重要的。特征选择稳定性尽管每次运行自动选出的特征子集有部分波动Jaccard相似度约0.41但存在一个由10个特征组成的“核心集”在所有的折叠中都被选中。我们的消融实验表明仅使用这10个核心特征就能达到接近峰值性能的水平加入更多特征最终模型约30个能带来轻微但稳定的提升。超参数稳定性我们重复运行LODO 20次以观察超参数选择是否收敛。结果显示大部分关键超参数如选择的特征数非常稳定。一些存在波动的参数如学习率、树的数量往往存在此消彼长的补偿关系这意味着不同的参数组合可以达到相似的模型性能这并不损害模型的鲁棒性。这些稳定性分析从多个维度证实ActiTect的建模流程是可靠的它收敛到的解是一致且可复现的而非偶然结果。5. 结果解读与临床意义探讨ActiTect在多个独立队列上验证的成功不仅仅是一组漂亮的数字其背后蕴含着对临床筛查实践的深刻启示。5.1 性能指标的临床解读在评估二元分类模型时我们通常关注AUROC综合判别能力、精确率、召回率、F1分数精确率与召回率的调和平均和平衡准确率兼顾正负类的准确率。在疾病筛查的语境下这些指标有不同的权重高召回率敏感性至关重要筛查的核心目的是“宁可错杀不可放过”即尽可能少地漏诊真正的患者假阴性。在我们的结果中模型在多个测试集上表现出召回率高于精确率的趋势例如Local Test集召回率0.99精确率0.83这是一个非常理想的特性。这意味着它倾向于将可疑案例标记出来后续可以通过更精确但昂贵的vPSG进行确诊从而实现了“粗筛-精诊”的漏斗式流程。多夜数据聚合的价值对比图3b中的夜间水平预测和患者水平预测可以清晰看到将单个患者多晚的数据进行聚合我们采用均值概率和多数投票结合的策略性能有显著提升AUROC从0.87升至0.96。这有力地说明了为了克服夜间运动模式的自然波动收集至少5-7夜的连续数据对于提高筛查可靠性是必要的。概率校准的意义一个好的分类器不仅要有区分能力其输出的概率也应反映真实患病的可能性。我们使用Brier分数评估了概率校准度。单中心模型在内部验证中Brier分数较低0.12说明概率输出较准。在多中心模型中Brier分数略有上升提示概率校准在面对新数据分布时存在挑战这是未来可以改进的方向。但在二元决策通过阈值分类层面模型性能依然稳健。5.2 工具优势与潜在应用场景ActiTect的核心优势在于其工程完备性和泛化能力。端到端解决方案它提供了一个从原始数据到风险评分的完整管道解决了跨设备数据兼容性这一工程难题。即开即用预训练的多中心模型允许研究人员或临床医生在获得新数据后无需重新训练直接进行预测极大地降低了使用门槛。适用于多种场景流行病学研究在大规模社区人群中快速筛查RBD高危个体用于疾病风险分层和队列构建。临床试验入组筛选高效地从大量潜在参与者中初步识别出可能符合条件的iRBD患者节省PSG筛查成本。疾病进展监测对于已确诊的iRBD患者定期进行腕动仪监测量化夜间运动症状的变化可能为神经保护治疗的疗效评估提供客观指标。初级保健机构作为神经科或睡眠门诊的一线筛查工具对主诉有异常睡眠行为的患者进行快速、客观的初步评估。5.3 局限性与未来方向没有任何工具是完美的清醒地认识局限性是推动其发展的前提。数据依赖与标注模型的训练和验证仍然依赖于PSG确诊的“金标准”标签。获取大量高质量的、标注好的多中心数据成本高昂。未来探索半监督或无监督学习利用大量未标注数据是一个重要方向。共病与混淆因素其他睡眠障碍如周期性肢体运动障碍、睡眠呼吸暂停也可能引起夜间活动增多。当前模型在区分这些共病方面的特异性有待在更复杂的人群中进一步验证。从筛查到诊断ActiTect定位是“筛查工具”而非“诊断工具”。其高敏感性有助于发现疑似病例但最终诊断仍需结合临床评估和vPSG。它应该被看作是临床决策的支持工具而非替代工具。计算特征的可解释性深化虽然我们设计了可解释的特征但模型最终的决策仍是这些特征的复杂组合。未来可与深度学习结合尝试直接从原始信号中学习更具判别力的表示并与临床视频进行对齐分析或许能发现新的、人类未曾总结过的RBD生物标志物。实时性与嵌入式部署目前流程是离线的。未来的工作可以探索模型轻量化将其部署在腕动仪设备或智能手机端实现近实时的风险预警。6. 实践指南如何使用ActiTect为了让读者能真正用起来我将分享如何在实际环境中部署和运行ActiTect的核心步骤与经验。项目代码已开源在GitHub以下指南基于最新版本。6.1 环境准备与安装ActiTect基于Python生态。建议使用Conda或venv创建独立的虚拟环境以避免依赖冲突。# 1. 克隆仓库 git clone https://github.com/bozeklab/actitect.git cd actitect # 2. 创建并激活虚拟环境以Conda为例 conda create -n actitect_env python3.9 conda activate actitect_env # 3. 安装核心依赖 pip install -r requirements.txt # 关键依赖包括numpy, pandas, scipy, scikit-learn, xgboost, matplotlib, seaborn等 # 此外需要安装用于读取特定腕动仪数据格式的库如 pyActigraphy (用于GENEActiv/Axivity的CWA文件) pip install pyActigraphy避坑提示pyActigraphy的安装有时会因依赖的bitstruct库在Windows上编译失败而卡住。如果遇到此问题可以尝试先通过pip install bitstruct安装预编译的wheel或者使用conda install -c conda-forge pyActigraphy。务必确保能成功导入pyActigraphy。6.2 数据准备与预处理假设你有一批来自Axivity AX6设备的.cwa格式数据文件存储在一个目录中并且有一个CSV文件metadata.csv记录了每个文件对应的受试者ID和标签如iRBD或HC。import pandas as pd from actitect.preprocessing import StandardPreprocessingPipeline from actitect.utils import load_actigraphy_data # 1. 加载元数据 meta_df pd.read_csv(path/to/your/metadata.csv) # 2. 初始化预处理管道 # 参数说明target_sampling_rate100Hz, filter_range(0.8, 20)Hz preprocessor StandardPreprocessingPipeline( target_fs100.0, filter_range(0.8, 20.0), use_auto_calibrationTrue, use_auto_sleep_detectionTrue ) processed_data_list [] for idx, row in meta_df.iterrows(): subject_id row[subject_id] file_path fpath/to/raw_data/{subject_id}.cwa label row[diagnosis] # e.g., RBD, HC # 3. 加载原始数据使用pyActigraphy raw_data load_actigraphy_data(file_path, device_typeaxivity) # 4. 运行完整预处理流程 # 这一步将执行重采样、校准、滤波、非佩戴检测、睡眠窗口检测 processed_nights preprocessor.process(raw_data) # processed_nights 是一个字典列表每个元素代表一晚处理后的数据 # 包含标准化后的加速度序列、睡眠区间起止时间、是否有效夜等 for night_data in processed_nights: night_data[subject_id] subject_id night_data[label] 1 if label RBD else 0 # 转换为二分类标签 processed_data_list.append(night_data) # 5. 将处理后的数据保存或转换为特征提取所需的格式 import pickle with open(processed_nights_data.pkl, wb) as f: pickle.dump(processed_data_list, f)实操心得预处理是最耗时但也最容易出错的环节。务必对每个受试者的处理结果进行可视化检查。可以简单绘制一两晚处理前后的加速度幅度图以及算法检测出的睡眠区间确保睡眠检测结果符合常识如夜间长时间低活动段被识别为睡眠。如果发现某个文件处理失败或结果异常检查原始文件是否损坏或尝试调整preprocessor中的参数如min_rest_period_duration用于校准的最小静止时长或sleep_detection_method的敏感度。6.3 特征提取与模型预测使用预处理后的数据调用特征提取器和预训练模型进行预测。from actitect.feature_extraction import NightlyFeatureExtractor from actitect.models import load_pretrained_model import numpy as np # 1. 加载预处理好的数据 with open(processed_nights_data.pkl, rb) as f: nights_data pickle.load(f) # 2. 初始化特征提取器 feature_extractor NightlyFeatureExtractor() # 3. 为每一晚数据提取特征 night_features [] valid_night_indices [] # 记录有效夜的索引 for i, night in enumerate(nights_data): if night[is_valid]: # 确保是有效夜非佩戴期短睡眠数据充足 features feature_extractor.extract(night[calibrated_signal], night[sleep_intervals]) features[subject_id] night[subject_id] night_features.append(features) valid_night_indices.append(i) # 4. 转换为模型输入格式 import pandas as pd features_df pd.DataFrame(night_features) # 确保特征列的顺序与模型训练时一致模型内部会处理 feature_columns [col for col in features_df.columns if col not in [subject_id, label]] X_night features_df[feature_columns].values # 5. 加载预训练的多中心模型 model load_pretrained_model(multicenter_xgboost_v1.pkl) # 6. 进行夜间水平预测 y_night_prob model.predict_proba(X_night)[:, 1] # 获取属于RBD类的概率 features_df[nightly_rbd_prob] y_night_prob # 7. 聚合到患者水平 patient_predictions features_df.groupby(subject_id).agg({ nightly_rbd_prob: [mean, lambda x: (x 0.5).mean()], # 平均概率 多数投票比例 label: first # 假设同一个受试者标签相同 }) patient_predictions.columns [mean_prob, majority_vote_ratio, true_label] # 8. 应用决策规则结合平均概率和多数投票 def aggregate_to_risk_score(row): alpha 0.7 # 可调参数权衡平均概率和多数投票的权重 risk_score alpha * row[mean_prob] (1 - alpha) * row[majority_vote_ratio] return risk_score patient_predictions[rbd_risk_score] patient_predictions.apply(aggregate_to_risk_score, axis1) patient_predictions[predicted_label] (patient_predictions[rbd_risk_score] 0.5).astype(int) # 9. 输出结果 print(patient_predictions[[mean_prob, majority_vote_ratio, rbd_risk_score, predicted_label, true_label]])6.4 模型再训练与调优高级如果你有自己的标注数据并希望在新的数据上微调或重新训练模型可以参考以下流程from actitect.models import RBDClassifier from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.metrics import classification_report, roc_auc_score # 1. 准备特征和标签 (患者水平) # 假设 patient_features 是患者水平的特征DataFrame patient_labels 是对应的标签 X patient_features.values y patient_labels.values # 2. 划分训练集和测试集 X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, stratifyy, random_state42) # 3. 初始化分类器并设置超参数搜索空间 clf RBDClassifier(model_typexgboost) param_grid { n_estimators: [100, 200, 300], max_depth: [3, 5, 7], learning_rate: [0.01, 0.05, 0.1], subsample: [0.7, 0.8, 0.9], colsample_bytree: [0.7, 0.8, 0.9], } # 4. 使用网格搜索进行超参数调优数据量小时可用交叉验证 grid_search GridSearchCV(clf, param_grid, cv5, scoringroc_auc, n_jobs-1, verbose1) grid_search.fit(X_train, y_train) # 5. 评估最佳模型 best_model grid_search.best_estimator_ y_pred_prob best_model.predict_proba(X_test)[:, 1] y_pred (y_pred_prob 0.5).astype(int) print(fBest Parameters: {grid_search.best_params_}) print(fTest AUROC: {roc_auc_score(y_test, y_pred_prob):.3f}) print(classification_report(y_test, y_pred)) # 6. 保存模型 best_model.save(my_custom_rbd_model.pkl)注意事项重新训练模型需要足够的数据量每个类别至少数十例且数据需具有代表性。直接在小数据集上训练极易过拟合。建议优先使用我们提供的预训练模型进行预测仅当你有大量高质量的新数据且确信数据分布与原有训练集有较大差异时才考虑重新训练或微调。7. 常见问题与排查实录在实际使用ActiTect或类似工具的过程中你可能会遇到以下典型问题。这里分享我的排查思路和解决方案。问题一预处理失败报错“无法检测到有效的睡眠区间”。可能原因1数据质量极差设备佩戴异常松动或夜间活动过于频繁导致算法找不到连续的低活动期。排查绘制原始数据加速度幅度图。观察是否有大段数据为0或恒定值设备未佩戴或整夜都处于高活动状态。解决检查设备佩戴日志排除无效数据。或尝试调整sleep_detection_method的参数如降低检测睡眠所需的最低静止时长阈值。可能原因2时区或时间戳错误。原始数据的时间戳不是本地时间或者存在巨大的跳变。排查检查raw_data对象的start_time和sampling_frequency属性。绘制24小时活动概览图看活动模式是否与昼夜节律相符。解决在加载数据时使用load_actigraphy_data(file_path, tzEurope/Berlin)明确指定时区。如有时间戳跳变需联系数据提供方确认。问题二特征提取后输入模型预测所有样本的输出概率都接近0.5没有区分度。可能原因1预处理步骤未正确执行特别是自动校准失败导致信号仍处于未校准的“原始值”范围与模型训练时见过的分布完全不同。排查检查校准前后的加速度矢量幅度。校准后静止期的幅度应紧密围绕1g9.81 m/s²分布。可以计算校准误差。解决确保use_auto_calibrationTrue已启用。如果自动校准失败可尝试手动提供校准参数或检查数据中是否有足够的低活动期用于校准。可能原因2提取的特征列名或顺序与预训练模型期望的不匹配。排查打印出feature_columns列表并与模型文件如果可查看或项目文档中声明的特征列表进行比对。解决使用模型自带的feature_names_in_属性如果为sklearn/xgboost格式来获取正确的特征顺序并据此对X_night进行排序。问题三在自己的小数据集上性能远低于论文报告的水平。可能原因1数据分布差异。你的患者人群、设备型号、采集协议可能与训练集存在较大差异。排查进行简单的数据探索性分析EDA。比较你的数据与训练集如提供描述性统计在年龄、性别、活动量分布上的差异。解决这是外部验证的常态。可以尝试使用我们提供的多中心模型因为它涵盖了更广的数据分布。如果条件允许收集更多样化的数据并考虑对模型进行微调需谨慎避免小数据过拟合。可能原因2标签噪声。你的“金标准”诊断vPSG可能存在误判或者RBD与其他睡眠障碍如PLMD共病影响了标签的纯净度。排查回顾诊断流程。是否所有患者都经过了严格的vPSG判读是否有共病信息解决清理数据确保标签准确。对于共病案例可以尝试在特征层面进行分析看是否能找到区分模式或将其作为单独的类别处理。问题四运行速度慢处理大量数据时内存不足。可能原因默认设置下特征提取可能计算了所有高维特征如全频段频谱且数据未进行批处理。排查使用内存监控工具。特征提取步骤通常是计算瓶颈。解决并行化利用Python的multiprocessing或joblib库将不同受试者或不同夜晚的数据分配到多个进程进行预处理和特征提取。简化特征如果只是进行筛查可以尝试只使用核心的10个特征见论文这能大幅减少计算量。可以在NightlyFeatureExtractor初始化时传入一个feature_subset参数如果支持。流式处理对于极大数据集考虑编写脚本每次只加载和处理一个文件提取特征后立即保存或聚合然后释放内存。开发ActiTect的过程是一个不断在理想高精度模型与现实嘈杂、异构的真实世界数据之间寻找平衡的过程。最大的体会是在医疗机器学习项目中数据工程的质量往往比模型算法的复杂度更重要。一个精心设计的、能够处理现实世界混乱数据的预处理管道其价值不亚于一个新颖的神经网络架构。其次泛化能力必须通过严格的多中心、前瞻性验证来证明任何仅在内部数据集上炫技的模型其临床价值都是存疑的。最后开源和易用性是工具能否被广泛采纳的关键。我们花了大量时间封装代码、编写文档、提供示例就是希望降低使用门槛让更多研究者能在此基础上进行验证、改进和应用。这个工具只是一个起点期待社区的力量能推动它不断进化最终为神经退行性疾病的早期防控带来切实的改变。