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

y轴对数变换下如何从stat_smooth提取二次拟合并求y=0.1时的x值

问题:log变换y轴后lm()与stat_smooth拟合不一致,求y=0.1时的x坐标

我想要提取二次拟合线以计算y=0.1时的x坐标,但由于y轴采用了log变换,lm()函数与stat_smooth得到的拟合结果不一致。最小数据集及代码如下:

xvals <- c(0,1,2,2.5,3,5,7.5,10)
yvals <- c(1,0.65,0.425,0.45,0.26,0.085,0.0121667,0.000675)
df <- cbind.dataframe(xvals,yvals)

ggplot(df, aes(x = xvals, y = yvals))+
  stat_smooth(method= 'lm', formula = y~poly(x,2), se = F, color = 'blue')+
  stat_function(fun=function(x) 0.93389 + -0.25608 *x + 0.01663*x^2, color = 'green')+
  geom_point(color = 'blue', shape = 22, size = 3)+
  geom_hline(yintercept = 0.1)+
  geom_vline(xintercept = 4.675868)+
  scale_y_continuous(trans = 'log10')

stat_function的参数来自lm(使用poly(x,2,raw=T)结果一致):

lm(df, formula = yvals ~ I(xvals^2) + I(xvals))

通过解方程得到y=0.1时x≈4.7,但该结果与stat_smooth的拟合线不匹配;移除y轴log变换后,两者拟合线重合,交点为4.7。推测这是因为ggplot在拟合前先转换了数据,请问如何转换lm的输入数据,或获取stat_smooth使用的方程,以得到其与y=0.1交点的x坐标?


解决方案

核心原因

当你给ggplot添加scale_y_continuous(trans='log10')时,stat_smooth会先对y值做log10转换,再在转换后的数据上做二次线性拟合;而你直接调用lm(yvals ~ poly(xvals,2))是在原始y值上拟合,两者的拟合对象完全不同,所以结果自然不一致。

方法一:手动转换数据拟合,解方程求x

直接对y值做log10转换后拟合二次模型,再反推y=0.1对应的x值:

  1. 拟合对数转换后的模型
# 对y做log10转换,拟合x的二次多项式
lm_log <- lm(log10(yvals) ~ poly(xvals, 2, raw = TRUE), data = df)
# 查看系数
coefs <- coef(lm_log)
coefs
  1. 解方程求x
    当y=0.1时,log10(0.1) = -1,代入拟合方程log10(y) = a + b*x + c*x²,得到:
    c*x² + b*x + (a + 1) = 0
    用R代码求解这个二次方程:
# 提取系数
a <- coefs[1]
b <- coefs[2]
c <- coefs[3]

# 解二次方程
roots <- polyroot(c(a + 1, b, c))
# 筛选出实数根,且在x的取值范围内的解
real_root <- Re(roots)[abs(Im(roots)) < 1e-10]
valid_x <- real_root[real_root >= min(df$xvals) & real_root <= max(df$xvals)]

# 输出结果
valid_x
  1. 验证拟合曲线
    将拟合方程转换回原始y轴尺度,用stat_function画出来,会和stat_smooth的蓝色曲线完全重合:
ggplot(df, aes(x = xvals, y = yvals))+
  stat_smooth(method= 'lm', formula = y~poly(x,2), se = F, color = 'blue')+
  stat_function(fun=function(x) 10^(a + b*x + c*x^2), color = 'red', linetype = "dashed")+
  geom_point(color = 'blue', shape = 22, size = 3)+
  geom_hline(yintercept = 0.1)+
  scale_y_continuous(trans = 'log10')

方法二:提取stat_smooth的拟合模型参数

可以通过ggplot_build直接提取stat_smooth使用的拟合数据和模型:

# 构建ggplot对象
p <- ggplot(df, aes(x = xvals, y = yvals))+
  stat_smooth(method= 'lm', formula = y~poly(x,2), se = F, color = 'blue')+
  geom_point(color = 'blue', shape = 22, size = 3)+
  scale_y_continuous(trans = 'log10')

# 提取拟合的模型数据
smooth_data <- ggplot_build(p)$data[[1]]
# smooth_data中的y值是log10转换后的预测值,x是对应的x值

# 如果你想直接找y=0.1(即log10(y)=-1)对应的x,可以用插值法
approx(x = smooth_data$x, y = smooth_data$y, xout = NULL, y = -1)$x

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 12:04:51