线性回归模型预测报错:mpg数据集无因子却出现因子新水平错误
错误原因分析
你遇到的这个报错其实很常见,核心问题出在分类变量的水平在训练集和测试集的分布不一致:
- 虽然你用
str(mpg)查看时,变量显示为字符型(chr),但当你调用lm()拟合线性回归模型时,R会自动把字符型自变量转换为因子变量来处理分类信息。 - 你随机拆分训练集和测试集时,刚好测试集里出现了训练集从未见过的
model水平(也就是报错里的land cruiser wagon 4wd)。模型在训练阶段根本不知道这个水平的存在,自然无法对它进行预测,于是抛出了错误。
你可以用这段代码验证这个差异:
# 查看训练集和测试集的model水平差异 train_models <- unique(mpg[train_ind, ]$model) test_models <- unique(mpg[-train_ind, ]$model) setdiff(test_models, train_models) # 这会返回训练集没有的测试集model水平
解决方案
针对这个问题,有几种实用的解决思路:
1. 分层抽样确保分类变量水平全覆盖
拆分数据集时,按分类变量(比如model)进行分层抽样,保证每个分类水平都能在训练集和测试集里出现。用dplyr就能轻松实现:
library(dplyr) set.seed(1) # 按model分层,每个model抽取50%的样本作为训练集 train_ind <- mpg %>% group_by(model) %>% sample_frac(0.5) %>% ungroup() %>% pull(row_number()) lm_mod <- lm(displ ~ ., data = mpg[train_ind, ]) lm_pred <- predict(lm_mod, mpg[-train_ind, ])
2. 对齐训练集和测试集的因子水平
如果必须用随机抽样,可以在拟合模型前,手动将测试集的因子水平与训练集对齐,把训练集没有的水平转为NA:
set.seed(1) train.ind <- sample(1:nrow(mpg), round(nrow(mpg)/2)) # 处理训练集:将字符型变量转为因子 train_data <- mpg[train.ind, ] train_data <- train_data %>% mutate(across(where(is.character), as.factor)) # 处理测试集:对齐因子水平,训练集没有的水平设为NA test_data <- mpg[-train.ind, ] test_data <- test_data %>% mutate(across(where(is.character), ~factor(., levels = levels(train_data[[cur_column()]])))) # 拟合模型并预测 lm_mod <- lm(displ ~ ., data = train_data) lm_pred <- predict(lm_mod, test_data)
这样测试集里的新水平会被转为NA,预测时不会报错(默认会忽略这些行,或者你可以设置na.action = na.pass保留NA结果)。
3. 简化高基数分类变量
model这类分类变量的水平非常多(mpg里有38种model),很容易出现拆分后水平缺失的问题。你可以考虑:
- 去掉这类高基数变量,改用更粗粒度的分类(比如
manufacturer) - 使用正则化模型(如
glmnet)来处理高基数分类变量,避免传统线性回归的因子水平限制
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

