nls拟合含两个分类变量的Makeham模型报错如何解决
报错的核心原因
你当前的模型参数设计存在硬伤级的秩亏问题,没有唯一的拟合解,这是触发数值计算报错的根源:
- 单分类模型里你写的
a[maduraciongrp]是3个对应成熟度组的全自由常数,因为没有其他加性截距项,模型刚好满秩,可以正常收敛。 - 当你新增
b[origen]这组2个对应来源组的全自由常数后,两个向量的加和c_ij = a_i + b_j存在无穷多组解:只要把所有a_i的值加k、所有b_j的值减k,所有组的拟合常数完全不变。 - 这种结构下nls计算数值导数会碰到梯度共线的问题,步长稍微偏移就会算出无穷大或者缺失值,直接触发
Missing value or an infinity produced when evaluating the model的报错。 - 额外的疏漏:你预处理时只把
maduraciongrp转成了因子,origen还是字符型,虽然在当前数据集里不会直接崩溃,但后续做分类索引很容易出现匹配错乱。
具体调整方案
按照研究逻辑选择满秩的模型结构,消除参数的线性依赖:
1. 先修正数据预处理
把两个分类变量都转为正式因子,固定索引顺序:
df <- df %>% mutate( mx = dec/expuestos, maduraciongrp = as.factor(maduraciongrp), origen = as.factor(origen) )
2. 选择可识别的双分类模型结构
结构A:两个分类为加性效应(最常用,无交互)
保留已验证可识别的成熟度组全常数项a[maduraciongrp],把来源组的效应改成相对于基准组的标量偏移,避免双全自由向量的秩亏问题。
逻辑是:来源为0的组常数项是成熟度组对应的a_i,来源为1的组常数项在a_i的基础上加一个固定偏移b_orig。
对应的可运行代码:
# 基于已拟合的Gompertz和单分类Makeham模型设置初始值 makeham_single_cat <- nls( mx ~ a[maduraciongrp] + exp(b0 + b1*edad), data = df, start = list( a = rep(0, nlevels(df$maduraciongrp)), b0 = coef(gompertz)[1], b1 = coef(gompertz)[2] ), weights = expuestos ) # 纳入origen的加性效应 makeham_add_two_cat <- nls( mx ~ a[maduraciongrp] + b_orig * I(origen == levels(df$origen)[2]) + exp(b0 + b1*edad), data = df, start = list( a = coef(makeham_single_cat)[c("a1", "a2", "a3")], # 复用单分类模型的a值做初始值 b_orig = 0, # 第二个来源组相对于基准组的常数偏移 b0 = coef(makeham_single_cat)["b0"], b1 = coef(makeham_single_cat)["b1"] ), weights = expuestos )
这个结构完全没有共线性问题,a参数对应每个成熟度组的基础常数,b_orig参数对应两个来源组的常数差,所有参数都有独立的解释。
结构B:两个分类为交互效应(每个组合独立常数)
如果研究逻辑是“成熟度+来源”的每个组合都有独立的常数项,不要拆成两个独立向量,直接用交互生成的分组作为常数项的索引,类似你单分类的写法。
对应的可运行代码:
# 生成两个分类的交互分组 df$comb_grp <- interaction(df$maduraciongrp, df$origen) makeham_interact_two_cat <- nls( mx ~ c[comb_grp] + exp(b0 + b1*edad), data = df, start = list( c = rep(0, nlevels(df$comb_grp)), # 3*2=6个独立常数项 b0 = coef(gompertz)[1], b1 = coef(gompertz)[2] ), weights = expuestos )
这个结构的每个常数项都是独立估计的,没有线性依赖,nls可以稳定收敛。
避坑提示
nls对秩亏模型的兼容性极差,只要参数空间存在线性依赖,不管初始值设置得多接近真值,最终都会触发数值计算类的报错。这类问题无法通过调整初始值解决,必须从模型结构上消除参数的线性冗余。
内容的提问来源于stack exchange,提问作者bubleskmy
相关产品推荐
相关产品推荐

