【R语言机器学习】朴素贝叶斯(Naive Bayes)及K最近邻(KNN)的操作及拟合效果的ROC、PR、混淆矩阵两两比较

文摘   2024-12-29 21:56   山东  

在前期的分享中,我们演示了Logistic回归、决策树、随机森林、支持向量机、神经网络、XGBoost、lightGBM七种模型的简单操作示例和综合评价方法,今天,我们继续分享两种传统(或者说成熟)的机器学习方法:朴素贝叶斯(Naive Bayes)及K最近邻(KNN)的操作及拟合效果的两两比较。


朴素贝叶斯模型

‌朴素贝叶斯模型(Naive Bayes Model, NBM)是一种基于贝叶斯定理和特征条件独立性假设的分类算法‌。其核心思想是通过给定特征X的条件下,预测样本属于某类别c的后验概率P(c|X),选择后验概率最大的类别作为分类结果‌。




基本原理

朴素贝叶斯模型的基本原理基于贝叶斯定理,公式如下:

[ P(c|X) = \frac{P(X|c)P(c)}{P(X)} ]

其中:

( P(c|X) )表示在给定样本特征X的条件下,样本属于类别c的后验概率。

( P(X|c) )表示在类别c已知的情况下,样本特征X出现的概率。

( P(c) )表示类别c本身的概率。

( P(X) )表示样本特征X出现的总概率,通常用于归一化‌。

特征条件独立性假设

朴素贝叶斯模型的关键假设是特征之间在给定类别的情况下是相互独立的。这一假设极大地简化了计算,使得似然( P(X|c) )可以分解为各个特征的条件概率的乘积:

[ P(X|c) = \prod_{j=1}^n P(X^{(j)}|c) ]

这一假设虽然在实际中往往不完全成立,但在许多任务中仍然表现良好‌。

应用场景和优缺点

朴素贝叶斯模型在许多领域有广泛的应用,如文本分类、垃圾邮件识别等。其优点包括实现简单、计算效率高、所需估计的参数少;缺点是假设特征之间完全独立,这在现实中很少见,可能导致分类效果不佳‌。




‌K最近邻(KNN)

K最近邻(KNN)模型‌是一种简单且有效的机器学习算法,主要用于分类和回归任务。KNN的基本思想是:‌一个样本的类别或数值取决于其最邻近的k个邻居的类别或数值‌。具体来说,KNN通过计算待分类点与训练数据集中所有点的距离,选择距离最近的k个点作为邻居,然后根据这些邻居的类别或数值来预测该点的类别或数值‌。




KNN模型的工作原理

KNN算法的工作流程如下:

‌距离度量‌:KNN使用距离度量(如欧几里得距离、曼哈顿距离等)来确定数据点之间的相似性。最常见的距离度量是欧几里得距离‌。

‌选择K值‌:K是一个超参数,表示在进行决策时考虑的最近邻居的数量。K的选择对模型的性能有很大影响,一般通过网格搜索等方法来确定最佳的K值‌。

‌决策‌:对于分类任务,KNN算法通过多数投票法来预测新样本的类别;对于回归任务,则计算K个最近邻居的目标值的平均值作为新样本的目标值‌。

KNN模型的优缺点

‌优点‌:

‌简单易懂‌:KNN算法概念简单,容易理解和实现。

‌无需训练阶段‌:KNN没有显式的训练阶段,只需存储训练数据集,因此在数据集规模和特征数量相同的条件下,建模训练速度较快‌。

‌适用于小数据集‌:对于小数据集,KNN通常表现良好。

‌缺点‌:

‌计算量大‌:对于大规模数据集,计算每个测试样本与训练集中所有样本的距离非常耗时。

‌内存消耗大‌:需要存储所有训练数据以进行距离计算。

‌对异常值敏感‌:近邻的选择对异常值非常敏感,可能导致模型不稳定‌。

应用场景和实际案例

KNN算法在实际应用中有广泛的应用,例如:

‌文本分类‌:用于将文本数据分类到不同的类别中。

‌图像识别‌:通过比较图像特征来识别图像内容。

‌推荐系统‌:根据用户的购买或浏览历史推荐相关商品或内容‌。






今天我们仍以熟悉的示例数据集为例,演示一下朴素贝叶斯(Naive Bayes)及K最近邻(KNN)的操作及拟合效果的两两比较。










