Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

str_replace inside fct_reorder inside mutate(across())

Say I have this tibble:

df <- tibble::tribble(
  ~how_bright_txt, ~how_bright_num,   ~how_hard_txt, ~how_hard_num, ~how_hot_txt, ~how_hot_num,
  "Not very much",              1L,   "Really hard",            5L,       "Cold",           1L,
       "Somewhat",              2L, "Somewhat hard",            2L, "A bit cold",           2L,
         "Medium",              3L,        "Medium",            3L,     "Medium",           3L,
    "Quite a bit",              4L,    "Quite hard",            4L,  "Quite hot",           4L,
          "A lot",              5L, "Not very hard",            1L, "Really hot",           5L
  )

I want to make new columns named with the first part of the existing column names (minus the _txt or _num prefix) and which take the value of the _txt columns but converting them to factors ordered by the corresponding _num columns.

I can do this by repeating fct_reorder inside mutate for each column, like so:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

require(tidyverse)

df %>% 
    mutate(how_bright = fct_reorder(how_bright_txt, -how_bright_num),
           how_hard = fct_reorder(how_hard_txt, -how_hard_num),
           how_hot = fct_reorder(how_hot_txt, -how_hot_num)) %>%
    select(-c(ends_with("_txt"), ends_with("_num")))

But I want to streamline this and use mutate(across()). So I tried doing this:

df %>% 
    mutate(across(ends_with("_txt"), 
         ~ fct_reorder(.x, str_replace(.x, "_txt", "_num")), 
                     .names = '{stringr::str_remove({col}, "_txt")}')) %>%
    select(-c(ends_with("_txt"), ends_with("_num")))

But the ordering of the resulting factors (how_bright, how_hard, how_hot) are incorrect and don’t correspond to the ordering in the original _num columns. I have also tried replacing the str_replace call with a gsub call but I get the same output

Can anyone see what I’m doing wrong?

>Solution :

What you need is cur_column() and get(). cur_column() gives the current column name, i.e. *_txt. After str_replace() is used on it, get() searches the new name (i.e. *_num) in the current dataset and returns its values.

library(tidyverse)

df %>% 
  mutate(across(ends_with("_txt"), 
                ~ fct_reorder(.x, get(str_replace(cur_column(), "_txt", "_num"))),
                .names = "{str_remove(.col, '_txt')}"),
         .keep = "unused")

# # A tibble: 5 × 3
#   how_bright    how_hard      how_hot   
#   <fct>         <fct>         <fct>     
# 1 Not very much Really hard   Cold      
# 2 Somewhat      Somewhat hard A bit cold
# 3 Medium        Medium        Medium    
# 4 Quite a bit   Quite hard    Quite hot 
# 5 A lot         Not very hard Really hot
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading