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

如何在ggplot2中正确拟合Random Intercept-Fixed Slope模型?

问题描述

我用以下代码生成模拟数据:

# Create an empty data frame to store the simulated data
data <- data.frame(
  Lot = rep(1:num_lots, each = 9),
  Time = rep(3 * 0:8, times = num_lots),
  Purity = numeric(num_lots * 9)
)

# Simulate purity data for each lot and time point
for (lot in 1:num_lots) {
  # Generate random intercept and slope for each lot
  intercept <- rnorm(1, mean = 95, sd = 2)
  slope <- runif(1, min = -.7, max = 0)
  
  for (month in 0:8) {
    # Simulate purity data with noise
    data[data$Lot == lot &
           data$Time == month * 3, "Purity"] <-
      intercept + slope * month * 3 + rnorm(1, mean = 0, sd = .35)
  }
}

我想拟合随机截距-固定斜率的混合效应模型,用了下面的ggplot2代码却没得到预期结果:

ggplot(data, aes(x = Time, y = Purity)) +
  geom_point(aes(color = as.factor(Lot), shape = as.factor(Lot))) +
  geom_smooth(
    method = "lm",
    formula = y ~ x  + (1 | Lot), data = data,
    se = FALSE,
    size = 0.5,
    show.legend = FALSE
  ) +
  labs(
    title = "Random Intercept and Fixed Slope ",
    x = "month",
    y = "Purity",
    color = "Lot",
    shape = "Lot"
  ) +
  theme_minimal() +
  scale_x_continuous(breaks = c(0, 3, 6, 9, 12, 15, 18, 21, 24))

我期望每个Lot对应一条斜率相同、截距不同的回归线,请问代码哪里出错了?

错误原因及解决方法

你的核心问题是geom_smooth的method = "lm"不支持混合效应模型的公式语法(1 | Lot)——这个随机效应项会被直接忽略,最终只会画出一条全局的普通线性回归线,而非每个Lot单独的回归线。

下面提供两种符合需求的解决方案:

方案1:基于混合效应模型预测绘图(推荐)

先用lme4包拟合标准的随机截距-固定斜率模型,再生成每个Lot的预测值,最后用ggplot绘制回归线:

library(lme4)
library(ggplot2)

# 拟合混合效应模型
model <- lmer(Purity ~ Time + (1 | Lot), data = data)

# 构建包含所有Time和Lot组合的预测数据集
pred_data <- expand.grid(
  Time = unique(data$Time),
  Lot = unique(data$Lot)
)
# 生成预测值
pred_data$Purity_pred <- predict(model, newdata = pred_data)

# 绘图
ggplot(data, aes(x = Time, y = Purity)) +
  geom_point(aes(color = as.factor(Lot), shape = as.factor(Lot))) +
  geom_line(data = pred_data, aes(x = Time, y = Purity_pred, color = as.factor(Lot)), size = 0.5) +
  labs(
    title = "Random Intercept and Fixed Slope",
    x = "Month",
    y = "Purity",
    color = "Lot",
    shape = "Lot"
  ) +
  theme_minimal() +
  scale_x_continuous(breaks = c(0, 3, 6, 9, 12, 15, 18, 21, 24))

方案2:强制全局斜率的分组拟合

如果不想依赖lme4,可以先计算全局线性模型的斜率,再让每个Lot仅拟合截距,从而实现固定斜率、不同截距的效果:

library(ggplot2)

# 计算全局斜率
global_lm <- lm(Purity ~ Time, data = data)
global_slope <- coef(global_lm)[["Time"]]

ggplot(data, aes(x = Time, y = Purity)) +
  geom_point(aes(color = as.factor(Lot), shape = as.factor(Lot))) +
  geom_smooth(
    aes(group = Lot, color = as.factor(Lot)),
    method = "lm",
    formula = y ~ I(x * global_slope) + 1, # 固定斜率,仅拟合截距
    se = FALSE,
    size = 0.5
  ) +
  labs(
    title = "Random Intercept and Fixed Slope",
    x = "Month",
    y = "Purity",
    color = "Lot",
    shape = "Lot"
  ) +
  theme_minimal() +
  scale_x_continuous(breaks = c(0, 3, 6, 9, 12, 15, 18, 21, 24))

说明

  • 方案1严格遵循混合效应模型的统计逻辑,生成的回归线是模型的预测结果,更严谨;
  • 方案2是一种近似实现,适合快速验证可视化效果,结果和混合模型的预测线会略有差异。

内容的提问来源于stack exchange,提问作者Joe the Second

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 22:05:03