在 R 中,如何对不平衡的 2 类数据进行特征选择的平衡 10 倍 CV 信息增益测试?

问题描述

我有一个大型训练数据集 data.trn,包含 50 多个变量的 260,000 多个观察值,因变量 loan_status 由 2 个类别 "paid off""default" 组成,各自不平衡约 5:1。我想使用 information.gain 包中的 FSelector 命令将功能减少到最有意义的程度。但是,我担心这种保留下来的过滤方法会偏向于多数类,从而导致对特征的评估产生误导。为了避免这种情况,我认为一种形式的基于 sapply 的过程可以通过提取 10 个不同平衡交叉验证折叠的几个信息增益测试的平均值来缓解这个问题。我想象折叠可以通过每次获取所有少数类观察并与来自多数类的不同等量观察配对来构建。然而,问题是,我是 R 的初学者,所以我不太擅长自己创建这样的结构,所以我想这里有人可以告诉我如何做到这一点,因为我仍然无法理解任务。目前我只做了基本的信息增益测试,不知道如何制作所需的平衡 CV 版本:

info_gain <- FSelector::information.gain(loan_status ~ .,data.trn)

解决方法

我会推荐以下两种策略之一:

  1. 对多数类的一个子集进行采样,直到更符合较小类的数字。重复多次,每次记录重要特征。然后看看是否有一些特征在所有集合中始终是最重要的特征。

  2. 对较小的类重新采样以获得综合膨胀的样本数。基本上估计它们的协方差,从中抽样随机样本,在此数据上拟合模型(并在估计性能之前删除样本)。因此,从某种意义上说,您只是借用合成数据来稳定模型拟合过程。

第一个可能不太复杂。

这是方法 1 的简单演示:


## Using the `mpg` dataset,pretending the 'dri' column is of particular interest to us.
##
## 'drv' is a column with three levels,that are not very balanced:
##
## table( mpg$drv )
##   4   f   r
## 103 106  25

## Let's sub-sample 25 of each class,it makes sense from the table above
n.per.class  <- 25

## let's do the sampling 10 times
n.times <- 10

library(foreach) ## for parallell work
library(doMC)
registerDoMC()

unique.classes <- unique( mpg$drv ) ## or just use levels( mpg$drv ) if you have a factor

variable.importances <- foreach( i=1:n.times ) %dopar% {

    j <- sapply(
        unique.classes,function(cl.name) {
            sample( which( mpg$drv == cl.name ),size=n.per.class )
        },simplify=FALSE
    )

    ## 'j' is now a named list,we easily turn it to a vector with unlist:
    sub.data <- mpg[ unlist(j),]

    ## table( sub.data$drv )
    ##  4  f  r
    ## 25 25 25
    ##
    ## 25 of each!


    fit <- train.your.model()
    varimp <- variable.importance( fit )

    ## I don't know what varimp will look like in your case,is it a numeric vector perhaps?

}

## variable.importances now is a list with the result of each
## iteration. If it is a vector wiht number for example,the following
## could be useful to have those collected into a matrix:

matrix.of.variable.importances <- Reduce( rbind,variable.importances )
colnames( matrix.of.variable.importances ) <- colnames( your.data )

如果您对方法 2 感兴趣,我建议您查看 caret 包,它可以轻松完成此操作,但我不知道他们是否支持您的特定方法。