R语言MLR包:如何阻止makeClassifTask删除测试集空因子水平
解决mlr中测试集空因子水平导致的任务创建问题
我之前也碰到过完全一样的场景,咱们先把问题的核心理清楚:mlr的makeClassifTask默认会自动清理空因子水平(也就是fixup.data="yes"的默认行为),但咱们需要保留这些水平来和训练集的特征对齐——毕竟模型是基于训练集所有因子水平训练的,测试集必须严格匹配特征结构才行。
问题拆解
你已经通过testdata$Var1 <- factor(testdata$Var1, levels = levels(traindata$Var1))给测试集Var1加上了空水平-1,但遇到了两难:
- 用默认参数创建任务时,mlr会自动删掉这个空水平,抛出警告
- 设置
fixup.data="no"时,mlr又因为检测到空水平直接报错,不让任务创建
可行的解决方案
这里有两个靠谱的办法,你可以根据自己的习惯选:
方法1:临时添加空水平记录,创建任务后再移除
这个办法有点取巧但实用性拉满,核心是先让测试集每个因子水平都至少有一条数据,过了mlr的校验后再把临时数据删掉:
# 先复制一份测试集避免修改原数据 temp_test <- testdata # 添加一条包含Var1=-1的临时记录(response填虚拟值即可) temp_test <- rbind(temp_test, data.frame(ID = 999, Var1 = "-1", Var2 = 0, response = 0)) # 创建任务,此时不会有警告或错误 testtask <- makeClassifTask(data = temp_test, target = "response", positive = "1") # 移除刚才添加的临时记录 testtask <- subsetTask(testtask, subset = temp_test$ID != 999)
这样创建出来的任务会完整保留Var1的所有水平,同时测试集还是你原本的真实数据。
方法2:直接修改任务的特征属性,强制保留所有水平
如果不想折腾临时数据,也可以先默认创建任务(接受空水平被删除),再手动把Var1的水平改回训练集的版本:
# 先默认创建任务(此时Var1的-1水平会被自动删除) testtask <- makeClassifTask(data = testdata, target = "response", positive = "1") # 获取任务的特征列表 feat_names <- getTaskFeatureNames(testtask) # 定位Var1的位置 var1_pos <- which(feat_names == "Var1") # 手动把任务描述里的Var1水平改回训练集的水平 testtask$task.desc$features[[var1_pos]]$levels <- levels(traindata$Var1) # 同步更新任务数据里的Var1因子水平 testtask$env$data$Var1 <- factor(testtask$env$data$Var1, levels = levels(traindata$Var1))
这个方法直接修改任务的内部结构,需要注意mlr版本的兼容性,但绝大多数场景下都能正常工作。
补充说明
因为你测试集的response是虚拟值,这两个方法都不会影响后续的预测——毕竟预测时只需要特征和训练集对齐就行,response的虚拟值只是为了满足任务创建的格式要求。
内容的提问来源于stack exchange,提问作者mank




