【问题标题】:Not getting a smooth curve using ggplot2使用ggplot2没有得到平滑的曲线
【发布时间】:2020-05-09 20:30:39
【问题描述】:

我正在尝试使用 lme4 包拟合混合效果模型。不幸的是,我无法分享我正在使用的数据。我也找不到与我的问题相关的玩具数据集。所以在这里我展示了我到目前为止所遵循的步骤:

首先我将数据的整体趋势绘制如下:

p21 <- ggplot(data = sub_data, aes(x = age_cent, y = y))
p21+ geom_point() + geom_smooth()

基于此,数据中似乎存在某种非线性趋势。因此,我尝试如下拟合二次模型:

sub_data$age_cent=sub_data$age-mean((sub_data)$age)
sub_data$age_centsqr=(sub_data$age-mean((sub_data)$age))^2

m1= lmer(y ~ 1 + age_cent +  age_centsqr +(1 | id) , sub_data, REML = TRUE)

在上面的模型中,我只包含了一个随机截距,因为我没有足够的数据来包含随机斜率和截距。然后我在人口水平上提取了这些模型的预测如下:

pred1=predict(m1,re.form=NA)

接下来我将这些预测与这样的平滑二次函数一起绘制

    p21+ geom_point() + geom_smooth(method = "lm", formula = y ~ I(x) + I(x^2)
 ,col="red")+geom_line(aes(y=pred1,group = id) ,col="blue", lwd = 0.5)

在上图中,曲线对应的预测不平滑。任何人都可以帮助我找出原因吗? 我在这里做错了什么?

更新: 正如 eipi10 指出的那样,这可能是由于为不同的人拟合了不同的曲线。

但是当我使用 lme4 包中的玩具数据集尝试相同的事情时,我得到了每个人的相同曲线,如下所示:

m1 <- lmer(Reaction ~ 1+I(Days) + (1+ Days| Subject) , data = sleepstudy)



pred1new1=predict(m1,re.form=NA)

p21 <- ggplot(data = sleepstudy, aes(x = Days, y = Reaction))
p21+ geom_point() + geom_smooth()
p21+ geom_point() + geom_smooth()+ geom_line(aes(y=pred1new1,group = Subject) ,col="red", lwd = 0.5)

导致不同结果的原因可能是什么?这是由于数据不平衡造成的吗? 我使用的数据是在 3 个时间步骤中收集的,有些人在 3 个时间步骤中都没有。但是玩具数据集是一个平衡的数据集。

谢谢

【问题讨论】:

  • predict 函数返回每个数据行的预测。看起来您对id 的每个级别都有预测,并且您在geom_line 中添加了group=id 作为美学,因此您将获得每个id 的单独行。
  • 另外,看起来pred1 是一个预测向量。我不知道这是否会导致任何问题,但总的来说,将预测包含在传递给ggplot(在这种情况下为sub_data)的数据框中会更安全,这样您就可以确定其中的值之间的关系predsub_data 的行保持一致。
  • @eipi10 感谢您的建议。这可能是由于数据不平衡造成的吗?请参考更新后的问题,我在其中包含一个使用玩具数据集的情节。
  • 您需要一个不平衡的数据集和一个非线性(例如多项式)模型才能看到这种效果。有机会我会举一个例子。您应该能够通过使用newdata=expand.grid(levels(group),unique(x_values))) 填充预测框架中的缺失值来获得更漂亮的图表。
  • @BenBolker 如果您能举一些例子,那就太好了。谢谢 。您还可以解释您将哪个变量视为 x_values 吗?是时间相关的变量吗?

标签: r ggplot2 lme4


【解决方案1】:

tl;dr 使用 expand.grid() 或类似的东西为每个组生成一个平衡/均匀间隔的样本(如果您有一个强非线性曲线,您可能希望生成一个更大/更精细x 值的间隔集比原始数据中的值)

您还可以查看 sjPlot 包,它会自动执行很多此类操作...

您需要一个不平衡的数据集和一个非线性(例如多项式)模型才能让固定效果看到这种效果。

  • 如果模型是线性的,那么您不会注意到缺失值,因为 geom_line() 完成的线性插值工作完美
  • 如果数据是平衡的,那么线性插值就不会奇怪地填补空白

生成具有二次效应和不平衡数据集的示例;拟合模型

library(lme4)
set.seed(101)
dd <- expand.grid(id=factor(1:10),x=1:10)
dd$y <- simulate(~poly(x,2)+(poly(x,2)|id),
                 newdata=dd,
                 family=gaussian,
                 newparams=list(beta=c(0,0,0.1),
                                theta=rep(0.1,6),
                                sigma=1))[[1]]
## subsample randomly (missing values)
dd <- dd[sort(sample(nrow(dd),size=round(0.7*nrow(dd)))),]
m1 <- lmer(y ~ poly(x,2) + (poly(x,2)|id) , data = dd)

天真的预测和情节:

dd$pred1 <- predict(m1,re.form=NA)

library(ggplot2)
p11 <- (ggplot(data = dd, aes(x = x, y = y))
    + geom_point() + geom_smooth(method="lm",formula=y~poly(x,2))
)
p11 + geom_line(aes(y=pred1,group = id) ,col="red", lwd = 0.5)

现在生成一个平衡的数据集。此版本在最小值和最大值之间生成 51 个均匀分布的点 - 如果原始数据不均匀分布,这将很有用。如果您的 x 变量中有 NA 值,请不要忘记 na.rm=TRUE ...

pframe <- with(dd,expand.grid(id=levels(id),x=seq(min(x),max(x),length.out=51)

做出预测,并将它们覆盖在原始图上:

pframe$pred1 <- predict(m1,newdata=pframe,re.form=NA)    
p11 + geom_line(data=pframe,aes(y=pred1,group = id) ,col="red", lwd = 0.5)

【讨论】:

  • 感谢您的澄清。正如我在之前的评论中告诉你的,我的 X 变量是每一波的年龄(时间步长)。我使用年龄,因为时间步长不相等。所以这会给数据带来额外的不平衡。
  • 此外,这项工作的基本目标是:通过在人口水平上绘制预测,确定数据的总体趋势以及该总体趋势是否已被我的线性混合效应模型捕获。从这个角度来看,是否可以告诉我我是否正确使用了 ggplot 包?再次感谢您
  • 似乎是合理的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-23
  • 1970-01-01
  • 1970-01-01
  • 2018-10-16
  • 1970-01-01
  • 2022-12-04
  • 1970-01-01
相关资源
最近更新 更多