如何用geom_smooth()绘制多条nls拟合曲线(函数调用中获取模型参数)
解决ggplot分组拟合曲线(带专属起始参数)的问题
嘿,我完全懂你这种卡在ggplot分组拟合+自定义参数传递的痛苦!尤其是每个子集要带专属起始参数(比如某变量最小值)的时候,环境和geom_smooth的参数传递确实容易踩坑。我用公开的mtcars数据集给你做个可复现的示例,刚好对应你说的5个子集、同公式不同起始参数的需求,你可以直接套用到你的真实数据上。
步骤1:准备分组数据 + 定义每组专属起始参数
首先我们给mtcars添加5个分组,同时计算每个组的专属起始参数(这里用disp的最小值模拟你的需求):
library(ggplot2) library(dplyr) library(purrr) # 设置随机种子保证结果可复现 set.seed(123) # 创建5个数据子集,计算每组的起始参数(disp的最小值) mtcars_grouped <- mtcars %>% mutate(group = cut(mpg, breaks = 5, labels = paste0("Group ", 1:5))) %>% group_by(group) %>% mutate(x_min = min(disp)) %>% ungroup()
步骤2:定义带专属参数的自定义拟合函数
因为geom_smooth默认的方法没法直接给每个组传递独立参数,我们写一个自定义函数,每个组用自己的x_min来拟合模型(这里用非线性模型示例,你可以换成自己的公式):
# 自定义拟合函数:输入单组数据,输出该组的预测曲线数据 custom_fit <- function(data) { # 拟合模型:这里用 hp ~ a + b*(disp - x_min),x_min是每组专属起始参数 model <- nls( hp ~ a + b*(disp - x_min), data = data, start = list(a = min(data$hp), b = 0.1), # 初始值可根据你的数据调整 trace = FALSE # 关闭拟合过程输出 ) # 生成预测用的序列数据,保证曲线平滑 new_data <- data.frame(disp = seq(min(data$disp), max(data$disp), length.out = 100)) %>% mutate(x_min = unique(data$x_min)) # 计算预测值,绑定分组信息 new_data$pred <- predict(model, newdata = new_data) cbind(new_data, group = unique(data$group)) }
步骤3:分组拟合并合并结果
用group_split拆分数据,再用map_dfr批量拟合每个组,最后合并所有预测结果:
# 对每个分组应用拟合函数,合并成完整的预测数据集 fit_results <- mtcars_grouped %>% group_split(group) %>% map_dfr(custom_fit)
步骤4:绘制原始数据 + 分组拟合曲线
最后用ggplot把原始点和拟合曲线画在一起,完美实现5条带专属参数的拟合线:
ggplot() + # 绘制原始数据点,按分组上色 geom_point(data = mtcars_grouped, aes(x = disp, y = hp, color = group), alpha = 0.6) + # 绘制分组拟合曲线 geom_line(data = fit_results, aes(x = disp, y = pred, color = group), linewidth = 1) + # 添加标题和标签 labs(title = "5个子集的分组拟合曲线(带专属起始参数)", x = "排量(disp)", y = "马力(hp)", color = "分组") + theme_minimal()
关键问题说明
- 为什么不用直接用
geom_smooth?因为geom_smooth的method.args没法自动识别分组参数,容易出现环境绑定错误,分组拟合后再绘图的方式更可靠,也更灵活。 - 如果你用的是线性模型,只需要把自定义函数里的
nls换成lm即可,逻辑完全一致。
内容的提问来源于stack exchange,提问作者mpaladino
相关产品推荐
相关产品推荐

