Reputation: 477
Whenever I use the purrr library function pmap()
with a function that contains an if statement with multiple conditions, the if statement does not seem to work properly. To show you what I mean, here is a reproducible example using the gapminder dataset.
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()
Now I want to build a linear regression model for each grouped dataframe. The catch is that I want to use a different x-variable in my model depending on the country and continent. Here is my function where I suspect there is a problem with the if statement:
# 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)
}
}
Now i'm going to take that function and apply it to all the grouped dataframes. What I expect is that the model summary output will show that the model for the Afghanistan dataset will have a coefficient for year
rather than pop
.
by_country2 <- by_country %>%
mutate(model = pmap(list(data, continent, country), country_model),
modelsum = map(model, tidy)) %>%
unnest(modelsum, .drop = TRUE)
by_country2
My output showing that the coefficient for Afghanistan is pop
, not 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
What is bizarre to me is that when I use only 1 condition in my function if statement, then it seems to work perfectly:
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
I'm not sure if my problem is with pmap()
or my if statement.
Upvotes: 1
Views: 1412
Reputation: 35387
This is related to this GitHub issue.
It appears pmap
is sending through continent
and country
as numerics, as can be confirmed by putting a print statement in your function.
test_fun <- function(df, cont, xx) {
print(paste(cont, xx))
}
temp <-by_country %>%
mutate(model = pmap(list(data, continent, country), test_fun))
Prints:
[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
This doesn't happen in map2
, and therefore your second try does work.
Coercing to character solves the issue:
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
Upvotes: 1