与训练相比,R RF 不平衡 类 对未见数据的负预测值较低
R RF unbalanced classes low negative predicted value on unseen data compared to train
我建立了一个随机森林模型来预测客户是否在进行与欺诈有关的操作。这是一个非常不平衡的大样本,有 3% 的欺诈案例,我想预测少数 class(欺诈)。
我平衡数据(每个 50%)并构建 RF。到目前为止,我有一个很好的模型,其整体准确度约为 80%,并且正确预测了 +70% 的欺诈行为。但是当我在看不见的数据(测试)上尝试模型时,虽然整体准确性很好,但与训练数据相比,负预测值(欺诈)确实很低(仅 13% vs +70%)。
我试过增加样本量、增加平衡类别、调整 RF 参数...,但其中 none 效果很好,结果相似。我是不是过度拟合了?我可以做些什么来改进欺诈检测(负预测值)
在看不见的数据上?
这是代码和结果:
set.seed(1234)
#train and test sets
model <- sample(nrow(dataset), 0.7 * nrow(dataset))
train <- dataset[model, ]
test <- dataset[-model, ]
#Balance the data
balanced <- ovun.sample(custom21_type ~ ., data = train, method = "over",p = 0.5, seed = 1)$data
table(balanced$custom21_type)
0 1
5813 5861
#build the RF
rf5 = randomForest(custom21_type~.,ntree = 100,data = balanced,importance = TRUE,mtry=3,keep.inbag=TRUE)
rf5
Call:
randomForest(formula = custom21_type ~ ., data = balanced, ntree = 100, importance = TRUE, mtry = 3, keep.inbag = TRUE)
Type of random forest: classification
Number of trees: 100
No. of variables tried at each split: 3
OOB estimate of error rate: 21.47%
Confusion matrix:
0 1 class.error
0 4713 1100 0.1892310
1 1406 4455 0.2398908
#test on unseen data
predicted <- predict(rf5, newdata=test)
confusionMatrix(predicted,test$custom21_type)
Confusion Matrix and Statistics
Reference
Prediction 0 1
0 59722 559
1 13188 1938
Accuracy : 0.8177
95% CI : (0.8149, 0.8204)
No Information Rate : 0.9669
P-Value [Acc > NIR] : 1
Kappa : 0.1729
Mcnemar's Test P-Value : <2e-16
Sensitivity : 0.8191
Specificity : 0.7761
Pos Pred Value : 0.9907
Neg Pred Value : 0.1281
Prevalence : 0.9669
Detection Rate : 0.7920
Detection Prevalence : 0.7994
Balanced Accuracy : 0.7976
'Positive' Class : 0
首先我注意到您没有使用任何交叉验证。包括这将有助于增加用于训练的数据的变化,并有助于减少过度拟合。此外,我们将使用 C.50
代替 randomForest
,因为它更健壮并且对类型 1 错误给予更多惩罚。
您可能会考虑的一件事是实际上没有在训练数据中进行 50-50 的平衡拆分,而是使其更接近 80-20。这样欠平衡的 class 就不会被过度采样。我确信这会导致过度拟合,并且您的模型无法 class 将新示例确定为负数。
运行 这是在您创建重新平衡后的数据 (p=.2
)
library(caret)
#set up you cross validation
Control <- trainControl(
summaryFunction = twoClassSummary, #displays model score not confusion matrix
classProbs = TRUE, #important for the summaryFunction
verboseIter = TRUE, #tones down output
savePredictions = TRUE,
method = "repeatedcv", #repeated cross validation, 10 folds, 3 times
repeats = 3,
number = 10,
allowParallel = TRUE
)
现在我在评论中看到你所有的变量都是分类变量。这对于 NaiveBayes 算法是最优的。但是,如果您有任何数值数据,则需要按照标准程序进行预处理(缩放、归一化和 NA 输入)。我们还将实施网格搜索过程。
如果你的数据都是分类的
model_nb <- train(
x = balanced[,-(which(colnames(balanced))%in% "custom21_type")],
y= balanced$custom21_type,
metric = "ROC",
method = "nb",
trControl = Control,
tuneGrid = data.frame(fL=c(0,0.5,1.0), usekernel = TRUE,
adjust=c(0,0.5,1.0)))
如果您想要 RF 方法(如果数据是数字,请确保进行预处理)
model_C5 <- train(
x = balanced[,-(which(colnames(balanced))%in% "custom21_type")],
y= balanced$custom21_type,
metric = "ROC",
method = "C5.0",
trControl = Control,
tuneGrid = tuneGrid=expand.grid(.model = "tree",.trials = c(1,5,10), .winnow = F)))
现在我们预测
C5_predict<-predict(model_C5, test, type = "raw")
NB_predict<-predict(model_nb, test, type = "raw")
confusionMatrix(C5_predict,test$custom21_type)
confusionMatrix(nb_predict,test$custom21_type)
编辑:
尝试调整下面的成本矩阵。这个所做的是对第二类错误的惩罚是第一类错误的两倍。
cost_mat <- matrix(c(0, 2, 1, 0), nrow = 2)
rownames(cost_mat) <- colnames(cost_mat) <- c("bad", "good")
cost_mod <- C5.0( x = balanced[,-(which(colnames(balanced))%in%
"custom21_type")],
y= balanced$custom21_type,
costs = cost_mat)
summary(cost_mod)
编辑 2:
predicted <- predict(rf5, newdata=test, type="prob")
将为您提供每个预测的实际概率。默认截止值为 0.5。 IE。高于 .5 的所有内容将 class 化为 0,低于 .5 的所有内容将被化为 1。因此您可以调整此截止值以帮助处理不平衡的 classes.
ifelse(predicted[,1] < .4, 1, predicted[,1])
我建立了一个随机森林模型来预测客户是否在进行与欺诈有关的操作。这是一个非常不平衡的大样本,有 3% 的欺诈案例,我想预测少数 class(欺诈)。
我平衡数据(每个 50%)并构建 RF。到目前为止,我有一个很好的模型,其整体准确度约为 80%,并且正确预测了 +70% 的欺诈行为。但是当我在看不见的数据(测试)上尝试模型时,虽然整体准确性很好,但与训练数据相比,负预测值(欺诈)确实很低(仅 13% vs +70%)。
我试过增加样本量、增加平衡类别、调整 RF 参数...,但其中 none 效果很好,结果相似。我是不是过度拟合了?我可以做些什么来改进欺诈检测(负预测值) 在看不见的数据上?
这是代码和结果:
set.seed(1234)
#train and test sets
model <- sample(nrow(dataset), 0.7 * nrow(dataset))
train <- dataset[model, ]
test <- dataset[-model, ]
#Balance the data
balanced <- ovun.sample(custom21_type ~ ., data = train, method = "over",p = 0.5, seed = 1)$data
table(balanced$custom21_type)
0 1
5813 5861
#build the RF
rf5 = randomForest(custom21_type~.,ntree = 100,data = balanced,importance = TRUE,mtry=3,keep.inbag=TRUE)
rf5
Call:
randomForest(formula = custom21_type ~ ., data = balanced, ntree = 100, importance = TRUE, mtry = 3, keep.inbag = TRUE)
Type of random forest: classification
Number of trees: 100
No. of variables tried at each split: 3
OOB estimate of error rate: 21.47%
Confusion matrix:
0 1 class.error
0 4713 1100 0.1892310
1 1406 4455 0.2398908
#test on unseen data
predicted <- predict(rf5, newdata=test)
confusionMatrix(predicted,test$custom21_type)
Confusion Matrix and Statistics
Reference
Prediction 0 1
0 59722 559
1 13188 1938
Accuracy : 0.8177
95% CI : (0.8149, 0.8204)
No Information Rate : 0.9669
P-Value [Acc > NIR] : 1
Kappa : 0.1729
Mcnemar's Test P-Value : <2e-16
Sensitivity : 0.8191
Specificity : 0.7761
Pos Pred Value : 0.9907
Neg Pred Value : 0.1281
Prevalence : 0.9669
Detection Rate : 0.7920
Detection Prevalence : 0.7994
Balanced Accuracy : 0.7976
'Positive' Class : 0
首先我注意到您没有使用任何交叉验证。包括这将有助于增加用于训练的数据的变化,并有助于减少过度拟合。此外,我们将使用 C.50
代替 randomForest
,因为它更健壮并且对类型 1 错误给予更多惩罚。
您可能会考虑的一件事是实际上没有在训练数据中进行 50-50 的平衡拆分,而是使其更接近 80-20。这样欠平衡的 class 就不会被过度采样。我确信这会导致过度拟合,并且您的模型无法 class 将新示例确定为负数。
运行 这是在您创建重新平衡后的数据 (p=.2
)
library(caret)
#set up you cross validation
Control <- trainControl(
summaryFunction = twoClassSummary, #displays model score not confusion matrix
classProbs = TRUE, #important for the summaryFunction
verboseIter = TRUE, #tones down output
savePredictions = TRUE,
method = "repeatedcv", #repeated cross validation, 10 folds, 3 times
repeats = 3,
number = 10,
allowParallel = TRUE
)
现在我在评论中看到你所有的变量都是分类变量。这对于 NaiveBayes 算法是最优的。但是,如果您有任何数值数据,则需要按照标准程序进行预处理(缩放、归一化和 NA 输入)。我们还将实施网格搜索过程。
如果你的数据都是分类的
model_nb <- train(
x = balanced[,-(which(colnames(balanced))%in% "custom21_type")],
y= balanced$custom21_type,
metric = "ROC",
method = "nb",
trControl = Control,
tuneGrid = data.frame(fL=c(0,0.5,1.0), usekernel = TRUE,
adjust=c(0,0.5,1.0)))
如果您想要 RF 方法(如果数据是数字,请确保进行预处理)
model_C5 <- train(
x = balanced[,-(which(colnames(balanced))%in% "custom21_type")],
y= balanced$custom21_type,
metric = "ROC",
method = "C5.0",
trControl = Control,
tuneGrid = tuneGrid=expand.grid(.model = "tree",.trials = c(1,5,10), .winnow = F)))
现在我们预测
C5_predict<-predict(model_C5, test, type = "raw")
NB_predict<-predict(model_nb, test, type = "raw")
confusionMatrix(C5_predict,test$custom21_type)
confusionMatrix(nb_predict,test$custom21_type)
编辑:
尝试调整下面的成本矩阵。这个所做的是对第二类错误的惩罚是第一类错误的两倍。
cost_mat <- matrix(c(0, 2, 1, 0), nrow = 2)
rownames(cost_mat) <- colnames(cost_mat) <- c("bad", "good")
cost_mod <- C5.0( x = balanced[,-(which(colnames(balanced))%in%
"custom21_type")],
y= balanced$custom21_type,
costs = cost_mat)
summary(cost_mod)
编辑 2:
predicted <- predict(rf5, newdata=test, type="prob")
将为您提供每个预测的实际概率。默认截止值为 0.5。 IE。高于 .5 的所有内容将 class 化为 0,低于 .5 的所有内容将被化为 1。因此您可以调整此截止值以帮助处理不平衡的 classes.
ifelse(predicted[,1] < .4, 1, predicted[,1])