Развернуть и связать вложенные столбцы списка - PullRequest
0 голосов
/ 16 марта 2019

Чтобы упростить воспроизводимость, я использую набор данных goats из пакета ResourceSelection, который содержит пространственные данные для используемых (STATUS == 1) и «доступных» (STATUS == 0) GPS-местоположений горных козлов. ID для отдельных (n = 10), а ELEVATION, ... , TASP - атрибуты точек.

library(tidyverse)
library(broom)
library(ResourceSelection)
head(goats)
  STATUS ID ELEVATION   SLOPE       ET   ASPECT       HLI      TASP
1      1  1       651 38.5216  35.3553 243.1131 0.9175926 0.9468804
2      1  1       660 39.6927  70.7107 270.0000 0.8840338 0.6986293
3      1  1       316 20.5477  50.0000 279.2110 0.7131423 0.5749115
4      1  1       334 34.0783  35.3553 266.1859 0.8643775 0.7447368
5      1  1       454 41.6187  25.0000 258.3106 0.9349181 0.8292587
6      1  1       343 28.4694 103.0776 237.0426 0.8254866 0.9756112

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

#Function for model one
Mod1 <- function(df) {
  glm(STATUS ~ SLOPE + I(SLOPE^2) + ASPECT + ET, data = df)
}

#Function for model two without ET
Mod2 <- function(df) {
  glm(STATUS ~ SLOPE + I(SLOPE^2) + ASPECT, data = df)
  }


#Fit the models
ModelFits <- goats %>%
  group_by(ID) %>% 
  nest() %>% 
  mutate(fits1 = map(data, Mod1),
         fits2 = map(data, Mod2),
         glanced1 = map(fits1, glance),
            #Create a dummy column to index model one
            glanced1 = map(glanced1, ~ .x %>% mutate(Mod = "One")),
         glanced2 = map(fits2, glance),
            #Create a dummy column to index model two
            glanced2 = map(glanced2, ~ .x %>% mutate(Mod = "Two")))

Для каждого человека я хотел бы сделать выбор модели и определить, какая модель (Mod1 или Mod2) получила более высокий рейтинг согласно AIC. С этой целью я пытаюсь unnest два списка-столбца, созданных с помощью glance, и связать их в отдельный фрейм данных. Я могу сделать это вручную для glanced1 и glanced2, как показано ниже, что создает желаемый результат, суммирующий все отдельные модели в одном кадре данных.

Mod1DF <- ModelFits %>% 
  unnest(glanced1) %>% 
  #Remove other list-columns
  select(-c(data,  fits1, fits2, glanced2)) %>% 
  as.data.frame()

Mod2DF <- ModelFits %>% 
  unnest(glanced2) %>% 
  #Remove other list-columns
  select(-c(data,  fits1, fits2, glanced1)) %>% 
  as.data.frame()  


Dat <- bind_rows(Mod1DF, Mod2DF)
#There is one model for each model type and individual in `Dat`
table(Dat$Mod)
One Two 
 10  10

Однако для многих моделей такой подход громоздок. Я пробовал другие подходы, но результат связывает столбцы, а не строки (т. Е. Расширяется, а не длиннее), например:

Dat <- ModelFits %>% 
  select(-c(data, fits1, fits2)) %>% 
  unnest(glanced1, glanced2) %>% 
  bind_rows() %>% 
  as.data.frame()

Как мне достичь желаемых результатов с менее громоздким подходом?

1 Ответ

1 голос
/ 16 марта 2019

Вы можете использовать gather, чтобы преобразовать ваш широкий массив данных в длинный формат:

ModelFits %>%
  gather("model", "fit", glanced1:glanced2) %>%
  unnest(fit) %>%
  select(ID, null.deviance:Mod)

Но более простой путь может заключаться в итерации по списку моделей:

map_df(list("One" = Mod1, "Two" = Mod2), function(mod) {
  goats %>%
    group_by(ID) %>%
    nest() %>%
    mutate(fits = map(data, mod), glanced = map(fits, glance)) %>%
    select(ID, glanced) %>%
    unnest()
}, .id = "Mod")
...