Replace NAs in multiple columns using tidy eval

So I am attempting to make a function that summarize a dataset by some input columns and then replaces any NAs in those columns with "foo". I can figure it out with one grouping but am running into trouble when I have multiple groupings. Any thoughts?

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
library(tidyr)
#> Warning: package 'tidyr' was built under R version 4.1.1
library(rlang)
#> Warning: package 'rlang' was built under R version 4.1.2

sum_sw_height1 <- function(grouping) {
  starwars |>
    count(across({{ grouping }}), wt = height)
}

## works great
(d <- sum_sw_height1(c(hair_color, eye_color)))
#> # A tibble: 35 x 3
#>    hair_color    eye_color     n
#>    <chr>         <chr>     <int>
#>  1 auburn        blue        150
#>  2 auburn, grey  blue        180
#>  3 auburn, white blue-gray   182
#>  4 black         blue        336
#>  5 black         brown      1619
#>  6 black         dark          0
#>  7 black         yellow      137
#>  8 blond         blue        530
#>  9 blonde        yellow      168
#> 10 brown         blue       1366
#> # ... with 25 more rows


## Ok i'd love to always replace this NA with "foo"
d |> filter(is.na(hair_color))
#> # A tibble: 4 x 3
#>   hair_color eye_color     n
#>   <chr>      <chr>     <int>
#> 1 <NA>       black       173
#> 2 <NA>       orange      175
#> 3 <NA>       red         193
#> 4 <NA>       yellow      167

## cool this also works great for one grouping variable.
sum_sw_height2 <- function(grouping) {
  starwars |>
    count({{ grouping }}, wt = height) |>
    mutate("{{ grouping }}" := replace_na({{ grouping }}, "foo"))
}

## But my question is how does this work with two or grouping variables?
## I think this approach but that doesn't seem to work.

sum_sw_height3 <- function(grouping) {
  require(dplyr)
  require(tidyr)
  starwars |>
    count(across({{ grouping }}), wt = height) |>
    replace_na(list("{{ grouping }}" := replace_na(across({{ grouping }}), "foo")))
}

sum_sw_height3(c(hair_color, eye_color))
#> Error: `:=` can only be used within a quasiquoted argument

Unless I'm missing something, this is exactly what across() is meant for: when used in a mutate() statement, it automatically replaces all the columns selected (so no need for := or the like).

sum_sw_height4 <- function(grouping) {
  require(dplyr)
  require(tidyr)
  starwars |>
    count(across({{ grouping }}), wt = height) |>
    mutate(across({{grouping}}, replace_na, "foo"))
}

sum_sw_height4(c(hair_color, eye_color)) |> 
  tail()
#> # A tibble: 6 x 3
#>   hair_color eye_color     n
#>   <chr>      <chr>     <int>
#> 1 white      brown       259
#> 2 white      yellow      198
#> 3 foo        black       173
#> 4 foo        orange      175
#> 5 foo        red         193
#> 6 foo        yellow      167

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.