代码之家  ›  专栏  ›  技术社区  ›  Lyndz

从geom_smooth()中提取多条趋势线的斜率

  •  5
  • Lyndz  · 技术社区  · 6 年前

    我试图用ggplot绘制一个时间序列中的多条趋势线(每十年一次)。

    数据如下:

    dat <- structure(list(YY = 1961:2010, a = c(98L, 76L, 83L, 89L, 120L, 
    107L, 83L, 83L, 92L, 104L, 98L, 91L, 81L, 69L, 86L, 76L, 85L, 
    86L, 70L, 81L, 77L, 89L, 60L, 80L, 94L, 66L, 77L, 85L, 77L, 80L, 
    79L, 79L, 65L, 70L, 80L, 87L, 84L, 67L, 106L, 129L, 95L, 79L, 
    67L, 105L, 118L, 85L, 86L, 103L, 97L, 106L)), .Names = c("YY", 
    "a"), row.names = c(NA, -50L), class = "data.frame")
    

    剧本如下:

    p <- ggplot(dat, aes(x = YY))
    p <- p + geom_line(aes(y=a),colour="blue",lwd=1)
    p <- p + geom_point(aes(y=a),colour="blue",size=2)
    
    p <- p + theme(panel.background=element_rect(fill="white"),
             plot.margin = unit(c(0.5,0.5,0.5,0.5),"cm"),
             panel.border=element_rect(colour="black",fill=NA,size=1),
             axis.line.x=element_line(colour="black"),
             axis.line.y=element_line(colour="black"),
             axis.text=element_text(size=15,colour="black",family="serif"),
             axis.title=element_text(size=15,colour="black",family="serif"),
             legend.position = "top")
    
    p <- p + scale_x_discrete(limits = c(seq(1961,2010,5)),expand=c(0,0))
    
    p <- p + geom_smooth(data=dat[1:10,],aes(x=YY,y=a),method="lm",se=FALSE,color="black",formula=y~x,linetype="dashed")
    
    p <- p + geom_smooth(data=dat[11:20,],aes(x=YY,y=a),method="lm",se=FALSE,color="black",formula=y~x,linetype="dashed")
    
    p <- p + geom_smooth(data=dat[21:30,],aes(x=YY,y=a),method="lm",se=FALSE,color="black",formula=y~x,linetype="dashed")
    
    p <- p + geom_smooth(data=dat[31:40,],aes(x=YY,y=a),method="lm",se=FALSE,color="black",formula=y~x,linetype="dashed")
    
    p <- p + geom_smooth(data=dat[41:50,],aes(x=YY,y=a),method="lm",se=FALSE,color="black",formula=y~x,linetype="dashed")
    
    p <- p + labs(x="Year",y="Number of Days")
    outImg <- paste0("test",".png")
    ggsave(outImg,p,width=8,height=5)
    

    这是生成的图像:

    Output image

    我想要的/问题

    1. 我想提取斜率并将其添加到图中的趋势线上。如何从geom_smooth()中提取每条线的坡度?

    2. 目前,我正在逐一绘制趋势线。我想知道是否有一个有效的方法来做这个与可调的时间窗口。例如,我想每5年绘制一次趋势线。在上图中,时间窗口是10。

    3. 假设,我只想绘制有效的趋势线(即p-value<0.05,空:没有趋势或斜率等于0),是否可以用geom_smooth()实现?

    我很感激你的帮助。

    1 回复  |  直到 6 年前
        1
  •  5
  •   dpseidel    6 年前

    因此,在将数据导入ggplot2之前,最好先处理这些任务,但使用tidyverse中的其他一些包,这些任务都变得相当容易。

    从问题1和2开始:

    虽然ggplot2可以绘制回归线,但要提取估计的坡度系数,需要使用 lm() 明确反对。使用 group_by() mutate() 你可以添加一个分组变量(下面的代码是针对5年的组做的),然后计算和提取斜率估计值到你现有的数据帧中的列中。然后,可以使用 geom_text() 打电话来。我以一种快速而肮脏的方式完成了下面的工作(将每个标签放置在它们回归的x和y值的平均值处),但是您可以在数据帧中指定它们的确切位置。

    分组变量和数据准备也让问题2变得轻而易举:既然数据框中显式地包含了分组变量,就不需要逐个绘制, geom_smooth() 接受 group 唯美。

    此外,要回答问题3,您可以从lm对象的摘要中提取pvalue,并仅筛选出那些对您所关心的级别具有重要意义的对象。如果现在将完整的数据帧传递给 几何平滑() 几何文本() 你会得到你想要的情节!

    library(tidyverse)
    
     # set up our base plot
     p <- ggplot(dat, aes(x = YY, y = a)) +
      geom_line(colour = "blue", lwd = 1) +
      geom_point(colour = "blue", size = 2) +
      theme(
        panel.background = element_rect(fill = "white"),
        plot.margin = unit(c(0.5, 0.5, 0.5, 0.5), "cm"),
        panel.border = element_rect(colour = "black", fill = NA, size = 1),
        axis.line.x = element_line(colour = "black"),
        axis.line.y = element_line(colour = "black"),
        axis.text = element_text(size = 15, colour = "black", family = "serif"),
        axis.title = element_text(size = 15, colour = "black", family = "serif"),
        legend.position = "top"
      ) +
      scale_x_discrete(limits = c(seq(1961, 2010, 5)), expand = c(0, 0))
    
    # add a grouping variable (or many!)
     prep5 <- dat %>%
      mutate(group5 = rep(1:10, each = 5)) %>%
      group_by(group5) %>%
      mutate(
        slope = round(lm(YY ~ a)$coefficients[2], 2),
        significance = summary(lm(YY ~ a))$coefficients[2, 4],
        x = mean(YY),   # x coordinate for slope label
        y = mean(a)     # y coordinate for slope label
      ) %>%
      filter(significance < .2)   # only keep those with a pvalue < .2 
    
    p + geom_smooth(
      data = prep5, aes(x = YY, y = a, group = group5),  # grouping variable does the plots for us!
      method = "lm", se = FALSE, color = "black",
      formula = y ~ x, linetype = "dashed"
    ) +
      geom_text(
        data = prep5, aes(x = x, y = y, label = slope),
        nudge_y = 12, nudge_x = -1
      )
    

    现在,您可能需要比我在这里更小心地指定文本标签的位置。我用手段 nudge_* 争论 几何文本() 做一个简单的例子,但要记住,因为这些值显式地映射到x和y坐标,你有完全的控制!

    于2018-07-16由 reprex package (第0.2.0版)。