How do you take any function, e.g. f(.data, ...) and make it work with grouped data?
dplyr::do() does this elegantly. The approach via nest() + mutate() + map() + unnest() also works but isn't exactly the same and buries the intention of this specific task.
Is there a succinct/evocative way to tackle this problem?
Here is my attempt:
library(tidyverse)
# I want to make any funciton work with grouped data.
# For example:
first_row <- function(.x, to_chr = FALSE) {
first <- .x[1, ]
if (to_chr) {
first[] <- lapply(first, as.character)
}
tibble::as.tibble(first)
}
# Pulls the first row of a dataframe
first_row(mtcars)
#> # A tibble: 1 x 11
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> * <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 21 6 160 110 3.9 2.62 16.5 0 1 4 4
# Optionally converts all columns to character
first_row(mtcars, to_chr = TRUE)
#> # A tibble: 1 x 11
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> * <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 21 6 160 110 3.9 2.62 16.46 0 1 4 4
# To make it work with grouped data I can use dplyr::do()
mtcars %>%
group_by(cyl) %>%
do(first_row(., to_chr = TRUE))
#> # A tibble: 3 x 11
#> # Groups: cyl [3]
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 22.8 4 108 93 3.85 2.32 18.61 1 1 4 1
#> 2 21 6 160 110 3.9 2.62 16.46 0 1 4 4
#> 3 18.7 8 360 175 3.15 3.44 17.02 0 0 3 2
# But do() will be deprecated in favor of nest() + map() http://bit.ly/2uyzcwa
mtcars %>%
group_by(cyl) %>%
nest() %>%
mutate(., data = map(data, first_row, to_chr = TRUE)) %>%
unnest()
#> # A tibble: 3 x 11
#> cyl mpg disp hp drat wt qsec vs am gear carb
#> <dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 6 21 160 110 3.9 2.62 16.46 0 1 4 4
#> 2 4 22.8 108 93 3.85 2.32 18.61 1 1 4 1
#> 3 8 18.7 360 175 3.15 3.44 17.02 0 0 3 2
# This isn't exactly the same because `cyl` wasn't converted to character.
# But worse, this approach burries my intention. Let's make it move evocative
by_group <- function(.x, .f, ...) {
grouped <- tidyr::nest(.x)
out <- dplyr::mutate(grouped, data = purrr::map(.data$data, .f, ...))
tidyr::unnest(out)
}
mtcars %>%
group_by(cyl) %>%
by_group(first_row)
#> # A tibble: 3 x 11
#> cyl mpg disp hp drat wt qsec vs am gear carb
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 6 21 160 110 3.9 2.62 16.5 0 1 4 4
#> 2 4 22.8 108 93 3.85 2.32 18.6 1 1 4 1
#> 3 8 18.7 360 175 3.15 3.44 17.0 0 0 3 2
mtcars %>%
group_by(cyl) %>%
by_group(first_row, to_chr = TRUE)
#> # A tibble: 3 x 11
#> cyl mpg disp hp drat wt qsec vs am gear carb
#> <dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 6 21 160 110 3.9 2.62 16.46 0 1 4 4
#> 2 4 22.8 108 93 3.85 2.32 18.61 1 1 4 1
#> 3 8 18.7 360 175 3.15 3.44 17.02 0 0 3 2
# This doesn't solve the problem with `cyl` but makes the code clearer.
Created on 2018-07-14 by the reprex package (v0.2.0.9000).