卷三:模型篇——机器学习模型训练与评估
<div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 20px; border-radius: 12px; margin-bottom: 30px;">
<h3 style="color: white; margin: 0;">🎯 学习目标</h3>
<p style="color: #f0f0f0; margin: 10px 0 0 0;">掌握机器学习模型训练和评估的核心技术</p>
</div>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 15px; margin-bottom: 30px;">
<div style="background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
<strong style="color: #667eea;">📚 预计学习时长</strong><br>
<p style="margin: 10px 0 0 0;">3-4小时</p>
</div>
<div style="background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
<strong style="color: #667eea;">🔧 前置知识</strong><br>
<p style="margin: 10px 0 0 0;">Python基础、数据处理、基本统计学知识</p>
</div>
</div>
🏗️ 章节导航
- [[#5.1 机器学习基础]]
- [[#5.2 逻辑回归原理]]
- [[#5.3 类别不平衡处理]]
- [[#6.1 数据准备]]
- [[#6.2 模型构建]]
- [[#6.3 模型评估]]
- [[#6.4 模型优化]]
📚 本章导读
本章节深入讲解多模态抑郁检测系统的机器学习模型训练和评估技术。通过本章学习,您将:
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin: 20px 0;">
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; border-left: 4px solid #667eea;">
✅ 掌握机器学习基础概念和评估指标
</div>
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; border-left: 4px solid #667eea;">
✅ 深入理解逻辑回归算法原理
</div>
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; border-left: 4px solid #667eea;">
✅ 学会处理类别不平衡问题
</div>
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; border-left: 4px solid #667eea;">
✅ 掌握模型训练和优化的最佳实践
</div>
</div>
5.1 机器学习基础
5.1.1 监督学习概述
监督学习是机器学习的核心范式之一,其特点是:
- 训练数据:包含输入特征和对应的标签
- 学习目标:学习从输入到输出的映射关系
- 应用场景:分类问题、回归问题、序列预测等
分类问题 vs 回归问题深度解析:
# 分类问题示例:预测是否抑郁(二分类)
from sklearn.linear_model import LogisticRegression
clf = LogisticRegression()
clf.fit(X_train, y_train) # y_train 是 0/1 标签
y_pred = clf.predict(X_test)
# 回归问题示例:预测PHQ-8分数(连续值)
from sklearn.linear_model import Ridge
reg = Ridge()
reg.fit(X_train, y_score_train) # y_score_train 是连续的PHQ-8分数
y_pred_score = reg.predict(X_test)
核心概念深度解析
- 特征(Features):描述样本的属性,如音频特征、视频特征
- 标签(Labels):样本的真实结果,如抑郁/非抑郁
- 模型(Model):学习到的从特征到标签的映射函数
- 训练(Training):通过训练数据学习模型参数
- 预测(Prediction):使用训练好的模型对新数据进行预测
机器学习工作流程
数据收集 → 数据预处理 → 特征工程 → 模型选择 → 模型训练 → 模型评估 → 模型部署
5.1.2 模型评估指标
在抑郁检测任务中,评估指标的选择至关重要。由于数据集存在类别不平衡问题(抑郁样本约占30%),准确率(Accuracy)不是最佳选择。
关键评估指标深度解析:
from sklearn.metrics import accuracy_score, precision_score, recall_score, fbeta_score, roc_auc_score
# 计算评估指标
accuracy = accuracy_score(y_true, y_pred)
precision = precision_score(y_true, y_pred)
recall = recall_score(y_true, y_pred)
f2_score = fbeta_score(y_true, y_pred, beta=2)
auc = roc_auc_score(y_true, y_proba)
print(f"准确率: {accuracy:.4f}")
print(f"精确率: {precision:.4f}")
print(f"召回率: {recall:.4f}")
print(f"F2分数: {f2_score:.4f}")
print(f"AUC: {auc:.4f}")
指标数学定义
| 指标 | 公式 | 解释 |
|---|---|---|
| 准确率 | 正确预测的样本比例 | |
| 精确率 | 预测为抑郁的样本中,真正抑郁的比例 | |
| 召回率 | 真正抑郁的样本中,被正确预测的比例 | |
| Fβ分数 | $$1 + \beta^2$ \times \frac{precision \times recall}{\beta^2 \times precision + recall}$ | 综合考虑精确率和召回率 |
| AUC | ROC曲线下面积 | 模型区分正负样本的能力 |
抑郁检测场景的特殊考虑
- 漏检成本高:漏诊抑郁患者可能延误治疗,因此召回率尤为重要
- 误检成本:误诊可能导致不必要的心理负担,但相对漏检影响较小
- 指标选择:优先考虑F2分数(强调召回率)和召回率
混淆矩阵详解
预测正常 预测抑郁
实际正常 TN FP
实际抑郁 FN TP
5.1.3 交叉验证方法
交叉验证是评估模型泛化能力的重要方法:
from sklearn.model_selection import StratifiedKFold
# 分层5折交叉验证
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
for fold, (train_idx, test_idx) in enumerate(cv.split(X, y)):
X_train, X_test = X[train_idx], X[test_idx]
y_train, y_test = y[train_idx], y[test_idx]
# 在训练集上训练模型
model.fit(X_train, y_train)
# 在测试集上评估模型
y_pred = model.predict(X_test)
recall = recall_score(y_test, y_pred)
print(f"Fold {fold + 1}: Recall = {recall:.4f}")
交叉验证类型对比
| 类型 | 描述 | 优势 | 劣势 |
|---|---|---|---|
| K折交叉验证 | 将数据分成K份,轮流用K-1份训练,1份测试 | 充分利用数据 | 计算成本较高 |
| 分层交叉验证 | 保持各折中类别比例与原始数据一致 | 适合不平衡数据 | 实现稍复杂 |
| 留一交叉验证 | 每次留一个样本作为测试集 | 最充分利用数据 | 计算成本很高 |
| 留P交叉验证 | 每次留P个样本作为测试集 | 平衡计算成本和效果 | 需要选择合适的P值 |
交叉验证优势
- 充分利用数据:所有数据都参与训练和测试
- 减少随机因素:降低单次划分带来的随机性
- 提供可靠估计:给出更可信的模型性能评估
- 模型选择:帮助选择最佳模型参数
5.2 逻辑回归原理
5.2.1 逻辑回归基础
逻辑回归是一种常用的分类算法,尽管名字中有"回归",但它实际上是用于分类任务的:
from sklearn.linear_model import LogisticRegression
# 创建逻辑回归模型
model = LogisticRegression(
penalty='l1', # L1正则化
solver='liblinear', # 优化算法
class_weight='balanced', # 类别权重
random_state=42, # 随机种子
max_iter=1000 # 最大迭代次数
)
# 训练模型
model.fit(X_train, y_train)
# 预测类别和概率
y_pred = model.predict(X_test)
y_proba = model.predict_proba(X_test)[:, 1] # 预测为正类的概率
核心公式深度解析
- 线性预测:
- Sigmoid函数:
- 概率预测:
Sigmoid函数特性
- 值域:(0, 1),适合表示概率
- 单调性:单调递增函数
- 导数:
,便于梯度计算 - 解释性:可以解释为事件发生的概率
决策边界
- 阈值:通常使用0.5作为分类阈值
- 决策规则:当
时,预测为正类 - 几何意义:在特征空间中是一条直线(二分类)
5.2.2 正则化技术
正则化是防止过拟合的重要手段:
# L1正则化(Lasso)
model_l1 = LogisticRegression(penalty='l1', solver='liblinear')
# L2正则化(Ridge)
model_l2 = LogisticRegression(penalty='l2', solver='lbfgs')
# 弹性网(L1+L2)
from sklearn.linear_model import SGDClassifier
model_elastic = SGDClassifier(loss='log', penalty='elasticnet', l1_ratio=0.5)
正则化对比深度解析
| 正则化类型 | 惩罚项 | 效果 | 应用场景 |
|---|---|---|---|
| L1 (Lasso) | $\lambda \sum | w_i | $ |
| L2 (Ridge) | 限制权重大小,防止过拟合 | 一般情况,稳定性要求高 | |
| 弹性网 | $\lambda $\alpha \sum | w_i | + (1-\alpha) \sum w_i^2$$ |
正则化参数选择
- 参数λ:控制正则化强度,λ越大,正则化越强
- 网格搜索:使用交叉验证选择最佳λ值
- 贝叶斯优化:更高效的参数搜索方法
- 经验法则:从较小的λ开始尝试
正则化效果
- L1正则化:倾向于将不重要的特征权重置为0,实现特征选择
- L2正则化:倾向于让所有特征权重都较小,避免个别特征主导预测
- 弹性网:结合了特征选择和稳定性的优点
5.2.3 模型解释性
逻辑回归模型具有良好的解释性:
# 获取模型系数
coefficients = model.coef_[0]
intercept = model.intercept_[0]
# 创建特征重要性DataFrame
feature_importance = pd.DataFrame({
'feature': feature_names,
'coefficient': coefficients,
'abs_coefficient': np.abs(coefficients)
}).sort_values('abs_coefficient', ascending=False)
print("特征重要性排名:")
print(feature_importance.head(10))
系数解释深度解析
- 正系数:该特征值增加时,预测为抑郁的概率增加
- 负系数:该特征值增加时,预测为抑郁的概率减少
- 系数绝对值:反映特征对预测的重要程度
- 优势比:
,表示特征增加一个单位时,优势比的变化
实际应用
- 特征重要性分析:识别与抑郁最相关的特征
- 临床辅助决策:为医生提供AI决策依据
- 模型调试:理解模型为什么做出特定预测
- 特征工程指导:指导后续的特征选择和工程
可视化解释
import matplotlib.pyplot as plt
# 可视化特征重要性
plt.figure(figsize=(10, 6))
plt.barh(feature_importance['feature'][:10], feature_importance['abs_coefficient'][:10])
plt.xlabel('系数绝对值')
plt.title('特征重要性排名(前10名)')
plt.gca().invert_yaxis()
plt.tight_layout()
plt.show()
5.3 类别不平衡处理
5.3.1 类别不平衡问题
在抑郁检测数据集中,抑郁样本约占30%,正常样本约占70%,存在明显的类别不平衡问题:
# 计算类别分布
class_counts = np.bincount(y)
class_ratio = class_counts[0] / class_counts[1]
print(f"正常样本数: {class_counts[0]}")
print(f"抑郁样本数: {class_counts[1]}")
print(f"类别比例: {class_ratio:.2f}:1")
类别不平衡的影响深度解析
- 模型偏向多数类:模型倾向于预测为多数类(正常)
- 评估指标失真:高准确率可能掩盖对少数类(抑郁)的识别能力
- 决策边界偏移:默认的0.5阈值可能不适合不平衡数据
- 学习偏差:模型对少数类的学习不足
不平衡程度评估
- 不平衡比率:多数类样本数 / 少数类样本数
- 常用阈值:
- 轻微不平衡:2:1 ~ 5:1
- 中度不平衡:5:1 ~ 10:1
- 严重不平衡:> 10:1
5.3.2 SMOTE算法原理
SMOTE(Synthetic Minority Oversampling Technique)是一种常用的过采样算法:
from imblearn.over_sampling import SMOTE
from imblearn.pipeline import Pipeline
# 创建包含SMOTE的Pipeline
pipeline = Pipeline([
('scaler', StandardScaler()),
('smote', SMOTE(random_state=42, k_neighbors=2)),
('clf', LogisticRegression(class_weight='balanced'))
])
# 训练模型
pipeline.fit(X_train, y_train)
SMOTE算法步骤深度解析
- 找到近邻:对每个少数类样本,找到其k个最近邻
- 生成合成样本:在少数类样本和其最近邻之间随机插值
- 重复生成:直到少数类样本数量达到期望比例
SMOTE算法伪代码
for each minority sample x_i:
find k nearest neighbors of x_i
for each neighbor x_j:
generate synthetic sample: x_new = x_i + rand(0,1) * (x_j - x_i)
参数选择
- k_neighbors:近邻数量,通常选择2-5
- sampling_strategy:过采样比例,可以是具体数值或’auto’
- random_state:随机种子,确保结果可复现
SMOTE优势
- 避免过拟合:生成新的合成样本,而非简单复制
- 增加多样性:提高少数类样本的多样性
- 改善决策边界:使决策边界更加合理
- 易于实现:算法实现简单,计算效率较高
5.3.3 类别权重调整
除了SMOTE过采样,还可以通过调整类别权重来处理不平衡问题:
# 方法1:使用class_weight参数
model = LogisticRegression(class_weight='balanced')
# 方法2:手动指定权重
weights = {0: 1, 1: 3} # 给抑郁样本更高权重
model = LogisticRegression(class_weight=weights)
# 方法3:在损失函数中调整权重
from sklearn.utils.class_weight import compute_class_weight
class_weights = compute_class_weight('balanced', classes=np.unique(y), y=y)
class_weight参数深度解析
- None:所有类别的权重相等
- ‘balanced’:根据类别频率自动计算权重
- 字典:手动指定每个类别的权重
权重计算方法
- balanced模式:权重与类别频率成反比
- 计算公式:
- n:总样本数
- k:类别数
:第i类的样本数
适用场景
- 样本量较小:避免SMOTE生成过多合成样本
- 计算资源有限:类别权重调整计算成本低
- 结合使用:与SMOTE结合使用,进一步提升效果
- 快速验证:作为快速验证的方法
6.1 数据准备
6.1.1 特征标准化
特征标准化是机器学习预处理的重要步骤:
from sklearn.preprocessing import StandardScaler
# 创建标准化器
scaler = StandardScaler()
# 在训练集上拟合并转换
X_train_scaled = scaler.fit_transform(X_train)
# 在测试集上应用相同的转换
X_test_scaled = scaler.transform(X_test)
标准化原理深度解析
- 标准化公式:
:训练集特征的均值 :训练集特征的标准差 - 目标:将特征转换为均值为0,标准差为1的分布
标准化的重要性
- 加速收敛:加快梯度下降的收敛速度
- 消除尺度影响:避免不同尺度特征的影响
- 提高稳定性:提高模型的稳定性和性能
- 算法要求:某些算法(如SVM、神经网络)对特征尺度敏感
注意事项
- 避免数据泄露:必须在训练集上拟合,然后应用到测试集
- 保存标准化器:需要保存scaler用于推理阶段
- 处理异常值:标准化前应处理异常值
- 特征类型:标准化适用于连续型特征
6.1.2 特征选择方法
特征选择可以减少冗余特征,提高模型性能:
from sklearn.feature_selection import SelectKBest, f_classif
# 选择最佳的k个特征
selector = SelectKBest(f_classif, k=25)
# 在训练集上拟合并转换
X_train_selected = selector.fit_transform(X_train, y_train)
# 在测试集上应用相同的选择
X_test_selected = selector.transform(X_test)
# 获取被选中的特征索引
selected_indices = selector.get_support(indices=True)
selected_features = [feature_names[i] for i in selected_indices]
特征选择方法对比
| 方法类型 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| Filter方法 | 基于统计检验选择特征 | 计算高效,不依赖模型 | 忽略特征间交互 |
| Wrapper方法 | 基于模型性能选择特征 | 考虑特征交互 | 计算成本高 |
| Embedded方法 | 特征选择融入模型训练 | 计算高效,考虑模型 | 依赖特定模型 |
常用选择标准
- f_classif:计算每个特征与标签的ANOVA F值
- mutual_info_classif:计算互信息
- chi2:卡方检验,适用于非负特征
- SelectPercentile:选择前N%的特征
特征数量选择
- 交叉验证:使用交叉验证确定最佳特征数量
- 网格搜索:搜索不同的k值
- 经验法则:从特征总数的1/2或1/3开始尝试
- 性能曲线:绘制特征数量与模型性能的关系曲线
6.1.3 训练集与测试集划分
合理的数据划分是模型评估的基础:
from sklearn.model_selection import train_test_split, StratifiedKFold
# 简单划分(保持类别比例)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
# 分层K折交叉验证
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
划分策略深度解析
- 随机划分:简单随机分配样本
- 分层划分:保持各集中类别比例一致
- 时间序列划分:按时间顺序划分(不适用于本项目)
- 分组划分:按特定组划分,避免数据泄露
划分比例选择
- 常见比例:70-80%训练,20-30%测试
- 交叉验证:K折交叉验证,充分利用数据
- 样本量考虑:样本量小时,使用交叉验证
- 验证集:考虑使用验证集进行模型调参
注意事项
- 数据泄露:划分后训练集和测试集必须完全分离
- 随机种子:设置random_state确保结果可复现
- 类别平衡:使用stratify参数保持类别比例
- 测试集使用:测试集只能用于最终评估,不能用于调参
6.2 模型构建
6.2.1 Pipeline设计
Pipeline是scikit-learn中用于组织机器学习工作流的重要工具:
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.feature_selection import SelectKBest
from sklearn.linear_model import LogisticRegression
from imblearn.over_sampling import SMOTE
# 创建完整的Pipeline
pipeline = Pipeline([
('scaler', StandardScaler()),
('selector', SelectKBest(f_classif, k=25)),
('smote', SMOTE(random_state=42, k_neighbors=2)),
('clf', LogisticRegression(
penalty='l1',
solver='liblinear',
class_weight='balanced',
random_state=42,
max_iter=1000
))
])
# 训练整个Pipeline
pipeline.fit(X_train, y_train)
# 预测
y_pred = pipeline.predict(X_test)
y_proba = pipeline.predict_proba(X_test)[:, 1]
Pipeline优势深度解析
- 代码简洁:将多个步骤组合成一个对象
- 避免数据泄露:确保每个步骤只在训练集上拟合
- 方便调参:支持GridSearchCV进行参数搜索
- 易于部署:整个工作流可以作为一个整体保存和加载
Pipeline组件设计
- 数据预处理:标准化、归一化等
- 特征选择:选择重要特征
- 不平衡处理:SMOTE等过采样方法
- 模型训练:分类或回归模型
Pipeline使用技巧
- 命名约定:给每个步骤起清晰的名称
- 参数访问:使用
pipeline.named_steps['step_name']访问步骤 - 保存加载:整个pipeline可以一次性保存和加载
- 嵌套Pipeline:支持嵌套Pipeline处理复杂流程
6.2.2 模型参数配置
逻辑回归的关键参数配置:
# 基础配置
model = LogisticRegression(
penalty='l1', # 正则化类型:'l1', 'l2', 'elasticnet', 'none'
dual=False, # 是否使用对偶形式(仅适用于l2正则化)
tol=1e-4, # 收敛阈值
C=1.0, # 正则化强度的倒数(值越小,正则化越强)
fit_intercept=True, # 是否拟合截距
intercept_scaling=1, # 截距缩放因子
class_weight='balanced', # 类别权重
random_state=42, # 随机种子
solver='liblinear', # 优化算法
max_iter=1000, # 最大迭代次数
multi_class='auto', # 多分类策略
verbose=0, # 详细程度
warm_start=False, # 是否使用上次训练的结果作为初始值
n_jobs=None, # 并行作业数量
l1_ratio=None # L1正则化比例(仅用于elasticnet)
)
参数深度解析
- penalty:选择正则化类型,L1适合特征选择,L2适合一般情况
- solver:优化算法选择,’liblinear’支持L1正则化,’lbfgs’适合大数据集
- C:正则化强度,较小的值表示更强的正则化
- class_weight:处理类别不平衡问题
- max_iter:最大迭代次数,确保模型收敛
参数调优方法
from sklearn.model_selection import GridSearchCV
# 定义参数网格
param_grid = {
'clf__penalty': ['l1', 'l2'],
'clf__C': [0.1, 1.0, 10.0],
'selector__k': [15, 20, 25, 30]
}
# 使用网格搜索
grid_search = GridSearchCV(pipeline, param_grid, cv=5, scoring='recall')
grid_search.fit(X_train, y_train)
# 获取最佳参数
print("最佳参数:", grid_search.best_params_)
print("最佳得分:", grid_search.best_score_)
调优策略
- 网格搜索:穷举搜索参数组合
- 随机搜索:随机采样参数组合,效率更高
- 贝叶斯优化:基于贝叶斯定理的参数优化
- 手动调优:基于经验和领域知识手动调整
6.2.3 多模态融合策略
本项目采用多模态特征融合方法:
# 特征级融合:直接拼接音频和视频特征
audio_features = df[audio_feature_cols].values
video_features = df[visual_feature_cols].values
multimodal_features = np.concatenate([audio_features, video_features], axis=1)
# 训练多模态模型
multimodal_pipeline.fit(multimodal_features, y)
# 训练单模态模型作为备用
audio_pipeline.fit(audio_features, y)
video_pipeline.fit(video_features, y)
融合策略对比深度解析
| 融合层次 | 方法 | 优点 | 缺点 |
|---|---|---|---|
| 特征级融合 | 特征拼接 | 简单直接,充分利用所有特征 | 特征维度高,可能包含冗余信息 |
| 决策级融合 | 模型投票、加权融合 | 灵活性高,可处理不同模态 | 需要单独训练多个模型 |
| 模型级融合 | 多输入神经网络 | 自动学习模态间关系 | 复杂度高,需要大量数据 |
本项目融合策略
- 主要方法:采用特征级融合作为主要方法
- 备用方案:同时训练单模态模型作为备用
- 自动选择:支持根据输入数据类型自动选择合适的模型
- 加权融合:在决策层面进行加权融合
融合优势
- 信息互补:音频和视频特征提供不同维度的信息
- 鲁棒性增强:单个模态质量不佳时仍能获得较好结果
- 准确性提升:融合结果通常优于单模态
- 灵活适应:支持不同类型的输入数据
6.3 模型评估
6.3.1 混淆矩阵分析
混淆矩阵是评估分类模型的重要工具:
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
import matplotlib.pyplot as plt
# 计算混淆矩阵
cm = confusion_matrix(y_true, y_pred)
# 显示混淆矩阵
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=['正常', '抑郁'])
disp.plot(cmap='Blues')
plt.title('混淆矩阵')
plt.show()
# 提取指标
TN, FP, FN, TP = cm.ravel()
print(f"真阴性(TN): {TN}")
print(f"假阳性(FP): {FP}")
print(f"假阴性(FN): {FN}")
print(f"真阳性(TP): {TP}")
混淆矩阵解读深度解析
- 真阴性(TN):正常样本被正确预测为正常
- 假阳性(FP):正常样本被错误预测为抑郁(误报)
- 假阴性(FN):抑郁样本被错误预测为正常(漏报)
- 真阳性(TP):抑郁样本被正确预测为抑郁
关键指标计算
- 准确率:
- 精确率:
- 召回率:
- F1分数:
业务意义
- 漏报(FN):抑郁患者被漏诊,可能延误治疗
- 误报(FP):正常人被误诊,造成不必要的心理负担
- 权衡:在抑郁检测中,通常优先减少漏报
6.3.2 ROC曲线与AUC
ROC曲线和AUC是评估模型性能的重要指标:
from sklearn.metrics import roc_curve, auc, RocCurveDisplay
import matplotlib.pyplot as plt
# 计算ROC曲线
fpr, tpr, thresholds = roc_curve(y_true, y_proba)
roc_auc = auc(fpr, tpr)
# 绘制ROC曲线
plt.figure()
plt.plot(fpr, tpr, color='blue', lw=2, label=f'ROC曲线 (AUC = {roc_auc:.3f})')
plt.plot([0, 1], [0, 1], color='gray', lw=2, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('假阳性率')
plt.ylabel('真阳性率')
plt.title('受试者工作特征曲线')
plt.legend(loc="lower right")
plt.show()
ROC曲线解读深度解析
- 横轴:假阳性率(1 – 特异性)
- 纵轴:真阳性率(召回率)
- 对角线:随机猜测的性能
- 曲线位置:曲线越靠近左上角,模型性能越好
AUC解读
- AUC = 1:完美分类器,所有正样本排在负样本前面
- AUC = 0.5:随机猜测,没有区分能力
- AUC > 0.5:模型优于随机猜测
- AUC > 0.8:模型性能良好
- AUC > 0.9:模型性能优秀
最佳阈值选择
- Youden指数:
- 最大F1分数:选择使F1分数最大的阈值
- 临床需求:根据临床需求调整阈值
- 成本分析:考虑不同错误类型的成本
6.3.3 阈值优化
在不平衡数据中,默认的0.5阈值往往不是最优的:
def find_optimal_threshold(y_true, y_proba, beta=2):
"""
寻找最优阈值,最大化F-beta分数
参数:
y_true: 真实标签
y_proba: 预测概率
beta: F-beta分数的权重参数
返回:
best_threshold: 最优阈值
best_score: 最佳F-beta分数
"""
best_threshold = 0.5
best_score = 0
# 搜索阈值范围
for threshold in np.linspace(0.1, 0.9, 41):
y_pred = (y_proba >= threshold).astype(int)
score = fbeta_score(y_true, y_pred, beta=beta)
if score > best_score:
best_score = score
best_threshold = threshold
return best_threshold, best_score
# 寻找最优阈值
optimal_threshold, optimal_f2 = find_optimal_threshold(y_true, y_proba, beta=2)
print(f"最优阈值: {optimal_threshold:.3f}")
print(f"最佳F2分数: {optimal_f2:.4f}")
阈值优化方法深度解析
- 网格搜索:在阈值范围内搜索最佳值
- F-beta分数:根据业务需求调整beta值
- 成本敏感:考虑不同错误类型的成本
- 临床指导:结合临床知识确定阈值
阈值选择策略
- 高召回率需求:选择较低的阈值,减少漏报
- 高精确率需求:选择较高的阈值,减少误报
- 平衡需求:选择F1分数最优的阈值
- 动态调整:根据不同场景调整阈值
实际应用
- 保存阈值:将最优阈值保存用于推理阶段
- 阈值校准:使用校准技术调整阈值
- 阈值监控:定期重新评估和调整阈值
- 阈值解释:向用户解释阈值选择的依据
6.4 模型优化
6.4.1 特征重要性分析
特征重要性分析有助于理解模型决策过程:
# 获取特征重要性
feature_importance = pd.DataFrame({
'feature': feature_names,
'coefficient': model.coef_[0],
'abs_coefficient': np.abs(model.coef_[0])
}).sort_values('abs_coefficient', ascending=False)
# 显示最重要的特征
print("最重要的特征:")
print(feature_importance.head(10))
# 可视化特征重要性
plt.figure(figsize=(10, 6))
plt.barh(feature_importance['feature'][:10], feature_importance['abs_coefficient'][:10])
plt.xlabel('系数绝对值')
plt.title('特征重要性排名(前10名)')
plt.gca().invert_yaxis()
plt.tight_layout()
plt.show()
特征重要性解读深度解析
- 系数符号:正系数表示该特征与抑郁正相关,负系数表示负相关
- 系数大小:绝对值越大,特征对预测的影响越大
- 特征分组:可以按模态(音频/视频)分析特征重要性
- 临床意义:分析重要特征与临床症状的关联
实际应用
- 特征选择:识别与抑郁最相关的特征
- 模型简化:移除不重要的特征,简化模型
- 临床研究:为临床研究提供线索
- 特征工程指导:指导后续的特征工程工作
可视化技巧
- 水平条形图:适合显示特征重要性排名
- 颜色编码:使用颜色表示相关性方向
- 分组显示:按模态分组显示特征重要性
- 交互式图表:使用交互式图表展示详细信息
6.4.2 阈值校准与优化
阈值校准是提高模型性能的重要步骤:
# 跨折聚合概率,用于阈值优化
cv_proba = []
cv_true = []
for fold, (train_idx, test_idx) in enumerate(cv.split(X, y)):
X_train, X_test = X[train_idx], X[test_idx]
y_train, y_test = y[train_idx], y[test_idx]
pipeline.fit(X_train, y_train)
y_proba = pipeline.predict_proba(X_test)[:, 1]
cv_proba.extend(y_proba.tolist())
cv_true.extend(y_test.tolist())
# 寻找跨折最优阈值
optimal_threshold, optimal_f2 = find_optimal_threshold(cv_true, cv_proba)
# 保存阈值
with open('thresholds.json', 'w') as f:
json.dump({'optimal_threshold': optimal_threshold}, f)
阈值校准方法深度解析
- 跨折验证:使用交叉验证的概率进行阈值优化
- 健康组参考:基于健康组的概率分布设置阈值
- 动态调整:根据新数据定期调整阈值
- 校准曲线:使用校准曲线评估概率校准程度
阈值保存与应用
- 配置文件:将最优阈值保存到配置文件
- 推理应用:推理时使用保存的阈值进行预测
- 多模态阈值:支持不同模态使用不同的阈值
- 阈值版本控制:记录阈值的版本信息
校准技术
- Platt缩放:使用sigmoid函数校准概率
- 等渗回归:使用非参数方法校准概率
- 直方图校准:使用直方图进行概率校准
- Beta校准:使用Beta分布进行概率校准
6.4.3 模型保存与加载
模型的保存和加载是部署的关键步骤:
import joblib
# 保存模型
joblib.dump(pipeline, 'depression_model.pkl')
# 保存特征列信息
with open('feature_schema.json', 'w') as f:
json.dump({'feature_columns': feature_names}, f)
# 加载模型
loaded_pipeline = joblib.load('depression_model.pkl')
# 加载特征列信息
with open('feature_schema.json', 'r') as f:
feature_schema = json.load(f)
# 使用模型进行预测
y_pred = loaded_pipeline.predict(X_new)
模型保存格式对比
| 格式 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| joblib | 高效的序列化,支持大型对象 | 仅Python可用 | scikit-learn模型 |
| pickle | 标准Python序列化 | 安全性问题,效率较低 | 通用Python对象 |
| ONNX | 跨框架兼容 | 需要额外库,转换复杂 | 跨平台部署 |
| HDF5 | 支持大型数据 | 依赖h5py库 | 深度学习模型 |
保存内容深度解析
- 完整Pipeline:保存整个预处理和模型流程
- 特征列信息:确保推理时特征顺序正确
- 阈值配置:保存最优阈值
- 模型元数据:训练日期、版本、参数等信息
模型版本管理
- 版本命名:使用版本号命名模型文件
- 训练日志:保存训练日志和评估结果
- 模型卡片:创建模型卡片记录模型信息
- 自动化流程:建立自动化的模型版本管理流程
🎯 本章总结
核心知识点回顾
-
机器学习基础
- ✅ 监督学习概念和应用场景深度解析
- ✅ 模型评估指标及其选择策略
- ✅ 交叉验证方法和实现
-
逻辑回归
- ✅ 算法原理和数学基础深度解析
- ✅ 正则化技术和参数配置
- ✅ 模型解释性分析和可视化
-
类别不平衡处理
- ✅ SMOTE过采样算法原理和实现
- ✅ 类别权重调整策略
- ✅ 阈值优化方法
-
模型构建与评估
- ✅ Pipeline设计和使用最佳实践
- ✅ 特征选择和标准化方法
- ✅ 混淆矩阵和ROC曲线分析
重点/易错点总结
重点掌握:
- 逻辑回归模型的原理和参数配置
- 类别不平衡问题的处理方法
- 模型评估指标的选择和解读
- Pipeline的设计和使用
常见错误:
- ❌ 使用准确率评估不平衡数据:导致评估结果失真,解决方案:使用F2分数和召回率
- ❌ 在整个数据集上进行标准化:导致数据泄露,解决方案:在训练集上拟合,测试集上转换
- ❌ 忽略阈值优化:直接使用默认的0.5阈值,解决方案:使用交叉验证优化阈值
- ❌ 保存模型时忽略特征列信息:导致推理时特征顺序错误,解决方案:保存特征列信息
学习建议
- 实践练习:尝试使用不同的模型和参数
- 参数调优:使用网格搜索优化模型参数
- 特征分析:深入分析特征重要性和相关性
- 模型对比:尝试其他分类算法进行对比
- 部署实践:学习模型部署和服务化技术
📚 参考资源
- [[scikit-learn官方文档]]
- [[机器学习实战]]
- [[SMOTE算法论文]]
- [[ROC曲线和AUC详解]]
- [[Python机器学习手册]]
下一章预告:[[毕设项目学习笔记/04_卷四_应用篇]] – 深入讲解推理系统设计和用户界面开发