使用tidymodels调优Ames房价模型时遇下标越界错误求助
解决tidymodels处理Ames房价数据集时的「subscript out of bounds error」
问题背景
使用tidymodels处理Kaggle Ames房价数据集时,运行模型调优代码出现下标越界错误,具体信息:
x Fold1: preprocessor 1/1, model 1/12: Error in y.mat[, 2]: subscript out of bounds
Warning: All models failed. Runshow_notes(.Last.tune.result)for more information.
执行show_notes后仍仅返回相同错误提示。
我的代码流程
1. 数据拆分与预处理Recipe
data.split = initial_split(house.prices, prop=0.8) train.data = training(data.split) test.data = testing(data.split) # Create recipe - OLS sales.rec = recipe(SalePrice ~., data = train.data) %>% step_log(SalePrice, LotArea, GrLivArea, TotRmsAbvGrd) %>% update_role(Id, SalePrice, new_role = "ID") %>% step_num2factor(MSSubClass, levels = as.character(unique(house.prices$SalePrice))) %>% step_unknown(PoolQC, Fence, MiscFeature, BsmtQual, BsmtCond, BsmtExposure, BsmtFinType1, FireplaceQu, GarageType, GarageQual, GarageCond, new_level = "None") %>% step_mutate(PorchArea = OpenPorchSF+EnclosedPorch+`3SsnPorch`+ScreenPorch) %>% step_mutate(garage.age = YrSold - GarageYrBlt, house.age = YrSold - YearBuilt, renovation.age = YrSold - YearRemodAdd ) %>% step_mutate(has.garage = (GarageType != NA), has.basement = (BsmtExposure != NA), has.pool = (PoolQC != NA), is.new = house.age==0 ) %>% step_cut(OverallQual, breaks = c(2.5, 6.5, 8.5)) %>% step_cut(OverallCond, breaks = c(2.5, 6.5, 8.5)) %>% step_mutate(house.age = log(1+house.age)) %>% step_rm(-c(SalePrice, house.age, renovation.age, has.garage, has.basement, has.pool, is.new, MSZoning, LotArea, Alley, LotShape, Utilities, Neighborhood, OverallQual, OverallCond, ExterCond, Foundation, BsmtFinSF1, Heating, HeatingQC, CentralAir, GrLivArea, FullBath, KitchenQual, TotRmsAbvGrd, PavedDrive, PorchArea, MiscVal,SaleCondition)) %>% step_other(all_nominal_predictors(), all_factor(), all_string()) %>% step_string2factor(all_string_predictors()) %>% step_nzv(all_predictors()) %>% step_impute_median(all_numeric_predictors()) %>% step_unknown(all_factor_predictors()) %>% step_normalize(all_numeric_predictors())
2. 随机森林模型搭建
my.rf = rand_forest(mtry = tune(), trees = 2000, min_n=tune()) %>% set_engine("ranger") %>% set_mode("regression")
3. 工作流与模型调优
tree.grid = expand.grid(min_n=c(2,14,27,40), mtry = c(4, 8, 12)) folds = rsample::vfold_cv(train.data, v = 5) metric = metric_set(rmse) set_dependency("rand_forest", "ranger", "ranger", mode = "regression") # Random forest my.rf.rec = sales.rec %>% step_dummy(all_nominal_predictors()) %>% step_zv(all_predictors()) %>% step_other(all_nominal_predictors()) my.rf.wflow = workflow() %>% add_model(my.rf) %>% add_recipe(my.rf.rec) my.rf.res = my.rf.wflow %>% tune_grid( resamples = folds, metrics = metric, grid = tree.grid )
错误根源与修复方案
1. 核心错误:误将目标变量设为ID角色
在update_role(Id, SalePrice, new_role = "ID")中,把回归目标SalePrice标记为ID列,导致模型训练时无法找到目标变量,直接引发下标越界。
修复:仅将Id设为ID角色:
update_role(Id, new_role = "ID") %>%
2. step_num2factor的levels参数完全错误
用房价的唯一值作为房屋类型编码MSSubClass的因子水平,逻辑完全混乱。
修复:使用MSSubClass自身的唯一值:
step_num2factor(MSSubClass, levels = as.character(unique(train.data$MSSubClass))) %>%
3. NA判断方式错误
GarageType != NA这种写法在R中不成立(NA != NA返回NA),必须用!is.na()判断缺失值。
修复:
step_mutate(has.garage = !is.na(GarageType), has.basement = !is.na(BsmtExposure), has.pool = !is.na(PoolQC), is.new = house.age==0 ) %>%
4. 重复调用step_other
原始Recipe中已经处理过名义变量的低频类别,后续工作流中重复调用会导致冲突。
修复:移除my.rf.rec中的step_other(all_nominal_predictors())。
5. 冗余的set_dependency调用
该函数是tidymodels内部依赖注册函数,用户代码无需手动调用,直接删除即可。
修正后的完整代码
预处理Recipe
data.split = initial_split(house.prices, prop=0.8) train.data = training(data.split) test.data = testing(data.split) # Create recipe - 修正版 sales.rec = recipe(SalePrice ~., data = train.data) %>% step_log(SalePrice, LotArea, GrLivArea, TotRmsAbvGrd) %>% update_role(Id, new_role = "ID") %>% step_num2factor(MSSubClass, levels = as.character(unique(train.data$MSSubClass))) %>% step_unknown(PoolQC, Fence, MiscFeature, BsmtQual, BsmtCond, BsmtExposure, BsmtFinType1, FireplaceQu, GarageType, GarageQual, GarageCond, new_level = "None") %>% step_mutate(PorchArea = OpenPorchSF+EnclosedPorch+`3SsnPorch`+ScreenPorch) %>% step_mutate(garage.age = YrSold - GarageYrBlt, house.age = YrSold - YearBuilt, renovation.age = YrSold - YearRemodAdd ) %>% step_mutate(has.garage = !is.na(GarageType), has.basement = !is.na(BsmtExposure), has.pool = !is.na(PoolQC), is.new = house.age==0 ) %>% step_cut(OverallQual, breaks = c(2.5, 6.5, 8.5)) %>% step_cut(OverallCond, breaks = c(2.5, 6.5, 8.5)) %>% step_mutate(house.age = log(1+house.age)) %>% step_rm(-c(SalePrice, house.age, renovation.age, has.garage, has.basement, has.pool, is.new, MSZoning, LotArea, Alley, LotShape, Utilities, Neighborhood, OverallQual, OverallCond, ExterCond, Foundation, BsmtFinSF1, Heating, HeatingQC, CentralAir, GrLivArea, FullBath, KitchenQual, TotRmsAbvGrd, PavedDrive, PorchArea, MiscVal,SaleCondition)) %>% step_other(all_nominal_predictors(), all_factor(), all_string()) %>% step_string2factor(all_string_predictors()) %>% step_nzv(all_predictors()) %>% step_impute_median(all_numeric_predictors()) %>% step_unknown(all_factor_predictors()) %>% step_normalize(all_numeric_predictors())
模型与工作流
my.rf = rand_forest(mtry = tune(), trees = 2000, min_n=tune()) %>% set_engine("ranger") %>% set_mode("regression") tree.grid = expand.grid(min_n=c(2,14,27,40), mtry = c(4, 8, 12)) folds = rsample::vfold_cv(train.data, v = 5) metric = metric_set(rmse) # Random forest - 修正版 my.rf.rec = sales.rec %>% step_dummy(all_nominal_predictors()) %>% step_zv(all_predictors()) my.rf.wflow = workflow() %>% add_model(my.rf) %>% add_recipe(my.rf.rec) my.rf.res = my.rf.wflow %>% tune_grid( resamples = folds, metrics = metric, grid = tree.grid )
内容的提问来源于stack exchange,提问作者JPR
相关产品推荐
相关产品推荐

