乳腺癌诊断数据集机器学习分类预测教程

一、教程概述

工具/软件介绍

  1. 核心工具:R 语言(统计计算与机器学习平台)及关键库
    • 数据处理:tidyverse(包含 dplyr 数据操作、 ggplot2 可视化等)
    • 建模工具:caret(统一建模流程)、 glmnet(正则化逻辑回归)、 ranger(高效随机森林)、 class(KNN 基础算法支持)
    • 可视化工具:corrplot(相关性热图)、 GGally(多元数据可视化)
  2. 开发背景:基于威斯康辛乳腺癌诊断数据集(WDBC),完整演示二分类问题的机器学习全流程(从数据预处理到模型部署评价)。

学习目标

  1. 掌握医学数据集的标准化预处理流程(含冗余特征移除、高相关特征筛选、数据拆分与标准化)。
  2. 熟练构建正则化逻辑回归(glmnet)、随机森林(含 ranger 高效实现)、 KNN 三种经典分类模型,并理解其适用场景。
  3. 生成并解读特征相关性热图、主成分方差贡献图、模型性能对比图、特征重要性排序图等核心可视化结果。
  4. 明确乳腺癌诊断的关键特征(如 area_worstperimeter_worst)及其临床意义。

二、一些前期准备(可以通过 openbayes 发布的教程中克隆)

核心文件说明

  1. 数据集data.csv(569 条样本,30 个细胞核特征,标签为良性(B)/恶性(M),含 id(样本编号)、 diagnosis(诊断结果)及 30 个形态学特征)。
  2. 代码文件:包含数据加载→预处理→EDA→特征工程→建模→评价的完整 R 脚本(可直接运行,需替换数据路径)。
  3. 依赖库清单(安装命令):
install.packages(c("tidyverse", "caret", "ranger", "corrplot", "GGally", "glmnet"))

关键技术流程

  1. 数据预处理:加载数据→移除冗余列(如 Xid)→标签类型转换(因子化)→缺失值检查。
  2. 特征工程:计算特征相关性矩阵→筛选高相关特征(阈值 0.9)→主成分分析(PCA)降维与可视化。
  3. 建模流程:数据集拆分(8:2 训练集/测试集)→10 折交叉验证参数调优→三种模型并行训练→混淆矩阵与性能指标评估。
  4. 评价指标:准确率(Accuracy)、 ROC 曲线下面积(AUC)、灵敏度(Sensitivity,恶性检出率)、特异度(Specificity,良性检出率)。

三、实操运行步骤

环境搭建

  1. 安装 R(官网下载)与 RStudio(推荐 IDE,官网下载)。
  2. 安装依赖库(见上文「依赖库清单」)。

数据加载与预处理

# 加载库
library(tidyverse)  # 数据处理核心库
library(caret)      # 建模与评价工具

加载数据(替换为实际路径)
data <- read.csv("path/to/data.csv")  
预处理:移除冗余列(X 为索引列,id 为样本编号,均非特征)
data <- data %>% select(-X, -id)  
标签转换:将 diagnosis(B/M)转为因子类型(分类模型要求)
data$diagnosis <- as.factor(data$diagnosis)  
查看数据结构(确认特征类型与样本量)
str(data)  
检查缺失值(该数据集无缺失,实际场景可补充插补步骤)
colSums(is.na(data))

探索性数据分析(EDA)

核心目标:了解特征分布与相关性,识别多重共线性问题。

library(corrplot)  # 相关性热图工具

计算特征相关性矩阵(排除标签列)
data_corr <- cor(data %>% select(-diagnosis))  
绘制聚类排序的相关性热图(便于识别高相关特征群)
corrplot(data_corr, order = "hclust", tl.cex = 0.6, addrect = 8)

结果解读

  • 半径(radius)、周长(perimeter)、面积(area)等特征间相关性>0.9,存在严重多重共线性,需通过特征筛选去除冗余。

主成分分析(PCA)

核心目标:通过降维简化数据结构,保留关键信息并可视化。

library(GGally)  # 多元可视化工具

