Usando dicionário de dados para fazer o recode das variáveis

Olá pessoal, boa noite.

Estou precisando fazer o recode de várias variáveis e não estou conseguindo pensar numa solução viável.

Eu tenho um banco de dados com várias colunas e estão codificadas. Por exemplo, Sexo possui os valores F e M, sendo F = Feminino e M = Masculino. As outras variáveis seguem a mesma lógica, sendo que os códigos podem ser números.

Possuo também um excel com o dicionário de dados, sendo que formatei de forma a ficar da seguinte maneira:

variavel valor_tabela descricao
sexo F feminino
sexo M masculino
escola 1 publica
escola 2 particular
escola 3 outra

A minha tabela de dados é a seguinte:

id sexo escola
1 F 1
2 M 1
3 F 2
4 F 3
5 M 1

Eu gostaria de usar o dicionário de dados para fazer o recode() das variáveis com suas descrições. Gostaria que a tabela ficasse o seguinte:

id sexo escola
1 feminino publica
2 masculino publica
3 feminino particular
4 feminino outra
5 masculino publica

Meu objetivo é fazer o recode em todas as variáveis, utilizando da planilha de dicionário de dados. Minha tentativa foi criar uma lista com os nomes das variáveis alvo e fazer um FOR para fazer vários joins.

Obrigado pessoal.

Oi Euler, boa noite.
Acho que a sintaxe abaixo resolve seu problema, tenta ai…

library(dplyr)
x = data.frame(
   id = 1:5
  ,sexo = c('F','M','F','F','M')
  ,escola = c(1,1,2,3,1)
)

x <- x %>% mutate(
   sexo = if_else(sexo == 'F', 'feminino', 'masculino')
  ,escola = case_when(
     escola == 1 ~ 'publica'
    ,escola == 2 ~ 'particula'
    ,escola == 3 ~ 'outras'
   )
)
x

Abraços

@primojr, muito obrigado pela resposta.

A solução está perfeita. Eu tenho resolvido o problema com essa abordagem. Contudo, eu queria uma solução mais genérica pelo tamanho da base e o tamanho das variáveis que precisam ser ajustadas. Imagine que eu precise fazer isso para várias variáveis.

Seria como pegar o dicionário de dados (metadados) da base e utilizá-la para atualizar os valores na base automaticamente.

Obrigado.

Entendi @euleralencar
Neste caso, eu pensaria em estruturar de dados no formato de banco de dados, onde você terá uma tabela fato e as tabelas de dimensão. Dentro do PowerBI uso muito essa lógica.

Euler,

Eu vejo duas formas de resolver o problema: uma mais fácil de entender e outra mais fácil de automatizar. A primeira envolve usar o left_join() para juntar a referência com a tabela de interesse e depois só trocar o nome das colunas. A segunda precisa de uma função para generalizar esse processo e aplicar ela de forma repetida.

library(tidyverse)

# Tabela de referência
referencia <- tribble(
  ~variavel, ~valor_tabela, ~descricao,
  "sexo", "F", "feminino",
  "sexo", "M", "masculino",
  "escola", "1", "publica",
  "escola", "2", "particular",
  "escola", "3", "outra"
)

# Tabela de interesse
df <- tribble(
  ~id, ~sexo, ~escola,
  1, "F", 1,
  2, "M", 1,
  3, "F", 2,
  4, "F", 3,
  5, "M", 1
)

# Filtrar só os valores de referência de sexo
ref_sexo <- referencia %>%
  filter(variavel == "sexo") %>%
  select(-variavel)

# Juntar a tabela com a referência e fazer a descricao virar sexo
df <- df %>%
  left_join(ref_sexo, c("sexo" = "valor_tabela")) %>%
  select(-sexo) %>%
  rename(sexo = descricao)

# Filtrar só os valores de referência de escola
ref_escola <- referencia %>%
  filter(variavel == "escola") %>%
  select(-variavel)

# Juntar a tabela com a referência e fazer a descricao virar escola
df <- df %>%
  mutate(escola = as.character(escola)) %>% # Escola precisa virar string!
  left_join(ref_escola, c("escola" = "valor_tabela")) %>%
  select(-escola) %>%
  rename(escola = descricao)

# Tabela final
df
#> # A tibble: 5 × 3
#>      id sexo      escola    
#>   <dbl> <chr>     <chr>     
#> 1     1 feminino  publica   
#> 2     2 masculino publica   
#> 3     3 feminino  particular
#> 4     4 feminino  outra     
#> 5     5 masculino publica

Created on 2022-02-08 by the reprex package (v2.0.1)

Dá pra perceber que aplicar isso para mais de 2 colunas já vai ficar meio complicado… Nesse caso, vamos para a segunda solução, que tenta automatizar o máximo possível. O código não é simples, mas acho que dá para entender.

# Função para substituir uma coluna pela referência
substituir_referencia <- function(tab, col, tab_ref) {

  # Filtrar só os valores de referência de correta
  ref_col <- tab_ref %>%
    filter(variavel == col) %>%
    select(-variavel)

  # Quais colunas juntar
  by <- setNames("valor_tabela", col)

  # Juntar a tabela com a referência e fazer a descricao virar a coluna
  tab %>%
    mutate(across(all_of(col), as.character)) %>%
    left_join(ref_col, by) %>%
    select(-{{col}}) %>%
    rename({{col}} := descricao)
}

df %>%
  substituir_referencia("sexo", referencia) %>%
  substituir_referencia("escola", referencia)
#> # A tibble: 5 × 3
#>      id sexo      escola    
#>   <dbl> <chr>     <chr>     
#> 1     1 feminino  publica   
#> 2     2 masculino publica   
#> 3     3 feminino  particular
#> 4     4 feminino  outra     
#> 5     5 masculino publica

Created on 2022-02-08 by the reprex package (v2.0.1)

Se você estiver procurando um desafio, tente descobrir como funciona o comando abaixo, que aplica todas as substituições em uma linha só:

# Usando reduce()
reduce(c("sexo", "escola"), substituir_referencia, referencia, .init = df)
#> # A tibble: 5 × 3
#>      id sexo      escola    
#>   <dbl> <chr>     <chr>     
#> 1     1 feminino  publica   
#> 2     2 masculino publica   
#> 3     3 feminino  particular
#> 4     4 feminino  outra     
#> 5     5 masculino publica

Created on 2022-02-08 by the reprex package (v2.0.1)

1 curtida

@clente Sensacional essa automação!
Nas pesquisas que faço, geralmente a descrição que está no questionário é diferente do que apresento e sempre faço vários dePara com o mutate para arrumar a base. Apliquei essa função e ficou muito mais fácil, além do código ficar mais mais bonito :slight_smile:

Obrigado.

1 curtida

@clente sensacional. Muito elegante. Confesso que o reduce ainda estou apanhando para entender, mas é um bom desafio. Assim que eu conseguir venho aqui novamente. rsrs

Cara, achei sensacional o setNames para referenciar o ‘by’ do left_join. Nunca pensaria em usar.

Algo que eu ainda preciso entender melhor é esse conceito do NSE. Eu não consegui entender porque usou eles na parte de cima da função e na debaixo não.

De toda forma, muito obrigado!!!

1 curtida

Se quiser aprender mais sobre NSE, recomendo dar uma olhada no post que eu mesmo escrevi para introduzir o assunto: Tutorial: {rlang} para Filhotes

1 curtida