R语言中setdiff()无数据显示:决策树训练集异常问题
问题描述
我尝试用决策树预测药物类别,设置随机种子后用sample_frac()划分训练集,再用setdiff()生成测试集。遇到异常情况:明明能确认训练集数据存在,但查看data_test时显示无数据,不过决策树依然可以正常生成。
相关代码
data <- data %>% select(BP, Cholesterol, Drug) view(data) str(data) data <- lapply(data, as.factor) data <- lapply(data, as.numeric) view(data) data <- as.data.frame(data) view(data) set.seed(111) data_training <- data %>% sample_frac(0.80) data_test <- data %>% setdiff(data_training) view(data_training) view(data_test) data_tree <- rpart(Drug ~ BP + Cholesterol, data=data_training, method = 'class') plot(data_tree, uniform=TRUE, margin=0.5) text(data_tree, use.n = TRUE) data_test['Predicted'] <- predict(data_tree, data_test, type = 'class') view(data_test)
问题原因
setdiff()的逻辑不适合拆分数据集:setdiff()是按行内容进行差集计算,而非按行索引拆分。如果原数据存在重复行,它会把所有与训练集内容重复的行从测试集中移除,直接导致测试集为空;即使没有重复行,这种方式也不是标准的数据集拆分逻辑。- 数据类型转换的冗余操作:两次
lapply将数据框转为列表后再转回数据框,虽然最终结果是数据框,但中间步骤可能导致数据结构临时异常,不过核心问题还是setdiff()的使用错误。
解决方法
方法1:按索引拆分数据集(推荐)
通过生成随机索引拆分,能保证数据拆分的准确性,不受重复行影响:
set.seed(111) # 生成训练集索引 train_idx <- sample(nrow(data), size = 0.8 * nrow(data)) data_training <- data[train_idx, ] # 用负索引取测试集 data_test <- data[-train_idx, ]
方法2:用anti_join()替代setdiff()(dplyr风格)
anti_join()会保留原数据中所有不在训练集里的行,匹配逻辑更适合数据集拆分:
set.seed(111) data_training <- data %>% sample_frac(0.8) data_test <- data %>% anti_join(data_training)
方法3:简化数据类型转换
原代码的类型转换可以简化为数据框内的批量操作,避免转为列表的步骤:
data <- data %>% select(BP, Cholesterol, Drug) %>% # 批量将所有列转为因子后再转数值 mutate(across(everything(), ~ as.numeric(as.factor(.x))))
内容的提问来源于stack exchange,提问作者Dan C
相关产品推荐
相关产品推荐

