purrr :: pmap и функция с несколькими условиями

Каждый раз, когда я использую библиотечную функцию purrr pmap() с функцией, которая содержит оператор if с несколькими условиями, оператор if не работает должным образом. Чтобы показать вам, что я имею в виду, вот воспроизводимый пример с использованием набора данных gapminder.

library(tidyverse)
library(gapminder)
library(broom)

# Nest the tibble into separate dataframes for each country-continent combination

by_country <- gapminder %>%
  group_by(country, continent) %>%
  nest()

Теперь я хочу построить модель линейной регрессии для каждого сгруппированного фрейма данных. Загвоздка в том, что я хочу использовать в своей модели другую переменную x в зависимости от страны и континента. Вот моя функция, в которой, как я подозреваю, возникла проблема с оператором if:

# My function
country_model <- function(df, cont, count) {

  if(cont == "Asia" & count == "Afghanistan") { # 2 conditions

    lm(lifeExp ~ year, data = df)

  } else {

    lm(lifeExp ~ pop, data = df)

  }
}

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

by_country2 <- by_country %>%
  mutate(model = pmap(list(data, continent, country), country_model),
         modelsum = map(model, tidy)) %>%
  unnest(modelsum, .drop = TRUE)

by_country2

Мои результаты показывают, что коэффициент для Афганистана равен pop, а не year.

A tibble: 284 × 7
       country continent        term     estimate    std.error  statistic      p.value
        <fctr>    <fctr>       <chr>        <dbl>        <dbl>      <dbl>        <dbl>
1  Afghanistan      Asia (Intercept) 2.834615e+01 2.314395e+00  12.247758 2.410050e-07
2  Afghanistan      Asia         pop 5.771517e-07 1.343425e-07   4.296121 1.570999e-03
3      Albania    Europe (Intercept) 4.963274e+01 1.935933e+00  25.637630 1.871817e-10
4      Albania    Europe         pop 7.286188e-06 7.171585e-07  10.159802 1.374311e-06
5      Algeria    Africa (Intercept) 3.565187e+01 1.632853e+00  21.834099 9.087006e-10
6      Algeria    Africa         pop 1.176242e-06 7.588190e-08  15.500960 2.548769e-08
7       Angola    Africa (Intercept) 2.855043e+01 1.922225e+00  14.852803 3.843692e-08
8       Angola    Africa         pop 1.276860e-06 2.482137e-07   5.144195 4.351004e-04
9    Argentina  Americas (Intercept) 5.323586e+01 3.784907e-01 140.653008 8.102227e-18
10   Argentina  Americas         pop 5.532629e-07 1.282987e-08  43.123018 1.079775e-12
# ... with 274 more rows

Что для меня странно, так это то, что когда я использую только одно условие в своей инструкции if, то кажется, что оно работает отлично:

country_model <- function(df, cont) {

  if(cont == "Asia") { # Only 1 condition

    lm(lifeExp ~ year, data = df)

  } else {

    lm(lifeExp ~ pop, data = df)

  }
}

by_country2 <- by_country %>%
  mutate(model = map2(data, continent, country_model),
         modelsum = map(model, tidy)) %>%
  unnest(modelsum, .drop = TRUE)

by_country2

# A tibble: 284 × 7
       country continent        term      estimate    std.error  statistic      p.value
        <fctr>    <fctr>       <chr>         <dbl>        <dbl>      <dbl>        <dbl>
1  Afghanistan      Asia (Intercept) -5.075343e+02 4.048416e+01 -12.536613 1.934055e-07
2  Afghanistan      Asia        year  2.753287e-01 2.045093e-02  13.462890 9.835213e-08
3      Albania    Europe (Intercept)  4.963274e+01 1.935933e+00  25.637630 1.871817e-10
4      Albania    Europe         pop  7.286188e-06 7.171585e-07  10.159802 1.374311e-06
5      Algeria    Africa (Intercept)  3.565187e+01 1.632853e+00  21.834099 9.087006e-10
6      Algeria    Africa         pop  1.176242e-06 7.588190e-08  15.500960 2.548769e-08
7       Angola    Africa (Intercept)  2.855043e+01 1.922225e+00  14.852803 3.843692e-08
8       Angola    Africa         pop  1.276860e-06 2.482137e-07   5.144195 4.351004e-04
9    Argentina  Americas (Intercept)  5.323586e+01 3.784907e-01 140.653008 8.102227e-18
10   Argentina  Americas         pop  5.532629e-07 1.282987e-08  43.123018 1.079775e-12
# ... with 274 more rows

