I'm working on trying to understand the purrr::map function a little better. Let's say I have a simple vector of characters, and I want to run some function that outputs a data frame using each character as an input.
Here's a toy example
animals <- c('sheep', 'cow', 'horse')
make_df <- function(x){
data.frame(r1 = rnorm(1:5), r2 = rnorm(1:5), an = x)
}
Here's what make_df
> make_df('sheep')
r1 r2 an
-0.18069698 -0.4767575 sheep
0.09580225 0.2785548 sheep
-0.74701529 0.2673391 sheep
-1.62795239 1.0026010 sheep
0.36573951 -0.2323944 sheep
Now, I want to run this function for each animal and save each dataframe to a list, and put that list in a new data frame where one column is the animals and one column is the list of data frames (which I'll use with other tidyverse functions).
I think the way to do that would be something like data.frame(animals = animals) %>% mutate(ldf = map(animals, make_df(.)))
data.frame(animals = animals) %>% mutate(ldf = map(animals, make_df(.)))
but this gives me an error
Error in mutate_impl(.data, dots): Evaluation error: arguments imply differing number of rows: 5, 3. Traceback: 1. data.frame(animals = animals) %>% mutate(ldf = map(animals, make_df(.))) 2. withVisible(eval(quote(`_fseq`(`_lhs`)), env, env)) 3. eval(quote(`_fseq`(`_lhs`)), env, env) 4. eval(quote(`_fseq`(`_lhs`)), env, env) 5. `_fseq`(`_lhs`) 6. freduce(value, `_function_list`) 7. withVisible(function_list[[k]](value)) 8. function_list[[k]](value) 9. mutate(., ldf = map(animals, make_df(.))) 10. mutate.data.frame(., ldf = map(animals, make_df(.))) 11. as.data.frame(mutate(tbl_df(.data), ...)) 12. mutate(tbl_df(.data), ...) 13. mutate.tbl_df(tbl_df(.data), ...) 14. mutate_impl(.data, dots)
Of course, I can make this list of data frames with lapply
dfs <- lapply(animals, make_df)
But then if I try to bind dfs and animals into one data frame, I get a seemingly related error, again about differing numbers of rows.
data.frame(animals, dfs)
Error in data.frame(animals, dfs): arguments imply differing number of rows: 3, 5 Traceback: 1. data.frame(animals, dfs) 2. stop(gettextf("arguments imply differing number of rows: %s", . paste(unique(nrows), collapse = ", ")), domain = NA)
Clearly, I am missing something fundamental here. Why am I unable to combine a list of characters and a list of data frames into one data frame manually, and how am I misusing purrr::map
so that R runs into a problem, presumably trying to do the same within my functions.
Your syntax is a little bit off, you'd either use map(animals, make_df)
or map(animals, ~ make_df(.))
, the second argument of map
needs to be a function, which is the same as lapply
:
data.frame(animals) %>% mutate(ldf = map(animals, make_df)) %>% as.tibble()
# A tibble: 3 x 2
# animals ldf
# <fctr> <list>
#1 sheep <data.frame [5 x 3]>
#2 cow <data.frame [5 x 3]>
#3 horse <data.frame [5 x 3]>
data.frame(animals) %>% mutate(ldf = map(animals, ~ make_df(.))) %>% as.tibble()
# A tibble: 3 x 2
# animals ldf
# <fctr> <list>
#1 sheep <data.frame [5 x 3]>
#2 cow <data.frame [5 x 3]>
#3 horse <data.frame [5 x 3]>
Or if using the data.frame
constructor, you need to use I
to create a list type column:
data.frame(animals, ldf = I(lapply(animals, make_df)))
# ^
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.