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

ggplot2::geom_smooth调用gamlss::gamlss(ZAGA分布)报错及零膨胀连续分布拟合替代方案咨询

解决geom_smooth结合gamlss(ZAGA)的行数不匹配问题及替代方案

为什么会出现行数不匹配的警告?

直接在geom_smooth中使用method = gamlss::gamlss会报错,是因为stat_smooth的内部逻辑对拟合函数的返回值有特定要求——它期望模型的predict方法返回的结果长度和输入的预测网格行数完全一致,但gamlss的模型对象和stat_smooth的预期结构不兼容,导致了行数差异(比如示例中的80 vs 81),最终绘图为空。简单来说,gamlss并没有被geom_smooth官方支持,不能直接作为method参数传入。


解决方案1:手动拟合+预测绘图(支持置信区间、分组/分面)

既然直接用geom_smooth行不通,我们可以手动完成模型拟合、预测值+置信区间计算,再用ggplot2的基础图层绘图,这种方式完全可控,还能轻松支持分组和分面需求。

基础示例(单组数据)

library(gamlss)
library(dplyr)
library(ggplot2)

# 你的示例数据
in_df <- tibble(x = c(0.1, 3.1, 3, 0.5, 2, 0.2, 2.9, 1.2, 1, 0.2), 
                y = c(0, 2, 0, 0.2, 4, 0, 0, 1, 0, 0))

# 拟合ZAGA模型
gamlss_fit <- gamlss(y ~ x, data = in_df, family = ZAGA())

# 生成密集的x预测序列(比原始数据更平滑)
pred_x <- tibble(x = seq(min(in_df$x), max(in_df$x), length.out = 100))

# 预测响应值的均值和标准误
preds <- predict(gamlss_fit, newdata = pred_x, type = "response", se.fit = TRUE)

# 整理预测结果(计算95%置信区间)
pred_df <- pred_x %>%
  mutate(fit = preds$fit,
         se = preds$se.fit,
         lower = fit - 1.96 * se,  # 95%置信区间
         upper = fit + 1.96 * se)

# 绘图:原始点+拟合线+置信区间
ggplot(in_df, aes(x = x, y = y)) +
  geom_point(size = 2, alpha = 0.7) +
  geom_line(data = pred_df, aes(y = fit), color = "#2c3e50", linewidth = 1) +
  geom_ribbon(data = pred_df, aes(y = fit, ymin = lower, ymax = upper), 
              fill = "#2c3e50", alpha = 0.2)

分组/分面示例

如果你的数据有分组变量,我们可以用dplyr的分组嵌套功能批量拟合模型并生成预测:

set.seed(123) # 保证结果可复现
# 构造带分组的模拟数据
grouped_df <- bind_rows(
  tibble(x = runif(20, 0, 3), y = rZAGA(20, mu = 1 + 0.5*x, sigma = 0.3, nu = 0.7), group = "A"),
  tibble(x = runif(20, 0, 3), y = rZAGA(20, mu = 2 + 0.8*x, sigma = 0.4, nu = 0.6), group = "B")
)

# 分组拟合模型并生成预测数据
group_preds <- grouped_df %>%
  group_by(group) %>%
  nest() %>%
  mutate(
    # 为每个分组拟合ZAGA模型
    model = map(data, ~ gamlss(y ~ x, data = ., family = ZAGA())),
    # 为每个分组生成预测序列和置信区间
    pred_data = map2(model, data, function(mod, df) {
      pred_x <- tibble(x = seq(min(df$x), max(df$x), length.out = 100))
      preds <- predict(mod, newdata = pred_x, type = "response", se.fit = TRUE)
      pred_x %>%
        mutate(
          fit = preds$fit,
          se = preds$se.fit,
          lower = fit - 1.96*se,
          upper = fit + 1.96*se,
          group = df$group[1]
        )
    })
  ) %>%
  unnest(pred_data)

# 分组绘图(分面或叠加均可)
ggplot(grouped_df, aes(x = x, y = y, color = group, fill = group)) +
  geom_point(alpha = 0.6) +
  geom_line(data = group_preds, aes(y = fit), linewidth = 1) +
  geom_ribbon(data = group_preds, aes(y = fit, ymin = lower, ymax = upper), 
              alpha = 0.2, color = NA) +
  facet_wrap(~group) # 去掉这行就是叠加显示

解决方案2:适配geom_smooth的自定义方法(可选)

如果你一定要用geom_smooth的语法,可以自定义一个适配gamlss的方法函数,但这种方式相对复杂,且灵活性不如手动拟合。核心是让函数返回stat_smooth期望的结构(包含fit和se.fit的列表),示例框架如下:

# 自定义适配gamlss的方法函数
gamlss_smooth <- function(formula, data, family = ZAGA(), ...) {
  mod <- gamlss(formula, data = data, family = family, ...)
  pred <- predict(mod, newdata = data, type = "response", se.fit = TRUE)
  list(fit = pred$fit, se.fit = pred$se.fit)
}

# 使用自定义方法
ggplot(in_df) +
  geom_point(aes(x = x, y = y)) +
  geom_smooth(aes(x = x, y = y), method = gamlss_smooth, formula = y ~ x, se = TRUE)

不过这种方法的预测是基于原始数据点,而不是平滑的网格线,视觉效果不如手动生成密集预测序列好。


关于零调整连续分布的替代方案

如果你希望用method = "gam"(即mgcv包的gam函数),mgcv本身没有直接支持ZAGA分布,但可以考虑以下两种思路:

  1. 两阶段模型:先拟合二项模型预测是否为0,再对非零数据拟合gamma模型。但这种方式是分开的两个模型,不如ZAGA的单模型拟合效率高,且无法直接整合出统一的置信区间。
  2. 自定义族函数:为mgcv编写ZAGA的族函数,但这需要一定的统计编程基础,门槛较高。

对于你的日降雨量数据,ZAGA仍然是最适配的模型,因此推荐使用手动拟合+预测的绘图方式,既能保留模型的拟合效果,又能满足可视化需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 20:22:45