You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

受限立方样条拐点求解失败求助(R语言RMS包)

解决uniroot报错及寻找模型拐点的方法

报错原因

uniroot(f, interval=c(20,35))报错f(lower) * f(upper) > 0,核心问题有两个:

  • 你传入的f是模型的预测因变量函数,而非找拐点需要的二阶导数函数,目标方向错误。
  • 即使是找极值点(一阶导数为0),当前区间[20,35]内函数值符号未发生变化,uniroot无法找到有效根。

正确寻找拐点的步骤

拐点是曲线二阶导数为0的点,对应rcs(BMI)拟合曲线的曲率变化点,需按以下操作执行:

1. 先可视化拟合曲线,确认拐点存在性及合理区间

先画出BMI与BMD_ALL的拟合曲线及二阶导数曲线,观察曲率变化,确定uniroot的有效区间:

# 生成覆盖数据实际范围的BMI序列
bmi_seq <- seq(min(test$BMI, na.rm=TRUE), max(test$BMI, na.rm=TRUE), length.out=100)
# 固定其他协变量(示例为gender取参考水平、age取均值,可根据需求调整)
new_data <- data.frame(BMI=bmi_seq, gender=factor(levels(test$gender)[1]), age=mean(test$age, na.rm=TRUE))
# 预测二阶导数
preds_second <- predict(test_model, newdata=new_data, deriv=2)
# 绘制二阶导数曲线,查看是否穿越0线
plot(bmi_seq, preds_second, type="l", xlab="BMI", ylab="二阶导数")
abline(h=0, col="red", lty=2)

通过此图可观察到二阶导数在哪个区间内穿过0,以此作为uniroot的输入区间。

2. 定义二阶导数函数,用uniroot找根

方法一:利用rms内置的导数计算

直接用predict的deriv参数构造二阶导数函数:

# 固定其他协变量的二阶导数函数
f_second_deriv <- function(bmi) {
  predict(test_model, 
          newdata=data.frame(BMI=bmi, gender=factor(levels(test$gender)[1]), age=mean(test$age, na.rm=TRUE)), 
          deriv=2)
}

# 替换为你从可视化中得到的有效区间
uniroot_out <- uniroot(f = f_second_deriv, interval = c(25, 30))
uniroot_out

方法二:用Deriv包自动求导

若需要更灵活的求导方式,可使用Deriv包:

install.packages("Deriv")
library(Deriv)

# 定义固定协变量的预测函数
f_pred <- function(bmi) {
  predict(test_model, 
          newdata=data.frame(BMI=bmi, gender=factor(levels(test$gender)[1]), age=mean(test$age, na.rm=TRUE)))
}

# 求二阶导数
f_second_deriv <- Deriv(Deriv(f_pred))

# 传入有效区间找根
uniroot_out <- uniroot(f = f_second_deriv, interval = c(25, 30))
uniroot_out

3. 关键注意事项

  • 必须固定其他协变量(gender、age)的取值,拐点是控制其他变量时BMI与BMD_ALL关系的曲率变化点,不同协变量取值可能对应不同拐点。
  • 若可视化后发现二阶导数始终大于0或小于0,说明拟合曲线无拐点,此时uniroot必然报错,无需强行寻找。
  • 确保interval区间内二阶导数两端符号相反(一正一负),否则需调整区间范围。

内容的提问来源于stack exchange,提问作者you lin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 00:06:03