#数据准备,划分训练集测试集并保存

#分层抽样划分训练集和测试集

set.seed(1234)

train <- sample(1:nrow(data),nrow(data)*8/10) #取80%做训练集

#数据读取拆分与组合

Train <- data[train,]

Test <- data[-train,]

All <- rbind(Train, Test) 






#朴素贝叶斯(Naive Bayes)模型

# 加载必要的库

#使用klaR包中的NaiveBayes函数拟合朴素贝叶斯(Naive Bayes)模型

#安装加载包

install.packages("klaR")

library(klaR)

library(MASS)

library(e1071)





#因变量因子化与模型拟合

Train$Group<-as.factor(Train$结局)

Test$Group<-as.factor(Test$结局)

nb.fit<-NaiveBayes(Group ~ 指标1+指标2+指标3+指标4+指标5+指标6, 

                   data =Train)

nb.fit

summary(nb.fit)

par(mfrow = c(2, 3))  #6个变量一起看

plot(nb.fit)








#预测测试集数据

nb.pred<-predict(nb.fit,newdata =Test)

nb.pred

nb.pred$class








#构建混淆矩阵

nb.freq<-table(nb.pred$class, Test$结局)

nb.freq








#模型的准确率

nb.accuracy<-sum(diag(nb.freq))/sum(nb.freq)

nb.accuracy

#模型的AUC值

nb.modelroc<-roc(as.integer(Test$结局),

                 as.integer(nb.pred$class))

#绘制朴素贝叶斯(Naive Bayes)模型ROC曲线

par(mfrow = c(1, 1)) 

plot(nb.modelroc,print.auc=TRUE,auc.polygon = TRUE,

     grid =c(0.1,0.2),grid.col=c('green','red'),

     max.auc.polygon =TRUE,auc.polygon.col='steelblue')








#.K最近邻(KNN)模型

#数据整理

install.packages("dplyr")

library(dplyr)

library(caret)

library(stringr)

Trainknn <- Train[,c("指标1", "指标2", "指标3","指标4","指标5","指标6")]

Testknn <- Test[,c("指标1", "指标2", "指标3","指标4","指标5","指标6")]

#变量处理标准化

Trainknn  <- preProcess(Trainknn ,method = "scale") %>% predict(.,Trainknn )

Testknn  <- preProcess(Testknn ,method = "scale") %>% predict(.,Testknn )






#使用class包拟合K-近邻(KNN)算法

library(class)

library(pROC)

knnmodel <- knn(train = Trainknn, test = Testknn, cl = Train$结局, k = 49)

knnmodel

#根据最佳预测值对预测概率量化为预测结果

knn.pred <- as.numeric(knnmodel)

knn.pred

knn.pred <- ifelse(knn.pred == 1, 0, 1)

knn.pred 









#计算模型的AUC值(ROC曲线下面积)并绘制ROC曲线

auc <- auc(as.numeric(Test$结局),as.numeric(knnmodel))

auc

#ROC绘图

knn.modelroc<-roc(as.integer(Test$结局),

                  as.integer(knnmodel))

plot(knn.modelroc,print.auc=TRUE,auc.polygon = TRUE,

     grid =c(0.1,0.2),grid.col=c('green','red'),

     max.auc.polygon =TRUE,auc.polygon.col='steelblue')

# 计算准确率

mean(knnmodel == Test$CRBSI)








#组合绘制ROC曲线

roc01 <- roc(Test$结局,as.numeric(nb.pred$class));roc01

roc02 <- roc(Test$结局,as.numeric(knnmodel));roc02

plot(roc01,

     max.auc.polygon=FALSE,  # 填充整个图像

     smooth=F, # 绘制不平滑曲线

     main="ROC curves", # 添加标题

     col="red",  # 曲线颜色

     legacy.axes=TRUE)   # 使横轴从0到1,表示为1-特异度

plot.roc(roc02,

         add=T,  # 增加曲线

         col="green", # 曲线颜色为红色

         smooth = F)  # 绘制不平滑曲线

legend("bottomright", 

       legend = c("朴素贝叶斯模型AUC=0.953",

                  "KNN模型AUC=0.8965"),

       col = c("red","green"), 

       lwd = 1.5, cex = 0.75) 








