caret train() 预测与 Predict.glm() 非常不同

问题描述 投票:0回答:1

我正在尝试使用 10 倍交叉验证来估计逻辑回归。

#import libraries
library(car); library(caret); library(e1071); library(verification)

#data import and preparation
data(Chile)              
chile        <- na.omit(Chile)  #remove "na's"
chile        <- chile[chile$vote == "Y" | chile$vote == "N" , ] #only "Y" and "N" required
chile$vote   <- factor(chile$vote)      #required to remove unwanted levels 
chile$income <- factor(chile$income)  # treat income as a factor

目标是估计一个 glm - 模型,该模型根据相关解释变量预测投票“Y”或“N”的结果,并根据最终模型计算混淆矩阵和 ROC 曲线以掌握不同阈值下的模型行为水平。

模型选择导致:

res.chileIII <- glm(vote ~
                           sex       +
                           education +
                           statusquo ,
                           family = binomial(),
                           data = chile)
#prediction
chile.pred <- predict.glm(res.chileIII, type = "response")

生成:

> head(chile.pred)
          1           2           3           4           5           6 
0.974317861 0.008376988 0.992720134 0.095014139 0.040348115 0.090947144 

将观测值与估计值进行比较:

chile.v     <- ifelse(chile$vote == "Y", 1, 0)          #to compare the two arrays
chile.predt <- function(t) ifelse(chile.pred > t , 1,0) #t is the threshold for which the confusion matrix shall be computed

t = 0.3 的混淆矩阵:

confusionMatrix(chile.predt(0.3), chile.v)

> confusionMatrix(chile.predt(0.3), chile.v)
Confusion Matrix and Statistics

          Reference
Prediction   0   1
         0 773  44
         1  94 792

               Accuracy : 0.919          
                 95% CI : (0.905, 0.9315)
    No Information Rate : 0.5091         
    P-Value [Acc > NIR] : < 2.2e-16 

和 Roc 曲线:

roc.plot(chile.v, chile.pred)

这似乎是一个合理的模型。

现在我不想使用“正常”predict.glm() 函数,而是想测试 10 倍交叉验证估计的性能差异。

tc <- trainControl("cv", 10, savePredictions=T)  #"cv" = cross-validation, 10-fold
fit <- train(chile$vote ~ chile$sex            +
                          chile$education      +
                          chile$statusquo      ,
                          data      = chile    ,
                          method    = "glm"    ,
                          family    = binomial ,
                          trControl = tc)

> summary(fit)$coef
                      Estimate Std. Error   z value      Pr(>|z|)
(Intercept)          1.0152702  0.1889646  5.372805  7.752101e-08
`chile$sexM`        -0.5742442  0.2022308 -2.839549  4.517738e-03
`chile$educationPS` -1.1074079  0.2914253 -3.799971  1.447128e-04
`chile$educationS`  -0.6827546  0.2217459 -3.078996  2.076993e-03
`chile$statusquo`    3.1689305  0.1447911 21.886224 3.514468e-106

所有参数都很重要。

fitpred <- ifelse(fit$pred$pred == "Y", 1, 0) #to compare with chile.v

> confusionMatrix(fitpred,chile.v)
Confusion Matrix and Statistics

          Reference
Prediction   0   1
         0 445 429
         1 422 407

 Accuracy : 0.5003          
                 95% CI : (0.4763, 0.5243)
    No Information Rate : 0.5091          
    P-Value [Acc > NIR] : 0.7738

这显然与之前的混淆矩阵有很大不同。我的期望是,交叉验证的结果不应比第一个模型表现差很多。然而结果表明了一些其他的东西。

我的假设是train()参数的设置有错误,但我不知道它是什么。

我真的很感激一些帮助,提前谢谢你。

r glm r-caret confusion-matrix
1个回答
69
投票

您正在尝试使用混淆矩阵来了解样本内拟合。您使用

glm()
函数的第一种方法很好。

使用

train()
的第二种方法的问题在于返回的对象。您正在尝试通过
fit$pred$pred
从中提取样本内拟合值。但是,
fit$pred
不包含与
chile.v
chile$vote
对齐的拟合值。它包含不同(10)次折叠的观察值和拟合值:

head(fit$pred)
#   pred obs rowIndex parameter Resample
# 1    N   N        2      none   Fold01
# 2    Y   Y       20      none   Fold01
# 3    Y   Y       28      none   Fold01
# 4    N   N       38      none   Fold01
# 5    N   N       55      none   Fold01
# 6    N   N       66      none   Fold01

tail(fit$pred)
#      pred obs rowIndex parameter Resample
# 1698    Y   Y     1592      none   Fold10
# 1699    Y   N     1594      none   Fold10
# 1700    N   N     1621      none   Fold10
# 1701    N   N     1656      none   Fold10
# 1702    N   N     1671      none   Fold10
# 1703    Y   Y     1689      none   Fold10

由于折叠的随机性,并且由于您预测 0 或 1,因此您获得的准确度约为 50%。

您要查找的样本内拟合值位于

fit$finalModel$fitted.values
中。使用那些:

fitpred <- fit$finalModel$fitted.values
fitpredt <- function(t) ifelse(fitpred > t , 1,0)
confusionMatrix(fitpredt(0.3),chile.v)
# Confusion Matrix and Statistics
# 
# Reference
# Prediction   0   1
#          0 773  44
#          1  94 792
# 
#               Accuracy : 0.919          
#                 95% CI : (0.905, 0.9315)
#    No Information Rate : 0.5091         
#    P-Value [Acc > NIR] : < 2.2e-16      
# 
#                  Kappa : 0.8381         
# Mcnemar's Test P-Value : 3.031e-05      
#                                              
#            Sensitivity : 0.8916         
#            Specificity : 0.9474         
#         Pos Pred Value : 0.9461         
#         Neg Pred Value : 0.8939         
#             Prevalence : 0.5091         
#         Detection Rate : 0.4539         
#   Detection Prevalence : 0.4797         
#      Balanced Accuracy : 0.9195         
#            
#       'Positive' Class : 0

现在准确率接近预期值。将阈值设置为 0.5 会产生与 10 倍交叉验证的估计值大致相同的准确度:

confusionMatrix(fitpredt(0.5),chile.v)
# Confusion Matrix and Statistics
# 
# Reference
# Prediction   0   1
#          0 809  64
#          1  58 772
# 
#                Accuracy : 0.9284          
#                  95% CI : (0.9151, 0.9402)
# [rest of the output omitted]            

fit
# Generalized Linear Model 
# 
# 1703 samples
#    7 predictors
#    2 classes: 'N', 'Y' 
# 
# No pre-processing
# Resampling: Cross-Validated (10 fold) 
# 
# Summary of sample sizes: 1533, 1532, 1532, 1533, 1532, 1533, ... 
# 
# Resampling results
# 
#   Accuracy  Kappa  Accuracy SD  Kappa SD
#   0.927     0.854  0.0134       0.0267

此外,关于您的期望“交叉验证的结果不应比第一个模型表现差很多”,请检查

summary(res.chileIII)
summary(fit)
。拟合的模型和系数完全相同,因此它们会给出相同的结果。

© www.soinside.com 2019 - 2024. All rights reserved.