Reescrever trecho de código de forma tidy

Olá pessoal,

Gostaria de reescrever o trecho de código abaixo da forma “tidy” porém não estou sabendo como fazê-lo. Quem puder ajudar ficarei muito agradecido!

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

# Base de dados
base_dados <- structure(
  list(cod_cliente = c(762L, 4908L, 5249L, 5277L, 5300L, 5639L), 
       risco_bvsp = c("Tratavel", "Baixo", "Medio", "Baixo", "Medio","Baixo"), 
       risco_bmf = c("Alto", NA, "Baixo", NA, NA, "Baixo"), 
       risco_cvm = c("Medio", "Baixo", NA, NA, "Alto", NA), 
       risco_transf = c("Baixo", NA, NA, "Tratavel", "Medio", NA), 
       risco_mud = c("Medio", "Baixo", NA, NA, "Alto", NA), 
       risco_cad = c("Baixo", "Tratavel", "Baixo", "Baixo", "Alto", "Baixo")), 
  row.names = c(NA, 6L), 
  class = "data.frame"
)

# Juntar todos os riscos
matriz_completa<- base_dados %>% 
  mutate(
    riscos_juntos = paste(risco_bvsp, ";",
                          risco_bmf, ";",
                          risco_cvm, ";",
                          risco_transf,";",
                          risco_mud, ";",
                          risco_cad),
    risco_final = NA
    )

# OBS: O trecho abaixo é o que gostaria de reescrever de forma tidy
# Pegar o maior risco   
matriz_completa$risco_final[grep("Tratavel", matriz_completa$riscos_juntos)]<- "Tratavel"
matriz_completa$risco_final[grep("Baixo", matriz_completa$riscos_juntos)]<- "Baixo"
matriz_completa$risco_final[grep("Medio", matriz_completa$riscos_juntos)]<- "Medio"
matriz_completa$risco_final[grep("Alto", matriz_completa$riscos_juntos)]<- "Alto"

Created on 2022-04-22 by the reprex package (v2.0.1)

Não é tão simples assim deixar esse código tidy. Essa sequência de verificações não é algo fácil de fazer usando as ferramentas do tidyverse, mas existem opções! Eu ofereço duas: uma mais direta usando case_when() e uma mais enxuta usando c_across().

# Base exemplo
base_dados <- tibble::tibble(
  cod_cliente = c(762L, 4908L, 5249L, 5277L, 5300L, 5639L), 
  risco_bvsp = c("Tratavel", "Baixo", "Medio", "Baixo", "Medio","Baixo"), 
  risco_bmf = c("Alto", NA, "Baixo", NA, NA, "Baixo"), 
  risco_cvm = c("Medio", "Baixo", NA, NA, "Alto", NA), 
  risco_transf = c("Baixo", NA, NA, "Tratavel", "Medio", NA), 
  risco_mud = c("Medio", "Baixo", NA, NA, "Alto", NA), 
  risco_cad = c("Baixo", "Tratavel", "Baixo", "Baixo", "Alto", "Baixo")
)

# Opção 1: case_when()
base_dados |>
  # unite() é uma boa alternativa para um paste() longo
  tidyr::unite("riscos_juntos", -cod_cliente, sep = " ; ") |>
  dplyr::mutate(
    # Note que as verificações acontecem na ordem inversa!
    risco_final = dplyr::case_when(
      stringr::str_detect(riscos_juntos, "Alto") ~ "Alto",
      stringr::str_detect(riscos_juntos, "Medio") ~ "Medio",
      stringr::str_detect(riscos_juntos, "Baixo") ~ "Baixo",
      stringr::str_detect(riscos_juntos, "Tratavel") ~ "Tratavel"
    )
  )
#> # A tibble: 6 × 3
#>   cod_cliente riscos_juntos                                   risco_final
#>         <int> <chr>                                           <chr>      
#> 1         762 Tratavel ; Alto ; Medio ; Baixo ; Medio ; Baixo Alto       
#> 2        4908 Baixo ; NA ; Baixo ; NA ; Baixo ; Tratavel      Baixo      
#> 3        5249 Medio ; Baixo ; NA ; NA ; NA ; Baixo            Medio      
#> 4        5277 Baixo ; NA ; NA ; Tratavel ; NA ; Baixo         Baixo      
#> 5        5300 Medio ; NA ; Alto ; Medio ; Alto ; Alto         Alto       
#> 6        5639 Baixo ; Baixo ; NA ; NA ; NA ; Baixo            Baixo

# Base exemplo (recodificada)
# Se você puder recodificar os dados, é só pegar o max() de cada linha!
base_dados <- tibble::tibble(
  cod_cliente = c(762L, 4908L, 5249L, 5277L, 5300L, 5639L), 
  risco_bvsp = c(1, 2, 3, 2, 3,2), 
  risco_bmf = c(4, NA, 2, NA, NA, 2), 
  risco_cvm = c(3, 2, NA, NA, 4, NA), 
  risco_transf = c(2, NA, NA, 1, 3, NA), 
  risco_mud = c(3, 2, NA, NA, 4, NA), 
  risco_cad = c(2, 1, 2, 2, 4, 2)
)

# Opção 2: c_across()
base_dados |>
  dplyr::rowwise() |>
  dplyr::mutate(risco_final = max(dplyr::c_across(-cod_cliente), na.rm = TRUE)) |>
  dplyr::ungroup() |>
  dplyr::select(cod_cliente, risco_final)
#> # A tibble: 6 × 2
#>   cod_cliente risco_final
#>         <int>       <dbl>
#> 1         762           4
#> 2        4908           2
#> 3        5249           3
#> 4        5277           2
#> 5        5300           4
#> 6        5639           2

Created on 2022-04-23 by the reprex package (v2.0.1)

P.S.: Feitas as duas sugestões, eu ofereço mais dois comentários que não dizem respeito ao trecho que você queria deixar mais tidy:

  1. Evite usar grep() e prefira str_detect() do pacote stringr. As duas funcionam igual (só com a ordem dos argumentos trocada), mas a str_detect() é consideravelmente mais rápida e consistente.

  2. Use data.frame() ou, preferencialmente, tibble() para criar data frames. Com structure() você está essencialmente construindo a data frame “na mão”, ou seja, pulando todas as verificações essenciais para garantir a integridade dos dados.

@clente muito obrigado pela ajuda e pelas dicas!

1 Curtida