【问题标题】:Is it possible to plot the smooth components of a gam fit with ggplot2?是否可以使用 ggplot2 绘制 gam 拟合的平滑分量?
【发布时间】:2013-11-13 03:34:28
【问题描述】:

我正在使用mgcv 包中的gam 拟合模型并将结果存储在model 中,到目前为止,我一直在使用plot(model) 查看平滑组件。我最近开始使用 ggplot2 并喜欢它的输出。所以我想知道,是否可以使用 ggplot2 绘制这些图?

这是一个例子:

x1 = rnorm(1000)
x2 = rnorm(1000)
n = rpois(1000, exp(x1) + x2^2)

model = gam(n ~ s(x1, k=10) + s(x2, k=20), family="poisson")
plot(model, rug=FALSE, select=1)
plot(model, rug=FALSE, select=2)

我对@9​​87654326@ 和s(x2, k=20) 不合适。

部分回答:

我深入研究了plot.gammgcv:::plot.mgcv.smooth 并构建了自己的函数,该函数从平滑分量中提取预测效果和标准误差。它不能处理plot.gam 的所有选项和情况,所以我只认为它是部分解决方案,但它对我来说效果很好。

EvaluateSmooths = function(model, select=NULL, x=NULL, n=100) {
  if (is.null(select)) {
    select = 1:length(model$smooth)
  }
  do.call(rbind, lapply(select, function(i) {
    smooth = model$smooth[[i]]
    data = model$model

    if (is.null(x)) {
      min = min(data[smooth$term])
      max = max(data[smooth$term])
      x = seq(min, max, length=n)
    }
    if (smooth$by == "NA") {
      by.level = "NA"
    } else {
      by.level = smooth$by.level
    }
    range = data.frame(x=x, by=by.level)
    names(range) = c(smooth$term, smooth$by)

    mat = PredictMat(smooth, range)
    par = smooth$first.para:smooth$last.para

    y = mat %*% model$coefficients[par]

    se = sqrt(rowSums(
      (mat %*% model$Vp[par, par, drop = FALSE]) * mat
    ))

    return(data.frame(
      label=smooth$label
      , x.var=smooth$term
      , x.val=x
      , by.var=smooth$by
      , by.val=by.level
      , value = y
      , se = se
    ))
  }))
}

这会返回一个带有平滑分量的“熔化”数据框,因此现在可以在上面的示例中使用ggplot

smooths = EvaluateSmooths(model)

ggplot(smooths, aes(x.val, value)) + 
  geom_line() + 
  geom_line(aes(y=value + 2*se), linetype="dashed") + 
  geom_line(aes(y=value - 2*se), linetype="dashed") + 
  facet_grid(. ~ x.var)

如果有人知道在一般情况下允许这样做的软件包,我将不胜感激。

【问题讨论】:

  • ggplot 将predict 用于geom_smooth,所以只需使用method='gam'
  • 据我了解 geom_smooth 它显示的是适合而不是平滑的条款。所以我认为这不是解决方案。
  • 链接到数据集(只需引用来自 mgcv 的示例作为起点和您尝试复制的图),我们可以(可能)向您展示如何。

标签: r ggplot2 gam mgcv


【解决方案1】:

您可以将 visreg 包与 plyr 包结合使用。 visreg 基本上可以绘制任何可以使用 predict() 的模型。

library(mgcv)
library(visreg)
library(plyr)
library(ggplot2)

# Estimating gam model:
x1 = rnorm(1000)
x2 = rnorm(1000)
n = rpois(1000, exp(x1) + x2^2)
model = gam(n ~ s(x1, k=10) + s(x2, k=20), family="poisson")

# use plot = FALSE to get plot data from visreg without plotting
plotdata <- visreg(model, type = "contrast", plot = FALSE)

# The output from visreg is a list of the same length as the number of 'x' variables,
#   so we use ldply to pick the objects we want from the each list part and make a dataframe: 
smooths <- ldply(plotdata, function(part)   
  data.frame(Variable = part$meta$x, 
             x=part$fit[[part$meta$x]], 
             smooth=part$fit$visregFit, 
             lower=part$fit$visregLwr, 
             upper=part$fit$visregUpr))

# The ggplot:
ggplot(smooths, aes(x, smooth)) + geom_line() +
  geom_line(aes(y=lower), linetype="dashed") + 
  geom_line(aes(y=upper), linetype="dashed") + 
  facet_grid(. ~ Variable, scales = "free_x")

