построение линии регрессии для каждой записи во вложенном списке - PullRequest
3 голосов
/ 05 апреля 2019

У меня есть пример, который вкладывает данные в список, добавляет линейную модель к каждому столбцу в списке, добавляет коэффициенты регрессии к каждой записи в списке и добавляет 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>

выполнение последних двух строк показывает проблему. Код geom_smooth в plot1 создает 1 фигуру для каждой записи с данными из каждой записи и применяет линию сглаживания к каждой фигуре. Однако goem_abline в plot2 этого не делает. Кажется, что все 3 линии (по одной от каждой записи) нанесены на каждую из трех фигур. Будем очень благодарны за любые предложения о том, как заставить goem_abline вести себя как geom_smooth.

1 Ответ

2 голосов
/ 05 апреля 2019

Функция map, которую вы используете для plot 2, отображает ТОЛЬКО 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')
  )
  ) 
...