本文章是基于R语言一个数据挖掘的案例实现(预测糖尿病),主要内容包括: 数据源介绍——缺失值分析及填补——数据集拆分——建立模型及优化——总结
希望内容对大家有所收获,如有疑问欢迎沟通
数据源介绍
本次数据挖掘的数据来自于印第安人糖尿病数据库,数据源名称PimaIndiansDiabetes2,
可以通过以下途径进行获取
# 获取数据
library(mlbench)
data(PimaIndiansDiabetes2)
alldata<-PimaIndiansDiabetes2
数据源总共768条记录,9个字段,含有缺失值
缺失值分析
图是缺失值分布,可以看出缺失值得行数较多,将近50%记录数有缺失,所以不能采取将缺失值全部删除的做法。完整记录数392个,有缺失记录的个数376个,缺失值集中在insulin、triceps这两个字段,两者都缺失的记录数192个,insulin单独缺失的记录数140,glucose单独缺失的记录数只有1个
#缺失值数据探索
library(mice)
#缺失值表格展示
md.pattern(alldata)
运行结果如下:
#缺失值可视化
library("VIM")
aggr(alldata,prop=FALSE,numbers = TRUE)
缺失值填充
KNN插补
首先解释一下为啥用k近邻算法进行插补,因为k近邻算法依据“近朱者赤近墨者黑”的原理,利用缺失值附近的k个已知值维度上的数值进行平均值插补或者距离加权再插补,所以插补的值只和周围特定的值相关,所以一般而言这种插补方法相比较而言比较好
# K近邻算法进行插补
library(DMwR)
#使用knn加权平均算法进行插补计算,其中k是选择紧邻缺失值的10个点进行插补,scale表示对数#据集进行归一化,meth设置计算方法
knndata<-knnImputation(alldata,k= 10,scale = T,meth= "weighAvg")
# 验证一下是否还存在缺失,False表示无缺失值
anyNA(knndata)
# 查看数据集信息
summary(knndata)
多重插补(mice)
多重插补(MI)是基于重复模拟的处理缺失值的方法,在面对复杂的缺失问题时,MI是最常选用的方
法,它将从一个包含缺失值的数据集中生成一组完整的数据集(默认是5个)
#使用mice插补方法
library(mice)
# 基于随机森林算法的mice的缺失值插补方法(具体方法可以见R的函数帮助),模型会生出5组缺失值填补数据集
micedata<-mice(alldata,method = 'rf',m=5)
micedata1<-complete(micedata)# 生成完整数据集
# 进行判断是否还有缺失值,false表示无缺失值
anyNA(micedata1)
summary(micedata1) ##查看数据详情
注明:这里我们选用第一种knn方法填补的缺失值数据集,下面的建立模型都是使用这个数据集knndata
生成训练集和测试集
我们将对数据集按照变量diabetes等比例抽样,建立训练集(80%)和测试集(20%),这里要使用caret包里面的createDataPartition函数来进行抽样
#数据集等比例抽取
library(caret)
# 第一个参数是按照哪个变量进行等比例抽取,times表示抽样次数,p表示抽取索引占比,
#list是否生成列表
index1<-createDataPartition(knndata$diabetes,times= 1,p=0.8,list = FALSE)
# 生成训练集和测试数据集
traindata_glm<-knndata[index1,] # 训练集
testdata_glm<-knndata[-index1,] # 测试集
prop.table(table(traindata_glm$diabetes)) #检验抽取后比例
prop.table(table(knndata$diabetes))
执行结果如下
模型搭建及预测
这里将使用三种数据挖掘的方法来建模,它们分别是广义线性回归(GLM)、随机森林算法(randomForest)以及朴素贝叶斯分类,为什么选用这三种方法呢,首先广义线性回归算法易于理解和操作,方便后期解释,而随机森林算法在常见的决策树、knn、SVM中属于复合模型(决策树模型加强版),所以它模型结果的准确率一般来说都相对于其他几个表现得更好,而朴素贝叶斯分类在分类问题上使用的比较多。
一:变量间相关系数参看
#查看变量间相关性
cor(knndata[c(1:8)])
library(corrgram)
corrgram(knndata,order= TRUE,lower.panel = panel.cor,upper.panel = panel.pie,
text.panel = panel.txt,main ='knndata数据集变量间的相关性')
执行结果如下,可以看出glucose和insulin,triceps和mass,pregnant和age这三组变量之间相关
系数在0.5-0.7之间,整体而言应该是不存在共线性的干扰,
二:使用GLM广义线性回归建模(knndata数据集)
#建立glm回归模型----1
knn_logit<-glm(diabetes~.,data =traindata_glm,family = binomial())
summary(knn_logit)
# 检查变量之间的多重共线性
#这里我们使用统计量VIF(方差膨胀因子)进行检查,一般原则下,
#vif的平方根大于2表明存在多重共线性问题
library(car)
vif(knn_logit)
sqrt(vif(knn_logit))
# type=response 预测结果是概率值
prop<-predict(knn_logit,testdata_glm[c(-9)],type ='response')
par(mfrow=c(2,2))
plot(knn_logit)
logit.pred<-ifelse(prop>0.5,'pos','neg')
# 生成预测结果的混淆矩阵
table(testdata_glm$diabetes,logit.pred,dnn =c('Real','Predicted'))
运行结果如下图所示:预测的结果准确率79.7%(122/153)presssure、triceps、age这三个变量的F值没有达到显著性相关(p>0.05),说明这些变量对因变量走向影响较小,但是不确定哪些变量一定有用,所以接下来我们使用逐步回归step()函数
#逐步回归方法
knn_step<-step(knn_logit)
knn_logit2<-glm(diabetes~pregnant+mass+pedigree+glucose,data= traindata_glm,family = binomial())
summary(knn_logit2)
prop1<-predict(knn_logit2,testdata_glm[c(-9)],type= 'response')
logit.pred1<-ifelse(prop1>0.5,'pos','neg')
table(testdata_glm$diabetes,logit.pred1,dnn= c('Real','Predicted'))
#对前后两个模型做卡方检验,p>0.05说明新模型更好
anova(knn_logit,knn_logit2,test= 'Chisq')
采用step()函数可以的得知
glm(diabetes~pregnant+mass+pedigree+glucose,data= traindata_glm,family = binomial())
时,AIC的值最小,该模型四个变量都显著相关(p<0.05),而且两个模型的卡方检验值大于0.05,
说明新模型更优利用逐步回归模型之后新模型进行预测,得到的预测结果的准确率78.4%(120/153),
运行结果如下:
三:利用随机森林算法建模
#基于随机森林算法
library(randomForest)
set.seed(1234)
knn_forest<-randomForest(diabetes~.,data=traindata_glm,na.action=na.roughfix,importance=TRUE)
knn_forest
# 各个变量的重要性
importance(knn_forest,type = 2)
forest.pred<-predict(knn_forest,testdata_glm[c(-9)])#对测试数据集预测
#生出预测结果的混淆矩阵
table(testdata_glm$diabetes,forest.pred,dnn =c('Real','Predicted'))
执行结果如下:
从下面执行的结果可以看出,随机森林每次选择两个变量,建立500个决策树进行建模分析,从变量的重要性来看,glucose、insulin、mass、age四个变量重要性依次从高到低(MeanDecreaseGini系数越高表示越重要)),模型预测结果准确率79%(121/153)
四:利用朴素贝叶斯算法进行预测
##朴素贝叶斯方法实现,通过e1071包里面的navieBayes函数实现
library(e1071)
# 第一步模型搭建
model_naive<-naiveBayes(diabetes~.,data =traindata_glm)
# 利用建立好的模型对结果进行预测
pred_naive<-predict(model_naive,testdata_glm[c(-9)])
# 生成预测结果混淆矩阵,进行输出
result<-table(testdata_glm$diabetes,pred_naive)
(a<-paste0(round(sum(diag(result)*100)/sum(result),1),'% 的预测准确率'))
运行结果如下:
总结
使用以上三种方法进行建模,然后对预测结果进行比较,其中随机森林算法的预测效果稍微优于其他两者,,所以我会选择随机森林算法来进行建模,尽管三者的准确率都低于80%(而且这是医院数据,用于诊断),考虑到缺失数据将近一半,这样的预测效果目前勉强接受,后期会考虑其他方法来提升预测效果。
广义线性回归预测准确率precision_glm=78.4%
随机森林算法预测准确率precision_RF= 79.1%
朴素贝叶斯算法预测准确率precision_Navie=78.4%
谢谢大家的浏览,如有疑问或者文章有错误的地方,欢迎指正。如果你有更棒的想法欢迎加微信(qq号:546432637)沟通。希望明天都可以进步一点点!!!