为嵌套列表中的每条记录绘制回归线

Posted

技术标签:

【中文标题】为嵌套列表中的每条记录绘制回归线【英文标题】:plotting regression line for each record in a nested list 【发布时间】:2019-08-26 21:47:51 【问题描述】:

我有一个将数据嵌套到列表中的示例,将线性模型添加到列表中的每个小标题,将回归系数添加到列表中的每个记录,并将 2 个不同的 ggplot 对象添加到列表中的每个记录。我想为每条记录在单独的数字上绘制回归线。我可以让 geom_smooth 完全按照我的要求做,但是 geom_abline 似乎为列表中的每个记录添加了一个回归(我的示例有三个记录,因此每个图上有三行而不是每个图所需的单行记录。

library(tidyverse)
library(purrr)
library(broom)
library(ggplot2)

iris_species <- iris %>%  
  group_by(Species) %>%  
  nest()

# build model functions
model <- function(iris) 
  lm(Sepal.Length ~ Sepal.Width, data = iris)


# map models to the tibble
iris_species <- iris_species %>% 
  mutate(model = map(data, model))

iris_species # look at the structure

# add glance and tidy results to list
iris_species <- iris_species %>% 
  mutate(t = map(model, tidy)
         )

# unnest tidy list
iris_species_g <- iris_species %>% 
  unnest(t) %>% 
  select(Species, term, estimate) %>% 
  spread(key = term, value = estimate) %>%
  select(Species, `(Intercept)`, Sepal.Width) 

# pain down a list for species and data
iris_species_list <- iris_species %>% 
  select(Species, data, model)

# join  
iris_species_coeffs <- left_join(iris_species_list, iris_species_g, by = 'Species')

# add figures to list
iris_species_figs <- iris_species_coeffs %>% 
  mutate(plot1 = map(data, ~ ggplot(., aes(x = Sepal.Width, y = Sepal.Length)) +
                       geom_point() + 
                       geom_smooth(se = TRUE, size = 1, color = 'grey')
                     ) 
         ) 

iris_species_figs <- iris_species_figs %>% 
  mutate(plot2 = map(data, ~ ggplot(., aes(x = Sepal.Width, y = Sepal.Length)) +
                      geom_point() +
                      geom_abline(intercept = `(Intercept)`, slope = Sepal.Width, color = 'blue')
                    )
         ) 

iris_species_figs

# make figures
iris_species_figs$plot1 # works as expected

iris_species_figs$plot2 # does not

这是上面代码的最终结果:

# A tibble: 3 x 7
  Species    data              model    `(Intercept)` Sepal.Width plot1    plot2   
  <fct>      <list>            <list>           <dbl>       <dbl> <list>   <list>  
1 setosa     <tibble [50 × 4]> <S3: lm>          2.64       0.690 <S3: gg> <S3: gg>
2 versicolor <tibble [50 × 4]> <S3: lm>          3.54       0.865 <S3: gg> <S3: gg>
3 virginica  <tibble [50 × 4]> <S3: lm>          3.91       0.902 <S3: gg> <S3: gg>

运行最后两行显示问题。 plot1 中的 geom_smooth 代码使用每条记录的数据为每条记录创建一个图形,并将平滑线应用于每个图形。但是,plot2 中的 goem_abline 没有。它似乎在三个数字中的每一个上绘制了所有 3 条线(每条记录中的一条)。任何关于如何让 goem_abline 表现得像 geom_smooth 的建议都会非常受欢迎。

【问题讨论】:

purrrggplot2tidyverse 的一部分,因此您无需再次单独加载它们。 【参考方案1】:

您用于plot 2map 函数仅映射data,对于截距和斜率,它看到一个包含3 个元素的向量。这就是为什么您会在每个图中看到 3 条线。

您必须使用pmap 才能map 您需要用于每个绘图的所有信息/列。

试试这个:

iris_species_figs <- iris_species_figs %>% 
  mutate(plot2 = pmap(list(data,`(Intercept)`,Sepal.Width), 
                      function(a,b,c) ggplot(a, aes(x = Sepal.Width, y = Sepal.Length)) +
                       geom_point() +
                       geom_abline(intercept = b, slope = c, color = 'blue')
  )
  ) 

【讨论】:

完美运行。不过,我很想更好地了解您对 pmap 和函数 (a,b,c) 的使用。我可以看到 feed pmap 是一个列表(每条数据记录、截距和斜率),然后使用这些术语作为 geom_abline 的参数。这是必要的还是为了清楚起见?从表面上看,它看起来像是一种重命名尴尬参数名称的技术,例如(Intercept)。无论如何,我很欣赏答案。我一直觉得地图族的文档有点迟钝。 map2 接受 2 个输入,您可以使用类似 ~ .x +.y 或类似 function(a,b) a+b 的东西。但是,pmap 接受 3+ 个输入,因此您必须使用 function(a,b,c) a+b+c 之类的东西,因为在 .x.y 之后没有任何内容可以使用。正如您所说,您需要创建一个输入列表以作为输入传递给pmap

以上是关于为嵌套列表中的每条记录绘制回归线的主要内容,如果未能解决你的问题,请参考以下文章

根据查询中的每条记录将报告打印为 PDF

如何为mysql中的每条记录检索表中的两条记录

如何为数组中的每条记录设置一个属性的值

使用条件控制源控制报表中的每条记录

如何为数据库表中的每条记录生成一个id?

将比例 z 检验应用于数据框中的每条记录