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

R ggplot2 geom_ribbon()分组绘制置信区间出现尖刺锯齿异常

问题根因

geom_ribbon()绘制出带尖刺的锯齿状填充,核心是绘图逻辑和数据粒度不匹配:

  • 你通过predictInterval()得到的upr、lwr是**单条原始观测(单个被试单个时间点)**的预测区间边界,同一Time、同一Treatment分组下,不同被试的上下界值是分散的
  • 你画拟合线、上下界虚线时用了stat_summary(),会自动按Treatment分组对y值求均值后再绘制,所以虚线显示正常
  • 但geom_ribbon()默认使用stat="identity",直接逐行读取原始观测的lwr/upr连线填充,相当于把所有被试的独立区间挨个串起来填充,自然会出现尖刺
  • 按Subject分组绘图时能正常显示,是因为每个分组下每个Time点仅对应单个被试的一组lwr/upr值,不存在多观测混排,所以填充效果正常
解决方案

两种可直接复用的实现方式,按需选择即可:

方案1:提前聚合数据再绘图

先按绘图维度对数据分组求均值,再用聚合后的数据集绘图,从根源避免逐观测连线的问题:

library(dplyr)
library(ggplot2)

# 按绘图维度提前聚合指标
GCA_agg <- GCA3 %>%
  filter(Experiment == "Blocking", Time <= 10) %>%
  group_by(Experiment, Treatment, Time) %>%
  summarise(
    GCA_Full = mean(GCA_Full, na.rm = TRUE),
    upr = mean(upr, na.rm = TRUE),
    lwr = mean(lwr, na.rm = TRUE),
    .groups = "drop"
  )

# 直接用聚合后的数据绘图,无需嵌套stat_summary
mplot2 <- ggplot(GCA_agg, aes(Time, GCA_Full, group = Treatment, fill = Treatment, color = Treatment))+
  geom_line(linewidth = 1) + # 模型拟合线
  geom_ribbon(aes(ymin = lwr, ymax = upr), color = NA, alpha = 0.1) + # 置信区间填充
  geom_line(aes(y = upr), linetype = "dashed") + # 上界虚线
  geom_line(aes(y = lwr), linetype = "dashed") + # 下界虚线
  theme_bw(base_size = 10) +
  facet_wrap(~Experiment) +
  labs(x = "Item", y = "Accuracy (elogit)") +
  scale_x_continuous(breaks = seq(0, 10, 1))

方案2:在geom_ribbon中指定汇总统计逻辑

不提前聚合数据,直接给geom_ribbon添加统计汇总参数,让它和stat_summary逻辑一致,先按分组求均值再绘制填充区域:

mplot2 <- filter(GCA3, Experiment == "Blocking", Time <= 10) %>% 
  ggplot(aes(Time, GCA_Full, group = Treatment, fill = Treatment, color = Treatment))+
  stat_summary(aes(y = GCA_Full), fun = mean, geom = "line")+
  stat_summary(aes(y = upr), fun = mean, geom = "line", linetype = "dashed")+
  stat_summary(aes(y = lwr), fun = mean, geom = "line", linetype = "dashed")+
  # 给ribbon添加stat和fun参数,自动按分组聚合上下界
  geom_ribbon(aes(ymin = lwr, ymax = upr), stat = "summary", fun = mean, na.rm = TRUE, color = NA, alpha = 0.1) +
  theme_bw(base_size = 10) +
  facet_wrap(~Experiment)
labels <- labs(x = "Item", y = "Accuracy (elogit)")
mplot2 + labels + scale_x_continuous(breaks = seq(0, 10, 1))
补充说明

注意:上述方法是对逐观测预测区间求均值得到分组区间,本质上不是严格的总体均值置信区间。如果需要更严谨的群体水平置信区间,建议在predictInterval阶段就构建仅包含Treatment、Experiment、Time维度(剔除Subject随机效应)的新数据框做预测,不要对原始逐被试数据的预测结果直接求均值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 10:45:38