гнездо (), а затем map () для линейных моделей - PullRequest
1 голос
/ 17 июня 2019

Мои данные выглядят так:

#>   group.name x y
#> 1          a 1 2
#> 2          a 2 4
#> 3          a 3 6
#> 4          b 1 4
#> 5          b 2 3
#> 6          b 3 2
#> 7          c 1 2
#> 8          c 2 5
#> 9          c 3 8
df <- data.frame(stringsAsFactors=FALSE,
   group.name = c("a", "a", "a", "b", "b", "b", "c", "c", "c"),
            x = c(1, 2, 3, 1, 2, 3, 1, 2, 3),
            y = c(2, 4, 6, 4, 3, 2, 2, 5, 8)
)

Я пытаюсь запустить линейную модель для каждого 'group.name', поэтому я попробовал следующий код:

  1. group_by имя_группы
  2. создать вложенную функцию df
  3. map() lm для вложенной функции df.

НоЯ получаю ошибку.Может кто-нибудь объяснить, что я делаю не так?Спасибо.

library(tidyverse) 
models <- df %>%
  group_by(group.name) %>%
  nest() %>% 
  map(~ lm(y ~ x, data = .))


#> Error in eval(predvars, data, env): invalid 'envir' argument of type 'character'
models
#> Error in eval(expr, envir, enclos): object 'models' not found

Ответы [ 5 ]

2 голосов
/ 17 июня 2019

Данные, переданные map, не соответствуют ожидаемому формату. Попробуйте использовать group_split

library(dplyr)
library(purrr)

df %>%
  group_split(group.name,keep = FALSE) %>%
  map(~lm(y ~ x, data = .))


#[[1]]

#Call:
#lm(formula = y ~ x, data = .)

#Coefficients:
#(Intercept)            x  
#          0            2  


#[[2]]

#Call:
#lm(formula = y ~ x, data = .)

#Coefficients:
#(Intercept)            x  
#          5           -1  


#[[3]]

#Call:
#lm(formula = y ~ x, data = .)

#Coefficients:
#(Intercept)            x  
#         -1            3  
1 голос
/ 17 июня 2019

Подобные проблемы возникают из-за того, что существует пакет tidyverse broom.

require(broom)
df %>% 
    group_by(group.name) %>%
    do(tidy(lm(data = ., formula = y ~ x)))

df %>% 
    group_by(group.name) %>%
    do(glance(lm(data = ., formula = y ~ x)))

Первый блок кода содержит фрейм данных наилучшего соответствияпараметры.

# A tibble: 6 x 6
# Groups:   group.name [3]
  group.name term        estimate std.error  statistic    p.value
  <chr>      <chr>          <dbl>     <dbl>      <dbl>      <dbl>
1 a          (Intercept)       0   0.        NaN       NaN       
2 a          x                 2   0.        Inf         0.      
3 b          (Intercept)       5.  1.02e-15    4.91e15   1.30e-16
4 b          x                -1.  4.71e-16   -2.12e15   3.00e-16
5 c          (Intercept)      -1.  1.36e-15   -7.37e14   8.64e-16
6 c          x                 3.  6.28e-16    4.78e15   1.33e-16

Второй блок кода выводит фрейм данных сводной статистики из операции подбора.

Ключ в том, что результаты всехПодгонки отформатированы в удобной структуре фрейма данных.Не в списках, именованных списках или объектах S3 или S4 с произвольной структурой.Последующее манипулирование результатами моделирования может использовать уже знакомые инструменты обратного хода, как только модели будут в формате данных.Если вы делаете много такого рода вещей, вы можете взглянуть на метлу.(Недостатками было бы введение другой зависимости, и если у вас уже есть много кода, написанного для анализа структур списков подбора моделей, вам придется заново их настроить.)

1 голос
/ 17 июня 2019

Очень похожее решение, которое я нахожу немного более интуитивным, заключается в том, чтобы хранить модели в кадре данных до тех пор, пока вы не захотите извлечь их.

models_df <- df %>%
  nest(-group.name) %>% 
  mutate(models = map(data, ~lm(y ~ x, data = .)))

, который выглядит как:

# A tibble: 3 x 3
  group.name data             models
  <chr>      <list>           <list>
1 a          <tibble [3 × 2]> <lm>  
2 b          <tibble [3 × 2]> <lm>  
3 c          <tibble [3 × 2]> <lm>  

Тогда, если вы хотите извлечь модель, вы делаете:

models_df %>% 
  pull(models)

, который дает вам список моделей:

[[1]]

Call:
lm(formula = y ~ x, data = .)

Coefficients:
(Intercept)            x  
          0            2  

[[2]]

Call:
lm(formula = y ~ x, data = .)

Coefficients:
(Intercept)            x  
          5           -1  

[[3]]

Call:
lm(formula = y ~ x, data = .)

Coefficients:
(Intercept)            x  
         -1            3  
1 голос
/ 17 июня 2019

Попробуйте следующее:

df %>% group_by(group.name) %>% summarise(mod=list(lm(y~x))) ->df1
df1$mod[[1]]

#Call:
#lm(formula = y ~ x)

#Coefficients:
#(Intercept)            x  
#          0            2  
0 голосов
/ 17 июня 2019

В большинстве случаев, и особенно в этом простом случае, включение переменной группировки в вашу модель будет намного проще.

md <- lm(y ~ x*group.name - 1, data = df) 
summary(md) 

Добавление -1 удаляет перехват, который затем будет задан переменной group.namea, group.nameb и так далее.Резюме

lm(formula = y ~ x * group.name - 1, data = df)

Residuals:
         1          2          3          4          5          6          7          8          9 
 1.052e-15 -2.104e-15  1.052e-15  4.019e-16 -8.038e-16  4.019e-16 -2.313e-17  4.626e-17 -2.313e-17 

Coefficients:
                Estimate Std. Error    t value Pr(>|t|)    
x              2.000e+00  1.126e-15  1.776e+15   <2e-16 ***
group.namea   -1.820e-15  2.433e-15 -7.480e-01    0.509    
group.nameb    5.000e+00  2.433e-15  2.055e+15   <2e-16 ***
group.namec   -1.000e+00  2.433e-15 -4.110e+14   <2e-16 ***
x:group.nameb -3.000e+00  1.593e-15 -1.883e+15   <2e-16 ***
x:group.namec  1.000e+00  1.593e-15  6.278e+14   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.593e-15 on 3 degrees of freedom
Multiple R-squared:      1, Adjusted R-squared:      1 
F-statistic: 1.169e+31 on 6 and 3 DF,  p-value: < 2.2e-16

дает все 3 модели.У нас есть

  • Модель для группы a: y = -1.82*10^-15 + 2 * x
  • Модель для группы b: y = 10 + (2 - 3) * x = 10 - 1 x
  • Модель для группы c: y = -1 + (2 + 1) *x = -1 + 3 * x
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...