本项目是机器学习课程设计, 主要内容是利用 机器学习和深度学习 算法实现 高糖预测 功能.
小组成员: 19220432 陆昊宇, 19220448 董文杰, 19220430 沈子毅
数据集包含 16 个糖前用户多天的时序特征和血糖真值. 其中特征包括: 血容量脉冲信号 (BVP), 皮肤电活动 (EDA), 皮肤温度 (TEMP), 三轴加速度计 (ACC), 心率 (HR), 搏动间隔 (IBI). 同时还包括时间戳 (datatime) 和血糖浓度 (glucose).
我们对每一个用户的时序数据分别进行预处理和保存. 内容包括:
- 数据映射: 我们将每个用户的多天数据以 0.25ms 的粒度映射到一天的
$[0, 345599]$ ms 中. - 缺失异常值处理: 我们利用真实的数据进行线性 (linear) 循环插值处理, 从而将所有的缺失值和异常值进行填充.
- 归一化: 我们对每一个用户除了时间戳和血糖值之外的其他特征进行 最大最小值 归一化处理, 使得其值域落在
$[0, 1]$ 之间. - 可视化: 我们利用
subplots绘制 16 个用户的 时间-血糖趋势图 以便于观察数据分布从而决策出合适的阶段划分.
最终对于每一个用户可以得到类似于下面结构的 时序特征 矩阵, 共 9 个原始特征:
| datetime | eda | temp | ibi | acc_x | acc_y | acc_z | bvp | hr |
|---|---|---|---|---|---|---|---|---|
| 0 | 0.322 | 0.780 | 0.486 | 0.681 | 0.577 | 0.285 | 0.469 | 0.342 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 345599 | 0.322 | 0.780 | 0.472 | 0.684 | 0.577 | 0.285 | 0.470 | 0.343 |
本阶段, 我们首先利用 快速傅里叶变换 (FFT) 和 预训练模型 (xgboost) 删除无关特征 bvp 和 ibi. 然后将剩余的的合理特征以
在进行特征提取前, 我们有必要对数据进行第一轮降维. 为此我们引入 快速傅里叶变换 (FFT) 和 预训练模型 (xgboost).
对于 FFT 策略. 我们尝试将所有特征关于血糖值一一进行频谱分析比对, 如果两者频谱图在相同量纲下趋势相同则认为该特征与血糖变化趋势强相关, 反之则认为弱相关, 需要排除该特征. 最终发现 bvp 和 ibi 两个特征与血糖呈现弱相关 (如下图所示), 我们将这两个特征维度直接删除.
对于预训练策略. 我们引入 xgboost 模型, 得到 16 人的预训练数据 (如下表所示). 其中
| cnt | datetime | eda | temp | ibi | acc_x | acc_y | acc_z | bvp | hr |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 1.0 | 3.125 | 2.25 | 7.6875 | 6.3125 | 5.8750 | 6.0000 | 8.9375 | 3.8125 |
| 2 | 1.0 | 2.125 | 1.25 | 6.6875 | 5.3125 | 4.8750 | 5.0000 | 7.9375 | 2.8125 |
| 3 | 1.0 | 1.375 | 1.00 | 5.6875 | 4.3125 | 3.8750 | 4.0000 | 6.9375 | 1.8125 |
| 4 | 1.0 | 1.000 | 1.00 | 4.6875 | 3.3125 | 2.8750 | 3.0625 | 5.9375 | 1.1250 |
| 5 | 1.0 | 1.000 | 1.00 | 3.6875 | 2.3125 | 1.8750 | 2.1250 | 4.9375 | 1.0625 |
| 6 | 1.0 | 1.000 | 1.00 | 2.7500 | 1.5625 | 1.2500 | 1.5000 | 3.9375 | 1.0000 |
| 7 | 1.0 | 1.000 | 1.00 | 1.8750 | 1.0625 | 1.0625 | 1.0625 | 2.9375 | 1.0000 |
在经过 2.1 步删除了两个特征后, 还剩 7 个特征需要进行提取. 我们以 5 分钟为一个阶段. 特别的, 为了更好的利用时序数据, 我们让每一个 5 分钟区间都和前一个 5 分钟区间重合 4 分钟 (第一个区间除外). 这样对于一天共 1440 分钟, 我们会得到 1436 个区间. 也就是每个用户一天共有 1436 条样本数据.
对于 7 个特征. 我们尝试提取每一个区间中的均值 (mean) , 最小值 (min), 最大值 (max), 标准差 (std), 中位数 (median), 极差 (pk), 峰值因子 (kurt), 主频 (dominant frequency), 频谱质心 (spectral centroid), 频谱能量 (spectral energy) 和频谱带宽 (spectral bandwidth). 如果提取出来的特征与血糖的互信息计算结果小于临界值, 则认为该特征提取无效, 不加入最终的样本矩阵, 否则将其加入提取后的矩阵. 其中临界值为超参数.
对于血糖属性. 我们构造一个递推式生成函数用于计算每一个区间中发生高糖的先验概率. 具体的, 我们假设第 i 个区间超过阈值 (140 mg/dL) 的概率为
对于第一个式子, 它的目的是保证
最终可以得到 16 个用户共 16 个
对于上述 2.2 提取的结果, 我们有必要分析这全新的
对于相关性超过阈值的两个特征, 我们只保留其中一个. 得到最终的特征相关性矩阵如下 (共 21 个有效特征):
为了更好的利用数据, 我们添加 Demographics.csv 数据文件中的性别 (Gender) 和糖化血红蛋白指数 (HbA1c) 两个特征. 其中性别编码为 0 和 1, 糖化血红蛋白指数按 均值方差 归一化处理. 同时添加了一开始处理出来的时序特征, 即时间戳转化数据 (datetime). 最终有 24 维的特征数据.
由于高糖阶段相对于非高糖阶段极少, 因此有必要调整正负样本的比例. 我们定义高糖阶段为正样本, 非高糖阶段为负样本. 引入
我们首先使用机器学习算法中的串行式集成学习模型 XGBoost 进行训练与测试. 具体的, 我们在
| info | average | min | max |
|---|---|---|---|
| 0.7704 | 0.7211 | 0.8152 | |
| 0.6391 | 0.5689 | 0.7624 | |
| 38.7937 | 29.3371 | 47.3028 | |
| -4.2223 | -8.1471 | -2.1911 |
接着我们使用深度学习算法中的多层感知机模型 MLP 进行训练与测试. 同样的, 我们在
| info | average | min | max |
|---|---|---|---|
| 0.7703 | 0.7201 | 0.8152 | |
| 0.6414 | 0.5759 | 0.7624 | |
| 38.7937 | 29.3371 | 47.3028 | |
| -4.2094 | -8.1471 | -2.7533 |
对于项目所有涉及到的数据文件和 python 文件.
- 在数据预处理中. 我们首先编写了
data_gen.py文件将原始数据中多天的数据映射到了一天得到了./data/merged_data/数据集. 接着对这些以一天为最大单位的文件进行了清洗, 得到了./data/cleaned_data/数据集. - 在特征工程中. 我们首先编写了
data_draw.py文件中的draw_fft()函数可视化筛选出不合适的特征并删除了 bvp 和 ibi 两个特征, 接着编写了data_extractor.py文件得到了初步提取出来的以 5 分钟为一阶段的数据集./data/extraction_data/. 然后编写了data_draw.py文件中的draw_corr_matrix()函数可视化筛选出相关性较低的特征并调用data_extractor.py文件提取上述筛选出来的特征得到了./data/extraction_data_reduced/数据集. 在后续模型调用的逻辑中, 我们还添加了./data/Demographics.csv中的性别和糖化血红蛋白两个特征. - 在模型构建与评估中. 为了平衡正负样本的数量, 我们编写了
data_balance.py文件以过采样正例样本. 最后编写了models.py模型文件建立了机器学习模型 XGBoost 和深度学习模型 MLP 并在main.py中调用这两个模型来训练验证并预测, 得到了最终的预测结果.


