R语言含列表的while(TRUE)循环无法正确终止及lm.fit报错排查
问题根因
你的代码有两个核心bug,直接导致死循环和最终的拟合报错:
- 终止条件完全错误:你每次把当前阶的筛选结果存在
pmod[[i]]中,之后用sapply(pmod, length)生成各阶结果的长度向量,再判断这个向量本身的长度是否为0。只要i≥1,这个向量的长度就等于当前迭代次数i,哪怕某一阶的结果被compact()处理成空列表,sapply返回的也是长度为i、对应位置值为0的向量,length(length_pmod) == 0的条件永远不可能成立,break永远不会触发,i会无限递增。 - 高次幂数值溢出:你用的是raw=TRUE的原始多项式,会直接计算预测变量的i次幂。以测试用的savings数据为例,pop15取值在20~48区间,当i增长到20以上时,20^20已经超出R双精度浮点数的可表示范围,会生成Inf/NaN值传入lm,直接触发
NA/NaN/Inf in 'x'的报错。 - 额外逻辑偏差:你当前的筛选逻辑是只要某一阶里任意一个低次项显著就继续迭代,不符合最初“最高阶项不显著就终止”的多项式阶数选择逻辑。
修复后可用代码
library(tidyverse) library(faraway) regression_polynomial <- function(data, response_chosen, predictor_chosen, max_degree = 10, sig_level = 0.05){ pmod <- list() i <- 0 while(TRUE){ i <- i + 1 # 兜底终止:超过设定最大阶数直接停,避免极端情况死循环 if(i > max_degree){ warning("已达到设定的最大多项式阶数,迭代终止") break } # 构造当前阶的模型公式 form <- reformulate( termlabels = glue::glue('poly({predictor_chosen},{i}, raw=TRUE)'), response = response_chosen ) # 拟合模型并提取系数表 current_fit <- lm(form, data) coef_info <- current_fit %>% summary() %>% .$coefficients %>% as.data.frame() %>% rownames_to_column("term") %>% filter(term != "(Intercept)") %>% rename( estimate = 2, std_error = 3, t_value = 4, p_value = 5 ) # 存储当前阶的拟合结果 pmod[[i]] <- list( degree = i, fit = current_fit, coef = coef_info ) # 只判断最高阶项的p值,不显著就删掉当前阶结果后终止 highest_p <- coef_info$p_value[i] if(highest_p >= sig_level){ pmod[[i]] <- NULL break } } return(pmod) } # 测试运行 res <- regression_polynomial(savings, "sr", "pop15") # 输出最终选择的多项式阶数 cat("最优多项式阶数:", length(res), "\n")
效果说明
- 测试savings数据集场景时,迭代到3阶时3次项p值大于0.05,会自动终止,最终返回2阶多项式的拟合结果,不会出现死循环和数值溢出问题。
- 新增
max_degree参数做兜底,就算遇到特殊数据分布导致高阶项一直显著,也不会无限循环到数值计算溢出。 - 返回结果按阶数存储了对应的模型对象、系数表,后续做预测、绘图、结果提取都可以直接调用。
内容的提问来源于stack exchange,提问作者tesla john
相关产品推荐
相关产品推荐