#ROC曲线间的两两比较

roc.test(roc01,roc02,method = "delong") # 其他两种方法 “bootstrap”或“venkatraman”

plot(roc01,

     print.auc=TRUE, print.auc.x=0.4, print.auc.y=0.5,

     # 图像上输出AUC值,坐标为(x,y)

     auc.polygon=TRUE, auc.polygon.col="#fff7f7", # 设置ROC曲线下填充色

     max.auc.polygon=FALSE,  # 填充整个图像

     grid=c(0.5, 0.2), grid.col=c("black", "black"),  # 设置间距为0.1,0.2,线条颜色

     print.thres=TRUE, print.thres.cex=0.9, # 图像上输出最佳截断值,字体缩放倍数

     smooth=F, # 绘制不平滑曲线

     main="Comparison of two ROC curves", # 添加标题

     col="red",  # 曲线颜色

     legacy.axes=TRUE)   # 使横轴从0到1,表示为1-特异度

plot.roc(roc02,

         add=T,  # 增加曲线

         col="green", # 曲线颜色为红色

         print.thres=TRUE, print.thres.cex=0.9,  # 图像上输出最佳截断值,字体缩放倍数

         print.auc=TRUE, print.auc.x=0.4,print.auc.y=0.4,

         # 图像上输出AUC值,坐标为(x,y)

         smooth = F)  # 绘制不平滑曲线

testobj <- roc.test(roc01,roc02)   # 检验两条曲线

text(0.8, 0.2, labels=paste("P value =", format.pval(testobj$p.value)), adj=c(0, .5)) # 在图上添加P值

legend(0.35,0.30,  # 图例位置

       bty = "n",  # 图例样式,默认为 "o"

       title="",   # 引号内添加图例标题

       legend=c("朴素贝叶斯模型","KNN模型"),  # 添加分组

       col=c("red","green"),  # 颜色跟前面一致

       lwd=2)  # 线条粗细







#绘制PR曲线

plot(as.numeric(roc01$sens), as.numeric(roc01$spec), col="red", 

     xlab="Recall", ylab="Precision", 

     type="l", lwd=2, main="PR Curve")

lines(as.numeric(roc02$sens), as.numeric(roc02$spec), col="green", lwd=2)

legend("bottomleft", 

       legend=c("朴素贝叶斯模型",

                "KNN模型"), 

       col=c("red","green"), 

       lwd=2, lty=1)








#混淆矩阵因子转换及生成

library(ggplot2) #绘图用包

library(lattice) #绘图可视化包

library(caret)#加载混淆矩阵模型包

cm01 <- 

confusionMatrix(as.factor(Test$结局),

                        as.factor(nb.pred$class))

cm01

cm02 <- 

confusionMatrix(as.factor(Test$结局),

                        as.factor(knn.pred))

cm02








我们可以看到,上边的混淆矩阵评价指标中,

没有Precision 、Recall、F1三个指标,

我们在代码中加入

positive="1",

mode="everything"

然后,完整代码如下:

cm01 <- confusionMatrix(as.factor(Test$结局),

                        as.factor(nb.pred$class),

                        positive="1",

                        mode="everything")

cm01

cm02 <- confusionMatrix(as.factor(Test$结局),

                        as.factor(knn.pred),

                        positive="1",

                        mode="everything")

cm02

#批量计算输出各模型F1值

F1 <- data.frame(cm01[["byClass"]][["F1"]],

                 cm02[["byClass"]][["F1"]])

print(F1)

当然,我们前期分享的Logistic回归、决策树、随机森林、

支持向量机、神经网络、XGBoost、lightGBM七种模型,

也可以进行这样拟合效果的ROC、PR、混淆矩阵等方式

进行比较。






医学统计数据分析分享交流SPSS、R语言、Python、ArcGis、Geoda、GraphPad、数据分析图表制作等心得。承接数据分析,论文修回,医学统计,空间分析,问卷分析业务。若有投稿和数据分析代做需求,可以直接联系我,谢谢!




医学统计数据分析
分享交流SPSS、R语言、Python、ArcGis、Geoda、GraphPad、数据分析图表制作等心得。承接数据分析,论文修回,医学统计,空间分析,问卷分析业务。若有投稿和数据分析代做需求,可以直接联系我,谢谢!
 最新文章