Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mutate(across(map())): Any way to include the column name in a .progress message from map()?

Tags:

r

dplyr

purrr

If you want to call a function that returns multiple values on a column of a data.frame, and append these values as new columns to the data.frame, you can mutate(map()) |> unnest_wider(). If it's long-running, we can make use of the .progress argument of map to display a progress message from cli

library(tidyverse)

df <- tibble(
  id = letters[1:6],
  dim_h = c(2, 3, 4, 5, 6, 7),
  dim_w = c(3, 4, 5, 6, 7, 8)
)

chop <- function(dim){
  Sys.sleep(0.5)
  return(list(half=dim/2, thirds=dim/3))
}

df |>
  mutate(dim_h_chopped = map(dim_h, chop, .progress="chopping")) |>
  unnest_wider(dim_h_chopped, names_sep = "_")
#> chopping ■■■■■■■■■■■ 33% | ETA: 2s
#> chopping ■■■■■■■■■■■■■■■■ 50% | ETA: 2s
#> chopping ■■■■■■■■■■■■■■■■■■■■■ 67% | ETA: 1s
#> chopping ■■■■■■■■■■■■■■■■■■■■■■■■■■ 83% | ETA: 1s
#> # A tibble: 6 × 5
#>   id    dim_h dim_w dim_h_chopped_half dim_h_chopped_thirds
#>   <chr> <dbl> <dbl>              <dbl>                <dbl>
#> 1 a         2     3                1                  0.667
#> 2 b         3     4                1.5                1    
#> 3 c         4     5                2                  1.33 
#> 4 d         5     6                2.5                1.67 
#> 5 e         6     7                3                  2    
#> 6 f         7     8                3.5                2.33

We can expand to multiple columns by adding across() to the mix, but since the progress message resets for each new column, it'd be great to include the name of the column in the progress message to provide some sense of where we are in the big picture.

df |>
  mutate(across(starts_with("dim_"), ~ map(.x, chop, .progress = "chopping"), .names="{.col}_chopped")) |>
  unnest_wider(ends_with("_chopped"), names_sep = "_")
#> chopping ■■■■■■■■■■■ 33% | ETA: 2s
#> chopping ■■■■■■■■■■■■■■■■ 50% | ETA: 2s
#> chopping ■■■■■■■■■■■■■■■■■■■■■ 67% | ETA: 1s
#> chopping ■■■■■■■■■■■■■■■■■■■■■■■■■■ 83% | ETA: 1s
#> chopping ■■■■■■■■■■■ 33% | ETA: 2s
#> chopping ■■■■■■■■■■■■■■■■ 50% | ETA: 2s
#> chopping ■■■■■■■■■■■■■■■■■■■■■ 67% | ETA: 1s
#> chopping ■■■■■■■■■■■■■■■■■■■■■■■■■■ 83% | ETA: 1s
#> # A tibble: 6 × 7
#>   id    dim_h dim_w dim_h_chopped_half dim_h_chopped_thirds dim_w_chopped_half
#>   <chr> <dbl> <dbl>              <dbl>                <dbl>              <dbl>
#> 1 a         2     3                1                  0.667                1.5
#> 2 b         3     4                1.5                1                    2  
#> 3 c         4     5                2                  1.33                 2.5
#> 4 d         5     6                2.5                1.67                 3  
#> 5 e         6     7                3                  2                    3.5
#> 6 f         7     8                3.5                2.33                 4  
#> # ℹ 1 more variable: dim_w_chopped_thirds <dbl>

Can we build a better progress message?

# can we include the column name in the progress message?
df |>
  mutate(across(c(dim_h, dim_w), ~ map(.x, chop, .progress = glue::glue("chopping {.x}")), .names="{.col}_chopped")) |>
  unnest_wider(ends_with("_chopped"), names_sep = "_")
#> Error in `mutate()`:
#> ℹ In argument: `across(...)`.
#> Caused by error in `across()`:
#> ! Can't compute column `dim_h_chopped`.
#> Caused by error:
#> ! Failed to evaluate glue component {.x}
#> Caused by error:
#> ! object '.x' not found

Why can't glue() find .x, when two arguments to the left .x works just fine? (of course, .x probably isn't what we want here anyway--we want the name of .x, but I sense this is a start).

How can we get the column name into the progress message?

Created on 2025-10-07 with reprex v2.1.1

like image 281
mac Avatar asked Nov 02 '25 22:11

mac


1 Answers

  1. {.col} is specific to .names=, it is not a generic glue() thing nor available to other functions.
  2. I don't think we want .x, I suggest cur_column() instead.
library(dplyr)
library(tidyr)
library(purrr)

df |>
  mutate(across(starts_with("dim_"), ~ map(.x, chop, .progress = glue::glue("chopping {cur_column()}")), .names="{.col}_chopped")) |>
  unnest_wider(ends_with("_chopped"), names_sep = "_")
# chopping dim_h ■■■■■■■■■■■                       33% |  ETA:  2s
# chopping dim_h ■■■■■■■■■■■■■■■■                  50% |  ETA:  2s
# chopping dim_h ■■■■■■■■■■■■■■■■■■■■■             67% |  ETA:  1s
# chopping dim_h ■■■■■■■■■■■■■■■■■■■■■■■■■■        83% |  ETA:  1s
# chopping dim_w ■■■■■■■■■■■                       33% |  ETA:  2s
# chopping dim_w ■■■■■■■■■■■■■■■■                  50% |  ETA:  2s
# chopping dim_w ■■■■■■■■■■■■■■■■■■■■■             67% |  ETA:  1s
# chopping dim_w ■■■■■■■■■■■■■■■■■■■■■■■■■■        83% |  ETA:  1s
# # A tibble: 6 × 7
#   id    dim_h dim_w dim_h_chopped_half dim_h_chopped_thirds dim_w_chopped_half dim_w_chopped_thirds
#   <chr> <dbl> <dbl>              <dbl>                <dbl>              <dbl>                <dbl>
# 1 a         2     3                1                  0.667                1.5                 1   
# 2 b         3     4                1.5                1                    2                   1.33
# 3 c         4     5                2                  1.33                 2.5                 1.67
# 4 d         5     6                2.5                1.67                 3                   2   
# 5 e         6     7                3                  2                    3.5                 2.33
# 6 f         7     8                3.5                2.33                 4                   2.67
like image 105
r2evans Avatar answered Nov 05 '25 14:11

r2evans



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!