Я не уверен, связана ли моя проблема с pmap() или с моим оператором if.


person RNB    schedule 24.05.2017    source источник
comment
Что в этом случае является опрятным предметом?   -  person Michael    schedule 24.05.2017
comment
@ Майкл, я не понимаю, о чем вы? Объект by_country? by_country2 объект?   -  person RNB    schedule 24.05.2017
comment
@RNB, замешательство Майкла было вызвано отсутствующим вызовом библиотеки для broom, что приводит к тому, что ваш код показывает ошибку для отсутствующего объекта с именем tidy.   -  person Axeman    schedule 24.05.2017
comment
@Axeman, стреляй! Приношу свои извинения Майклу и благодарю за то, что понял это!   -  person RNB    schedule 24.05.2017


Ответы (1)


Это связано с этой проблемой GitHub.

Похоже, что pmap отправляет через continent и country в виде чисел, что можно подтвердить, поместив оператор печати в вашу функцию.

test_fun <- function(df, cont, xx) {
  print(paste(cont, xx))
}

temp <-by_country %>%
  mutate(model = pmap(list(data, continent, country), test_fun))

Печать:

[1] "3 1"
[1] "4 2"
[1] "1 3"
[1] "1 4"
[1] "2 5"
[1] "5 6"
[1] "4 7"
[1] "3 8"
[1] "3 9"
etc

Этого не происходит в map2, поэтому ваша вторая попытка сработает.

Принуждение к персонажу решает проблему:

by_country %>%
  mutate(model = pmap(list(data, as.character(continent), as.character(country)), country_model),
         modelsum = map(model, broom::tidy)) %>%
  unnest(modelsum, .drop = TRUE)
# A tibble: 284 x 7
       country continent        term      estimate    std.error  statistic      p.value
        <fctr>    <fctr>       <chr>         <dbl>        <dbl>      <dbl>        <dbl>
 1 Afghanistan      Asia (Intercept) -5.075343e+02 4.048416e+01 -12.536613 1.934055e-07
 2 Afghanistan      Asia        year  2.753287e-01 2.045093e-02  13.462890 9.835213e-08
 3     Albania    Europe (Intercept)  4.963274e+01 1.935933e+00  25.637630 1.871817e-10
 4     Albania    Europe         pop  7.286188e-06 7.171585e-07  10.159802 1.374311e-06
 5     Algeria    Africa (Intercept)  3.565187e+01 1.632853e+00  21.834099 9.087006e-10
 6     Algeria    Africa         pop  1.176242e-06 7.588190e-08  15.500960 2.548769e-08
 7      Angola    Africa (Intercept)  2.855043e+01 1.922225e+00  14.852803 3.843692e-08
 8      Angola    Africa         pop  1.276860e-06 2.482137e-07   5.144195 4.351004e-04
 9   Argentina  Americas (Intercept)  5.323586e+01 3.784907e-01 140.653008 8.102227e-18
10   Argentina  Americas         pop  5.532629e-07 1.282987e-08  43.123018 1.079775e-12
# ... with 274 more rows
person Axeman    schedule 24.05.2017
comment
Спасибо, @Axeman! Работал как шарм. Как вы думаете, стоит ли регистрировать это как проблему с мурлыканьем на GitHub? Или это не проблема? - person RNB; 24.05.2017
comment
О, я вижу ваш комментарий по этой проблеме выше. Спасибо :) - person RNB; 25.05.2017