为啥 do(lm...) 和 geom_smooth(method="lm") 有区别?
Posted
技术标签:
【中文标题】为啥 do(lm...) 和 geom_smooth(method="lm") 有区别?【英文标题】:Why is there a difference between do(lm...) and geom_smooth(method="lm")?为什么 do(lm...) 和 geom_smooth(method="lm") 有区别? 【发布时间】:2019-08-21 13:32:53 【问题描述】:我有一条略微进入饱和状态的外部校准曲线。所以我拟合了一个二阶多项式和一个测量样本的数据框,我想知道其中的浓度。
df_calibration=structure(list(dilution = c(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7,
0.8, 0.9, 1, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1),
area = c(1000, 2000, 3000, 4000, 5000, 6000, 7000, 7800,
8200, 8500, 1200, 2200, 3200, 4200, 5200, 6200, 7200, 8000,
8400, 8700), substance = c("A", "A", "A", "A", "A", "A",
"A", "A", "A", "A", "b", "b", "b", "b", "b", "b", "b", "b",
"b", "b")), row.names = c(NA, 20L), class = "data.frame")
df_samples=structure(list(area = c(1100, 1800, 2500, 3200, 3900, 1300, 2000,
2700, 3400, 4100), substance = c("A", "A", "A", "A", "A", "b",
"b", "b", "b", "b")), row.names = c(NA, 10L), class = "data.frame")
现在为了计算测量样品的实际稀释度,我采用了由此拟合生成的参数:
df_fits=df_calibration %>% group_by(substance) %>%
do(fit = lm(area ~ poly(dilution,2), data = .))%>%
tidy(fit) %>%
select(substance, term, estimate) %>%
spread(term, estimate)
df_fits=df_fits %>% rename(a=`poly(dilution, 2)2`,b=`poly(dilution, 2)1`,c=`(Intercept)`)
#join parameters with sample data
df_samples=left_join(df_samples,df_fits)
还有这个公式
#calculate with general solution for polynomial 2nd order
df_samples$dilution_calc=
(df_samples$b*(-1)+sqrt(df_samples$b^2-(4*df_samples$a*(df_samples$c-df_samples$area))))/(2*df_samples$a)
但是,当我现在绘制这个时,我注意到一些非常奇怪的东西。
计算出的 x 值(稀释)不会出现在 stat_smooth()
的曲线上。附加的虚线与图表中方程的参数(与数据框中的数字匹配)用于物质“A”。所以我的计算应该是正确的(或不正确?)为什么会有差异?我究竟做错了什么?我如何从stat_smooth()
完成的拟合中获取参数?
my.formula=y ~ poly(x,2)
ggplot(df_calibration, aes(x = dilution, y = area)) +
stat_smooth(method = "lm", se=FALSE, formula = my.formula) +
stat_function(fun=function(x)5250+(7980*x)+(-905*x^2),
inherit.aes = F,linetype="dotted")+
stat_poly_eq(formula = my.formula,
aes(label = paste(..eq.label.., ..rr.label.., sep = "~~~")),
parse = TRUE) +
geom_point(shape=17)+
geom_point(data=df_samples,
aes(x=dilution_calc,y=area),
shape=1,color="red")+
facet_wrap(~substance,scales = "free")
任何建议都将受到高度赞赏:-)
【问题讨论】:
在我的脑海中,我无法弄清楚“二次公式”与二阶多项式的预测有什么关系。因此,您可能应该更详细地描述您正在使用的逻辑。如果您使用来自poly()
的系数,那么您 a) 需要包括截距 b) 需要记住二阶项已与一阶项正交。而且,尽管执行了library(tidyverse)
,但我仍然收到“整理错误(., fit):找不到函数“整理””
【参考方案1】:
默认情况下,poly
计算正交多项式。您可以使用 raw=TRUE
参数关闭正交化。
请注意,该公式出现了两种情况:一次使用原始变量名称拟合回归,然后在stat_smooth
中使用通用变量名称x
和y
。但否则它应该是相同的公式,raw=TRUE
。
library("tidyverse")
# Define/import your data here....
df_fits <- df_calibration %>%
group_by(substance) %>%
do(fit = lm(area ~ poly(dilution, 2, raw = TRUE), data = .)) %>%
broom::tidy(fit) %>%
select(substance, term, estimate) %>%
spread(term, estimate) %>%
# It is simpler to rename the coefficients here
setNames(c("substance", "c", "b", "a"))
# join parameters with sample data
df_samples <- left_join(df_samples, df_fits)
# calculate with general solution for polynomial 2nd order
df_samples <- df_samples %>%
mutate(dilution_calc = (b * (-1) + sqrt(b^2 - (4 * a * (c - area)))) / (2 * a))
my.formula <- y ~ poly(x, 2, raw = TRUE)
df_calibration %>%
ggplot(aes(x = dilution, y = area)) +
stat_smooth(method = "lm", se = FALSE, formula = my.formula) +
geom_point(shape = 17) +
geom_point(
data = df_samples,
aes(x = dilution_calc, y = area),
shape = 1, color = "red"
) +
facet_wrap(~substance, scales = "free")
由reprex package (v0.2.1) 于 2019 年 3 月 31 日创建
【讨论】:
以上是关于为啥 do(lm...) 和 geom_smooth(method="lm") 有区别?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在分组 data.table 中的 lm 上使用更新会丢失其模型数据?
为啥即使在包含 math.h 并使用 -lm 链接到数学库之后我也会收到“未定义的符号:.sqrtf”