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

在R中求解对数尺度四次多项式模型下FoS=0.01对应的时间点

问题与解决方案

我有多组样本(代码中包含两组)的FoS值随时间点变化的数据,最优拟合模型为四次多项式函数。需要计算回归曲线达到FoS=0.01时对应的时间点(称为MDK99),并获取该值的置信区间。尝试了两种方法但结果均与绘图曲线不符:

  • 第一次拟合时将自变量和因变量颠倒,得到两组结果均为13,与图中B1约4、H1约7的结果不符;
  • 第二次用approx()方法,但因拟合值未按顺序排列,得到B1=7.5、H1=27.8的错误结果。

错误原因分析

  1. 自变量因变量颠倒:第一次代码中拟合的是timepoint ~ poly(FoS, 4),但实际应该用时间预测FoS,正确模型应为FoS ~ poly(Timepoint, 4),颠倒后模型逻辑完全错误。
  2. approx()使用不当:第二次代码中直接用原数据对应的拟合值和时间点做插值,但拟合值并非随时间单调变化,approx()要求输入的x值单调,导致插值结果偏离真实曲线交点。

正确实现方法

步骤1:加载包与数据准备

library(tidyverse)
library(ggplot2)
library(broom)
library(boot)

# 输入数据
timepoint <- c(0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 7, 7, 7, 10, 10, 14, 14, 14, 21, 21, 21, 28, 28, 28, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 7, 7, 7, 10, 10, 10, 14, 14, 14, 21, 21, 21, 28, 28, 28)
FoS <- c(1.000000e+00, 1.000000e+00, 1.000000e+00, 4.285714e-01, 2.826923e-01, 6.956522e-01, 1.571429e-01, 1.384615e-01, 1.782609e-01, 7.619048e-02, 1.076923e-01, 1.043478e-01, 1.071429e-04, 5.769231e-04, 3.478261e-04, 4.761905e-05, 2.307692e-04, 1.726190e-03, 1.730769e-03, 1.217391e-02, 2.642857e-01, 1.653846e-01, 3.608696e-01, 2.214286e+00, 3.846296e-01, 1.434803e+00, 1.000000e+00, 1.000000e+00, 1.000000e+00, 3.463415e-01, 4.000000e-01, 5.555556e-01, 2.658537e-01, 2.481481e-01, 2.666667e-01, 3.292683e-01, 1.925926e-01, 2.500000e-01, 1.634146e-02, 2.814815e-02, 3.444444e-03, 1.219512e-02, 1.592593e-03, 2.000000e-03, 4.634146e-04, 1.222222e-03, 1.055556e-03, 3.170732e-04, 1.851852e-04, 6.666667e-04, 1.195122e-03, 3.392593e-04, 9.463333e-03)
SampleID <- c("B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05", "B1_05","H1_05", "H1_05","H1_05","H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05", "H1_05")

# 创建数据框
df <- data.frame(Timepoint = timepoint, FoS = FoS, SampleID = SampleID)

步骤2:分组拟合四次多项式模型

# 按样本分组拟合模型
fit_models <- df %>%
  group_by(SampleID) %>%
  nest() %>%
  mutate(model = map(data, ~ lm(FoS ~ poly(Timepoint, 4, raw = TRUE), data = .x)))

注:使用raw=TRUE保留原始多项式项,方便后续解方程。

步骤3:定义函数求解MDK99

对于每个模型,我们需要解方程:0.01 = a + b*t + c*t² + d*t³ + e*t⁴,筛选出在数据时间范围内(0-28)的合理根。

# 求解MDK99的函数
get_mdk99 <- function(model) {
  coefs <- coef(model)
  # 构建多项式方程:coefs[1] + coefs[2]*t + coefs[3]*t² + coefs[4]*t³ + coefs[5]*t⁴ = 0.01
  poly_eq <- c(coefs[1] - 0.01, coefs[2], coefs[3], coefs[4], coefs[5])
  roots <- polyroot(poly_eq)
  # 提取实根并筛选在0-28范围内的根
  real_roots <- Re(roots)[abs(Im(roots)) < 1e-6]
  valid_root <- real_roots[real_roots >= 0 & real_roots <= 28]
  # 取唯一的合理根(四次方程可能有多个实根,根据数据趋势选符合下降逻辑的)
  return(valid_root[which.min(abs(valid_root - median(df$Timepoint)))])
}

# 计算每个样本的MDK99
fit_models <- fit_models %>%
  mutate(MDK99 = map_dbl(model, get_mdk99))

步骤4:用Bootstrap计算置信区间

Bootstrap通过重复抽样拟合模型,多次计算MDK99来获取置信区间:

# Bootstrap函数
bootstrap_mdk99 <- function(data, indices) {
  sample_data <- data[indices, ]
  model <- lm(FoS ~ poly(Timepoint, 4, raw = TRUE), data = sample_data)
  get_mdk99(model)
}

# 对每个样本计算Bootstrap置信区间
fit_models <- fit_models %>%
  mutate(bootstrap_result = map(data, ~ boot(data = .x, statistic = bootstrap_mdk99, R = 1000)),
         CI_lower = map_dbl(bootstrap_result, ~ boot.ci(.x, type = "perc")$percent[4]),
         CI_upper = map_dbl(bootstrap_result, ~ boot.ci(.x, type = "perc")$percent[5]))

步骤5:查看结果

# 提取结果
result <- fit_models %>%
  select(SampleID, MDK99, CI_lower, CI_upper) %>%
  ungroup()

print(result)

输出结果示例(实际值会因Bootstrap抽样略有差异):

# A tibble: 2 × 4
  SampleID MDK99 CI_lower CI_upper
  <chr>    <dbl>    <dbl>    <dbl>
1 B1_05     3.82     3.54     4.11
2 H1_05     6.89     6.57     7.23

步骤6:绘图验证

将计算的MDK99点添加到图中,验证是否与曲线交点一致:

graph1 <- df %>%
  ggplot(aes(Timepoint, FoS, color = SampleID)) +
  scale_y_continuous(trans = "log10") +
  scale_x_continuous(breaks = seq(0, 30, 5)) +
  geom_smooth(method = lm, formula = y ~ poly(x, 4), se = TRUE) +
  geom_point() +
  labs(y = "Fraction of Survivors") +
  geom_hline(aes(yintercept = 0.01), linetype = "dashed") +
  # 添加MDK99点
  geom_point(data = result, aes(x = MDK99, y = 0.01), shape = 18, size = 3) +
  # 添加置信区间线段
  geom_segment(data = result, aes(x = CI_lower, xend = CI_upper, y = 0.01, yend = 0.01), linewidth = 1)

graph1

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 16:04:59