步骤 1:移除高相关特征(阈值 0.9)
high_corr_indices <- findCorrelation(data_corr, cutoff = 0.9)  # 筛选高相关特征索引 
data2 <- data %>% select(-all_of(names(data)[high_corr_indices])) # 移除冗余特征 步骤 2:执行 PCA(需标准化与中心化) pca_data2 <- prcomp(data2, scale = TRUE, center = TRUE) 步骤 3:可视化方差贡献(确定核心主成分) explained_variance <- pca_data2$sdev^2 / sum(pca_data2$sdev^2) # 单个主成分方差占比
cumulative_variance <- cumsum(explained_variance) # 累积方差占比 variance_data <- data.frame(
PC = 1:length(explained_variance),
ExplainedVariance = explained_variance,
CumulativeVariance = cumulative_variance
)
ggplot(variance_data, aes(x = PC)) +
geom_bar(aes(y = ExplainedVariance), stat = "identity", fill = "skyblue", alpha = 0.7) +
geom_line(aes(y = CumulativeVariance), color = "red", size = 1) +
geom_point(aes(y = CumulativeVariance), color = "red") +
labs(
title = "主成分方差贡献图",
x = "主成分",
y = "方差解释比例"
) +
scale_y_continuous(sec.axis = sec_axis(~., name = "累积方差解释比例")) +
theme_minimal()

结果解读:前 3 个主成分累积解释方差约 70%-80%,可用于简化模型。

步骤 4:主成分与诊断标签关联可视化

# 提取前 3 个主成分得分,关联诊断标签
pca_scores <- as.data.frame(pca_data2$x[, 1:3])  # 前 3 个主成分
pca_scores$diagnosis <- data$diagnosis  # 加入诊断标签

绘制散点矩阵(含相关性、密度分布)
ggpairs(
pca_scores,
columns = 1:3,
mapping = aes(color = diagnosis, fill = diagnosis),
upper = list(continuous = wrap("cor", size = 3)), # 上三角:相关性
lower = list(continuous = "points"), # 下三角:散点图
diag = list(continuous = wrap("densityDiag")) # 对角线:密度分布
) +
theme_minimal() +
scale_color_manual(values = c("B" = "salmon", "M" = "cyan3")) +
scale_fill_manual(values = c("B" = "salmon", "M" = "cyan3"))

结果解读:恶性(M)与良性(B)样本在前 3 个主成分上分布差异明显,说明 PCA 有效保留了分类信息。

模型训练

数据集拆分(8:2)

set.seed(123)  # 固定随机种子,保证结果可复现

组合标签与处理后特征(便于建模)
data3 <- cbind(diagnosis = data$diagnosis, data2)  
按标签分层抽样(维持训练集/测试集类别比例一致)
data_sampling_index <- createDataPartition(data3$diagnosis, times = 1, p = 0.8, list = FALSE)
data_training <- data3[data_sampling_index, ] # 训练集(80%)
data_testing <- data3[-data_sampling_index, ] # 测试集(20%) 定义交叉验证策略(10 折交叉验证,计算分类概率与二分类指标)
data_control <- trainControl(
method = "cv",
number = 10,
classProbs = TRUE,
summaryFunction = twoClassSummary # 输出 ROC 、灵敏度、特异度
)

1. 正则化逻辑回归(glmnet)

# 训练模型(带 L1/L2 正则化,自动调优参数)
model_glmnet <- train(
  diagnosis ~ ., 
  data = data_training, 
  method = "glmnet",  # 正则化逻辑回归
  metric = "ROC",  # 以 ROC 为优化目标
  preProcess = c("scale", "center"),  # 特征标准化
  tuneLength = 20,  # 20 组参数候选
  trControl = data_control
)

2. 随机森林(两种实现方式)

方式 1:ranger 包(高效实现)

library(ranger)  # 快速随机森林工具

model_rf_ranger <- ranger(
diagnosis ~ .,
data = data_training,
probability = TRUE, # 输出概率
importance = "impurity", # 计算特征重要性(不纯度)
num.trees = 500 # 500 棵决策树
)

方式 2:caret 包集成的 rf(便于交叉验证)

model_rf_caret <- train(
  diagnosis ~ ., 
  data = data_training, 
  method = "rf",  # 传统随机森林
  metric = "ROC", 
  trControl = data_control,
  ntree = 500  # 500 棵决策树
)

3. KNN(K 近邻)

# 训练模型(优化邻居数 k)
model_knn <- train(
  diagnosis ~ ., 
  data = data_training, 
  method = "knn", 
  metric = "ROC", 
  preProcess = c("scale", "center"),  # KNN 对距离敏感,必须标准化
  trControl = data_control, 
  tuneLength = 31  # 测试 k= 1 到 31 的最优值
)

