KNN用于不平衡的数据集,并添加SMOTE以提高性能,但效果最差

问题描述

我有一个不平衡的数据集,称为酵母4。记录分为目标“正”和“负”两类。 积极阶层只占总比例的3%。 我已经使用kNN算法进行分类,并且我没有指定k,但是我在训练数据上使用了5倍交叉验证。我发现:auc_knn_none = 0.7062473。 我有兴趣添加一种过采样算法以提高模型的质量。 因此,我使用了SMOTE算法,而且我还没有指定k ok kNN,并且对训练数据使用了5倍交叉验证。 但是这次,我发现:auc_knn_smote = 0.56676。 通常,auc_knn_smote必须高于auc_knn_none 所以有问题,我不知道问题出在哪里。 这是我的代码

library(imbalance)
data(yeast4)
Data <- yeast4
Data$Mcg <- as.numeric(as.character(Data$Mcg))
Data$Gvh <- as.numeric(as.character(Data$Gvh))
Data$Alm <- as.numeric(as.character(Data$Alm))
Data$Mit <- as.numeric(as.character(Data$Mit))  
Data$Erl <- as.numeric(as.character(Data$Erl))
Data$Pox <- as.numeric(as.character(Data$Pox))
Data$Vac <- as.numeric(as.character(Data$Vac))
Data$Nuc <- as.numeric(as.character(Data$Nuc))
U <- data.frame(Data[,-9])
U <- scale(U,center = TRUE,scale=TRUE)
U <- data.frame(U)
q <- as.factor(unlist(Data$Class))
Q <- vector()
for(i in 1: nrow(Data))
{
  if(substr(q[i],1,1)=="n")
  {
    Q <- c(Q,0)
  }
  else{
    Q <- c(Q,1)
  }
}
Q <- as.factor(Q)

在这里,我已将数据缩放和居中,将负数的任何值都设置为0,其他所有值都设置为1。 这是我使用的功能

library(ROCR) 
library(pROC)
library(caret)
library(ROSE)
library(DMwR)
library(nnet)
AUC_KNN_SMOTE <- function(U,Q,k,M){
  folds <- createFolds(Q,k)
  AUC <- vector()
  W <- vector()
  for( i in 1:k){
    s <- data.frame(folds[i])[,1]
    TRAIN <- data.frame(U[-s,])
    TEST <- data.frame(U[s,])
    TRAIN$Class <- Q[-s]
    TRAIN.smote <- SMOTE(Class~.,data = TRAIN,perc.over = 100,perc.under = 200)
    trControl <- trainControl(method  = "cv",number  = 5,classprobs = TRUE,summaryFunction = twoClassSummary)
    fit <- train(make.names(Class) ~ .,method     = "knn",tuneGrid   = expand.grid(k = 1:M),trControl  = trControl,metric     = "ROC",data       = TRAIN.smote)
    W <- c(W,fit[["results"]][,2])
    W <- matrix(W,nrow=M,ncol = i)
    J <- which.is.max(W[,i])
    mod <- class::knn(cl = TRAIN.smote$Class,test = TEST,train = TRAIN.smote[,-9],k = J,prob = TRUE)
    X <-  roc(Q[s],attributes(mod)$prob,quiet = TRUE)
    AUC <- c(AUC,as.numeric(X$auc))
  }
  return(mean(AUC))
}

和我上面提到的并通过此函数发现的结果是:

b <- 0
for(i in 1:1000)
{
  m <- AUC_KNN_SMOTE(U,k=5,M=100)+b
  b <- m 
}
auc_knn_smote <- m/1000
auc_knn_smote=0.56676

谢谢您的帮助!

解决方法

我认为您的方法没有错。其结果解释需要澄清。

正如您所述,在初始不平衡数据集上,您的AUC得分为0.7062473。然后,您应用了SMOTE数据平衡算法,得到的AUC得分为0.56676。在这两种情况下,均采用了5倍交叉验证。

说明

  • 初始AUC分数较高,因为它偏爱具有较高比例的班级。
  • 为了平衡数据集,应用了过采样技术。让我们简要了解过采样的工作原理。它介绍了人工数据点。这引入了 bias (偏差),因为新数据点是从旧数据点生成的,因此它们不会给数据集带来太大的差异。在大多数情况下,它们仅与原始情况略有不同。
  • 从您的Q中不清楚火车测试拆分方面。假设,在火车测试拆分之前对数据进行了过采样,那么就会引入偏差。在这里需要注意的重要一点是,应该在平衡训练集之前 进行拆分。您希望测试集尽可能地无偏,以便对模型的性能进行客观评估。如果在拆分数据集之前进行了平衡,则模型可能会在训练过程中通过生成的数据点看到测试集上的信息。

可能的解决方案

  • 专注于消除过采样带来的偏差。一种方法是对数据重新采样。
  • 请记住,您的重点必须放在实现低偏差低方差模型上。这将有助于改善绩效评估指标。