如何处理 R 中 predict 函数的错误?

5

我有一个名为df的数据框,我正在构建一个机器学习模型(C5.0决策树)来预测一列(loan_approved)的类别:

结构(非真实数据):

id occupation income  loan_approved
1  business   4214214 yes
2  business   32134   yes
3  business   43255   no
4  sailor     5642    yes
5  teacher    53335   no
6  teacher    6342    no

过程:

  • 我将数据框随机拆分为测试集和训练集,从训练集中学习(使用行1、2、3、5、6作为训练集,使用第4行作为测试集)
  • 为了考虑一个或多个列中的新分类级别,我使用了try函数

功能:

    error_free_predict = function(x){
    output = tryCatch({
    predict(C50_model, newdata = test[x,], type = "class")
    }, error = function(e) {
    "no"
    })
    return(output)
    }

应用预测功能:

test <- mutate(test, predicted_class = error_free_predict(1:NROW(test)))

问题:

id occupation income loan_approved predicted_class
1  business   4214214 yes          no
2  business   32134   yes          no
3  business   43255   no           no
4  sailor     5642    yes          no
5  teacher    53335   no           no
6  teacher    6342    no           no

问题:

我知道这是因为测试数据框中有一个新的级别,而训练数据中没有,但我的函数不应该在除此之外的所有情况下都起作用吗?

P.S.:没有使用sapply,因为它太慢了。


你实际的问题是什么?是因为它只返回“no”吗?predict调用返回的错误是什么? - cdeterman
1
问题在于预测函数在'occupation'列中遇到了新的因子水平,导致不仅该行失败,而且整个数据框都被视为失败案例。 - Anubhav Dikshit
听起来你应该分层划分,这样每个划分中每个类别的数量大致相同。 - Aaron left Stack Overflow
@Aaron:我计划在生产中使用这个,有可能会看到至少一条记录具有新的职业/级别。 - Anubhav Dikshit
2个回答

1
这个问题有两个部分。
第一个问题出现在模型训练时,因为分类变量在随机划分时不会被等分到训练集和测试集中。例如,在您的情况下,如果只有一条记录的职业是“水手”,那么在进行随机划分时,它有可能被划分到测试集中。使用训练数据集构建的模型将永远不会看到“水手”职业的影响,因此会出现错误。更一般地说,随机划分后,可能会出现其他分类变量级别完全划分到测试集中的情况。
因此,您可以使用分层抽样而不是随机分割数据。使用data.table进行70:30划分的代码如下:
ind <- total_data[, sample(.I, round(0.3*.N), FALSE),by="occupation"]$V1
train <- total_data[-ind,]
test <- total_data[ind,]

这样可以确保任何级别在训练和测试数据集之间平均分配。因此,在随机拆分的情况下,测试数据集中不会出现“新”的分类级别。请注意保留html标签。
  1. Second part of the problem comes when model is in production and it encounters a altogether new variable which was not there in even training or test set. To tackle this problem one can maintain a list of all levels of all categorical variables by using lvl_cat_var1 <- unique(cat_var1) and lvl_cat_var2 <- unique(cat_var2) etc. Then before predict one can check for new level and filter:

    new_lvl_data <- total_data[!(var1 %in% lvl_cat_var1 & var2 %in% lvl_cat_var2)] 
    pred_data <- total_data[(var1 %in% lvl_cat_var1 & var2 %in% lvl_cat_var2)] 
    

对于默认预测,执行以下操作:

new_lvl_data$predicted_class <- "no" 

并对pred_data进行完整的预测。


你可以通过使用lvl_cat_var1 <- unique(cat_var1)lvl_cat_var2 <- unique(cat_var2)来维护所有分类变量的所有级别。然后,在进行预测之前,您可以检查新级别并筛选出new_lvl_data <- total_data[!(var1 %in% lvl_cat_var1 & var2 %in% lvl_cat_var2)]pred_data <- total_data[(var1 %in% lvl_cat_var1 & var2 %in% lvl_cat_var2)],然后执行new_lvl_data$predicted_class <- "no",以及对pred_data进行完整的预测。 - abhiieor
请将此作为您的答案,我将非常乐意接受! - Anubhav Dikshit
@agenis:OP希望新等级的记录被归类为默认类别。我只是选择“否”作为示例。没有更多的含义。 - abhiieor
@abhiieor: ind <- total_data[, sample(.I, round(0.3*.N), FALSE),by="occupation"]$V1 你能否解释一下这个命令?我遇到了一个错误。还有关于.I和.N等的更多信息。 - Toros91
这是data.table的抽样语法。.I表示当前行号,.N表示总行数。 - abhiieor

0

通常我会使用循环来处理这个问题,其中任何在训练集之外的级别都将被此函数重新编码为NA。在这里,train是您用于训练模型的数据,而test是将用于预测的数据。

for(i in 1:ncol(train)){
  if(is.factor(train[,i])){
    test[,i] <- factor(test[,i],levels=levels(train[,i]))
  }
}

Trycatch是一种错误处理机制,即在遇到错误后。除非您想在遇到错误后执行不同的操作,否则它将不适用。但是如果您仍希望运行该模型,则此循环将处理新层次。


谢谢您的回答,但是您不认为循环(包括for循环或其他循环)会非常慢吗?这是一个问题,因为我考虑将其制作成生产级别! - Anubhav Dikshit
这里的for循环仅用于删除因子水平。就性能而言,这并不重要。 - Chirayu Chamoli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接