Применение различных начальных параметров к модели с помощью purrr :: map в dplyr :: mutate

Пытаюсь ответить на чей-то вопрос в списке рассылки ggplot2, и я не могу его понять: https://groups.google.com/forum/#!topic/ggplot2/YgCqQX8JbPM

OP хочет применить различные параметры запуска к подмножествам своих данных для модели nls. Я думал, что ему следует прочитать dplyr и purrr, но после нескольких часов попыток я наткнулся на стену. Не уверен, что это ошибка или мой недостаток опыта работы с мурлыканьем.

library(tidyverse)

# input dataset
df <- data.frame(Group = c(rep("A", 7), rep("B", 7), rep("C", 7)),
                 Time = c(rep(c(1:7), 3)),
                 Result = c(100, 96.9, 85.1, 62.0, 30.7, 15.2, 9.6, 
                            10.2, 14.8, 32.26, 45.85, 56.25, 70.1, 100,
                            100, 55.61, 3.26, -4.77, -7.21, -3.2, -5.6))

# nest the datasets for computing models
df_p <-
df %>%
group_by(Group) %>%
nest

# add model parameters as rows/columns
df_p$starta = c(-3, 4,-3)
df_p$startb = c(85, 85, 85)
df_p$startc = c(4, 4, 4)
df_p$startd = c(10,10,10)

# compute models using nls
df_p %>%
mutate(model2 = map(data, ~nls(Result ~ a+(b-a)/(1+(Time/c)^d), data = ., start = c(a = starta, b = startb, c = startc, d = startd)))
        )

#Error in mutate_impl(.data, dots) : 
#  parameters without starting value in 'data': a, b, d

Похоже, это связано с этой ошибкой, но это уже исправлено ... https://github.com/hadley/dplyr/issues/1447

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


person bhive01    schedule 29.12.2016    source источник


Ответы (2)


Данные примера сложны, потому что у Группы B время в основном указано в обратном направлении. Найти для этого хорошие начальные значения - не моя проблема. Итак, я составил новые данные для группы B. Вот как настроить фрейм данных, чтобы применить nls() внутри map2().


library(tidyverse)

df <- data.frame(Group = c(rep("A", 7), rep("B", 7), rep("C", 7)),
                 Time = c(rep(c(1:7), 3)),
                 Result = c(100, 96.9, 85.1, 62.0, 30.7, 15.2, 9.6, 
                            ## I replaced these values!!
                            ## Group B initial values are NOT MY PROBLEM
                            105, 90, 82, 55, 40, 23, 7, 
                            100, 55.61, 3.26, -4.77, -7.21, -3.2, -5.6))

## ggplot(df, aes(x = Time, y = Result, group = Group)) + geom_line()

df_p <-
  df %>%
  group_by(Group) %>%
  nest() %>% 
  ## init vals are all the same, but this shows how to make them different
  mutate(start = list(
    list(a = -3, b = 85, c = 4, d = 10),
    list(a = -3, b = 85, c = 4, d = 10),
    list(a = -3, b = 85, c = 4, d = 10)
  )

)

df_p %>%
  mutate(model2 = map2(data, start,
                       ~ nls(Result ~ a+(b-a)/(1+(Time/c)^d),
                             data = .x, start = .y)))
#> # A tibble: 3 × 4
#>    Group             data      start    model2
#>   <fctr>           <list>     <list>    <list>
#> 1      A <tibble [7 × 2]> <list [4]> <S3: nls>
#> 2      B <tibble [7 × 2]> <list [4]> <S3: nls>
#> 3      C <tibble [7 × 2]> <list [4]> <S3: nls>
person jennybryan    schedule 29.12.2016
comment
Действительно, ни ваша, ни моя проблема с самими параметрами. Возникает вопрос, как вы ссылаетесь на столбцы списка как .x и .y. Как вы узнали об этом? Почему не .data и .start? - person bhive01; 29.12.2016
comment
Когда вы используете ярлык формулы purrr для определения отображаемой функции, заполнителями всегда являются .x (map_*() варианты) или .x и .y (map2_*() варианты. Это, например, в purrr::map() файле справки. - person jennybryan; 29.12.2016
comment
Если вы используете pmap(), вы можете полагаться на имена аргументов в своей пользовательской функции. В этом случае ярлык формулы больше не актуален. Вы можете определить myfun <- function(.data, .start) nls(Result ~ a+(b-a)/(1+(Time/c)^d), data = .data, start = .start). Затем убедитесь, что вы используете эти точные имена переменных и только те переменные во фрейме данных, которые вы планируете использовать в качестве основных входных данных для pmap(select(df, .data, .start), myfun). - person jennybryan; 29.12.2016

Не удалось найти набор параметров для создания моделей, которые вы настроили, но я думаю, что это то, что вы можете сделать при настройке процесса подгонки модели; В основном вы можете обернуть все параметры starta, startb .. etc в данные, а также столбцы Result и Time, а затем вы можете получить доступ к параметрам с помощью .$, обратите внимание, что в этом случае вам понадобится функция unique, чтобы выбрать одно значение, поскольку значение было передано при распаковке. Используя простую формулу модели, a + b*Time, она создает модели в столбце model2, вы можете следовать по этому пути и настроить начальные параметры, переданные в nls, чтобы они соответствовали более сложной формуле, как вы указали:

library(tidyverse)

df_p %>% unnest %>% group_by(Group) %>% nest %>%
         mutate(model2 = map(data, ~nls(Result ~ a + b*Time, data = ., 
                                        start = c(a = unique(.$starta), 
                                                  b = unique(.$startb))
                                       )
                             )
               )

# A tibble: 3 × 3
#   Group             data    model2
#  <fctr>           <list>    <list>
#1      A <tibble [7 × 6]> <S3: nls>
#2      B <tibble [7 × 6]> <S3: nls>
#3      C <tibble [7 × 6]> <S3: nls>
person Psidom    schedule 29.12.2016