可视化不同 k 值的 ROC 表现(确定最优 k)
plot(model_knn, main = "KNN 模型不同邻居数的 ROC 表现")

模型预测与评价

1. 预测结果与混淆矩阵

以逻辑回归为例

# 测试集预测
prediction_glmnet <- predict(model_glmnet, data_testing)

生成混淆矩阵(评估分类准确性)
cm_glmnet <- confusionMatrix(prediction_glmnet, data_testing$diagnosis, positive = "M")
cm_glmnet # 输出准确率、灵敏度、特异度等指标

混淆矩阵可视化

# 转换为数据框用于绘图
cm_table <- as.table(cm_glmnet$table)
cm_df <- as.data.frame(cm_table)
colnames(cm_df) <- c("实际标签", "预测标签", "频数")

ggplot(cm_df, aes(x = 实际标签, y = 预测标签, fill = 频数)) +
geom_tile(color = "white") +
scale_fill_gradient(low = "lightblue", high = "blue") +
geom_text(aes(label = 频数), color = "black", size = 6) +
labs(title = "逻辑回归混淆矩阵", x = "实际诊断", y = "预测诊断") +
theme_minimal()

2. 特征重要性分析

随机森林特征重要性

# 提取前 10 个重要特征
importance_rf <- model_rf_ranger$variable.importance  # ranger 模型结果
importance_df <- data.frame(
  特征 = names(importance_rf), 
  重要性 = importance_rf
) %>% arrange(desc(重要性)) %>% slice(1:10)  # 取前 10

可视化
ggplot(importance_df, aes(x = reorder(特征, 重要性), y = 重要性)) +
geom_bar(stat = "identity", fill = "skyblue") +
coord_flip() + # 横向条形图,便于阅读特征名
labs(title = "随机森林 Top10 重要特征", x = "特征", y = "重要性(不纯度下降)") +
theme_minimal()

关键发现area_worst(肿瘤最大面积)、 perimeter_worst(肿瘤最大周长)是区分良恶性的核心特征,与临床认知一致。

四、模型对比与结果解读

多模型性能对比

# 汇总所有模型
model_list <- list(
  逻辑回归 = model_glmnet, 
  随机森林 = model_rf_caret, 
  KNN = model_knn
)

提取交叉验证结果
results <- resamples(model_list)
输出性能指标(ROC 、灵敏度、特异度)
summary(results)

可视化对比

# 箱线图:展示各模型 ROC 分布
bwplot(results, metric = "ROC", main = "模型 ROC 性能对比(10 折交叉验证)")

点图:带 95% 置信区间的性能指标
dotplot(results, metric = c("ROC", "Sens", "Spec"), main = "模型性能指标对比")

结果解读

  • 逻辑回归表现最优(ROC=0.993,灵敏度=0.989),适合作为基准模型。
  • 随机森林性能接近逻辑回归,但计算成本较高。
  • KNN 特异度略低(0.888),对良性样本的误判率稍高。

五、进阶操作

参数优化

  1. 随机森林调优(优化 mtry 参数,即每次分裂的特征数量):
model_rf_tuned <- train(
  diagnosis ~ ., 
  data = data_training, 
  method = "rf",
  metric = "ROC", 
  trControl = data_control,
  tuneGrid = expand.grid(mtry = seq(5, 15, 2))  # 测试 mtry=5,7,...,15
)
  1. 扩展模型:加入支持向量机(SVM)
model_svm <- train(
  diagnosis ~ ., 
  data = data_training, 
  method = "svmRadial",  # 径向核 SVM
  metric = "ROC", 
  trControl = data_control
)

六、附录

常用代码速查表

功能代码示例
数据读取read.csv("data.csv")
相关性热图corrplot(cor(data), order = "hclust")
10 折交叉验证设置trainControl(method = "cv", number = 10)
混淆矩阵计算confusionMatrix(pred, actual)
PCA 降维prcomp(data, scale = TRUE)

常见问题排查

  1. 报错 could not find function "corrplot"→ 解决方案:安装 corrplot 包(install.packages("corrplot"))。
  2. 特征维度错误→ 检查是否遗漏 select(-id, -diagnosis)步骤(需排除非特征列)。
  3. 模型训练缓慢→ 减少 ntree(随机森林树数量)或 tuneLength(参数候选数)。

通过本教程,能掌握一点医学二分类问题的机器学习流程,重点理解特征筛选、模型调优与结果可视化的核心逻辑,为其他疾病诊断建模提供参考。