我们可以把整个事情放到一个函数中,并添加一个选项来显示模型的残差(res = TRUE):

ggplot.model <- function(model, type="conditional", res=FALSE, 
                       col.line="#7fc97f", col.point="#beaed4", size.line=1, size.point=1) {
  require(visreg)
  require(plyr)
  plotdata <- visreg(model, type = type, plot = FALSE)
  smooths <- ldply(plotdata, function(part)   
    data.frame(Variable = part$meta$x, 
             x=part$fit[[part$meta$x]], 
             smooth=part$fit$visregFit, 
             lower=part$fit$visregLwr, 
             upper=part$fit$visregUpr))
  residuals <- ldply(plotdata, function(part)
    data.frame(Variable = part$meta$x, 
               x=part$res[[part$meta$x]], 
               y=part$res$visregRes))
  if (res)
    ggplot(smooths, aes(x, smooth)) + geom_line(col=col.line, size=size.line) +
      geom_line(aes(y=lower), linetype="dashed", col=col.line, size=size.line) +
      geom_line(aes(y=upper), linetype="dashed", col=col.line, size=size.line) +
      geom_point(data = residuals, aes(x, y), col=col.point, size=size.point) +
      facet_grid(. ~ Variable, scales = "free_x")
  else
    ggplot(smooths, aes(x, smooth)) + geom_line(col=col.line, size=size.line) +
      geom_line(aes(y=lower), linetype="dashed", col=col.line, size=size.line) +
      geom_line(aes(y=upper), linetype="dashed", col=col.line, size=size.line) +
      facet_grid(. ~ Variable, scales = "free_x")
  }

ggplot.model(model)
ggplot.model(model, res=TRUE)

颜色取自http://colorbrewer2.org/

【讨论】:

  • 您现在可以使用plot=FALSE 参数visreg 返回绘图数据而不显示任何内容,而不是绘图到临时文件。但是我认为返回的对象已经与您假设的不同。
  • 帖子可能需要更新。如果我运行上面的代码,对象smooths 将返回空,因此plyr::ldply()call 有问题。
  • @pat-s 谢谢,你是对的。该帖子现已更新,应该可以使用。
  • 如果我有很多“x”对象,我如何将这个数字分成不同的行和列。
【解决方案2】:

仅供参考,visreg 可以直接输出gg 对象:

visreg(model, "x1", gg=TRUE)

【讨论】:

    【解决方案3】:

    已更新以允许用户选择绘制哪些变量。 将 'residuals' 术语更改为 'res_data' 以避免与 residuals 函数发生冲突。

    ggplot.model <- function(model, type="conditional", res=FALSE, 
                           col.line="#7fc97f", col.point="#beaed4", size.line=1, size.point=1, no_col = NULL,
                           what = "all") {
      require(visreg)
      require(plyr)
      
      plotdata <- visreg(model, type = type, plot = FALSE)
      smooths <- ldply(plotdata, function(part)   
        data.frame(Variable = part$meta$x, 
                 x=part$fit[[part$meta$x]], 
                 smooth=part$fit$visregFit, 
                 lower=part$fit$visregLwr, 
                 upper=part$fit$visregUpr))
      res_data <- ldply(plotdata, function(part)
        data.frame(Variable = part$meta$x, 
                   x=part$res[[part$meta$x]], 
                   y=part$res$visregRes))
      
       if (what != "all") {
        smooths <- smooths %>%
          filter(lapply(Variable,as.character)%in% what)
        res_data <- res_data%>%
          filter(lapply(Variable,as.character)%in% what)
       }
      
      
      if (res)
        ggplot(smooths, aes(x, smooth)) + geom_line(col=col.line, size=size.line) +
          geom_line(aes(y=lower), linetype="dashed", col=col.line, size=size.line) +
          geom_line(aes(y=upper), linetype="dashed", col=col.line, size=size.line) +
          geom_point(data = res_data, aes(x, y), col=col.point, size=size.point) +
          facet_wrap(. ~ Variable, scales = "free_x", ncol = no_col) + theme_bw()
      else
        ggplot(smooths, aes(x, smooth)) + geom_line(col=col.line, size=size.line) +
          geom_line(aes(y=lower), linetype="dashed", col=col.line, size=size.line) +
          geom_line(aes(y=upper), linetype="dashed", col=col.line, size=size.line) +
          facet_wrap(. ~ Variable, scales = "free_x", ncol=no_col)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      • 1970-01-01
      • 2017-04-25
      相关资源
      最近更新 更多