4 Preparando sua base de dados para fazer o linkage

Para o relacionamento de bases de dados são executados um conjunto de processos, tidos como boas práticas, para o estabelecimento de linkage de forma otimizada e com maior acurácia do resultado. Estes passos que foram daptados de podem variar conforme a estratégia de linkage acompanhe a seguir:

  1. Realizar a de padronização dos campos (variáveis) comuns a serem empregados no relacionamento (ex.: quebra do campo nome em seus componentes e a transformação de caracteres para caixa alta). A princípio não se deve remover os missings (NA) pois a não informação vai fazer parte da métrica de similaridade a ser usada.

  2. Deve-se identificar qual a variável a ser usada como blocagem para minimizar o custo com o processamento de dados e a perda de pares verdadeiros.

  3. A escolha de método de linkage, com o uso de cálculo de escores, que sumarizam o grau de concordância global entre registros de um mesmo par.

  4. A definição de limiares para a classificação dos pares de registros relacionados em pares verdadeiros, não pares e pares duvidosos.

  5. A revisão manual dos pares duvidosos visando a classificação dos mesmos como pares verdadeiros ou não pares. Nem sempre é possível se fazer essa etapa entretanto ela pode ajudar a entender e validar especialmente nas primeiras vezes que você vai fazer um linkage.

Adaptado de Coeli & Camargo Jr (https://doi.org/10.1590/S1415-790X2002000200006)


4.1 Deduplicando da base de dados

O primeiro passo para iniciar e fazer o linkage é a “deduplicação” das bases de dados. A deduplicação consiste em identificar e remover as duplicidades presentes nos dados. Nem sempre este é um procedimento simples que possa ser automatizado.

Nesta etapa é importante que você reconheça onde estão os melhores registros (de maior qualidade) das bases para o cruzamento. Em alguns registros, parte das informações relevantes pode estar em cada uma das duplicatas. Por exemplo, em relação a um mesmo paciente, a data de internação pode estar presente em um dos registros, enquanto a informação sobre a evolução do caso está gravada em um segundo registro. Em casos como os apresentados será necessária uma verificação manual para consolidar e reconstituir um registro único.


Tabela 7: Exemplos de tratamento de deduplicação.


O R possui diversos pacotes para fazer linkage de registros. Destacamos alguns que podem ser explorados.

Neste curso nossa escolha recaiu sobre o pacote reclin por ser mais simples que a versão mais nova (reclin2) e permitir demostrar os principais conceitos de linkage de bases de dados.

Outros pacotes que podem ser considerados são:

  • RecordLinkage: Record Linkage Functions for Linking and Deduplicating Data Sets

  • reclin2: Record Linkage Toolkit (versão mais nova mas não idêntica)

  • diyar: Record Linkage and Epidemiological Case Definitions in R

  • BRL: Beta Record Linkage methodology

  • fastLink: Fast Probabilistic Record Linkage with Missing Data

  • PPRL: Privacy Preserving Record Linkage

Saiba que o termo linkage se refere a várias técnicas diferentes seja na área de estatística, genética ou teoria de grafos.


Agora, vamos praticar! Abra o seu RStudio para realizarmos algumas análises.

Acompanhe o script a seguir para instalar e carregar os pacotes tidyverse, reclin e outros. Eles serão utilizados para as práticas neste curso.

if(!require(tidyverse)) install.packages("tidyverse");library(tidyverse)
if(!require(reclin)) install.packages("reclin");library(reclin)
if(!require(digest)) install.packages("digest");library(digest)
if(!require(knitr)) install.packages("knitr");library(knitr)
if(!require(DT)) install.packages("DT");library(DT)


Pronto. Agora precisamos importar a base de dados que será utilizada durante o curso. Acesse o menu lateral “Arquivos” do curso e faça download do banco de dados de nome sivep_identificado.csv e a de nome DO_ROSAS.csv. Lembre-se de manter todas as bases de dados deste curso em uma mesma pasta ou diretório!

Para nosso exemplo, iremos realizar um linkage com dados de dados exportadas do Sistema de Informação de Mortalidade (SIM) e do Sistema de Informação da Vigilância Epidemiológica da Gripe (SIVEP-Gripe) do Estado de Rosas (ambos fictícios). Vamos lá!

Imagine que a imprensa divulgou alguns óbitos por covid-19 diferentes dos que você tem acompanhado no SIM. A imprensa de Rosas refere que o estado está superestimando os óbitos, sua chefia imediata solicita então que seja feita um cruzamento entre as base de dados de internados e de óbitos para avaliar esse rumor.

Assim, você enquanto profissional de vigilância em saúde deverá realizar um linkage de bancos de dados e encontrar se existe diferenças de registros entre os sistemas e comunicar o resultado de forma imediata para a correção dos dados e sua publicação, caso couber.

Para esta avaliação, iniciaremos importando a base de dados do SIVEP-Gripe. Acompanhe o script a seguir e replique-o em seu RStudio:

# Importando dados do SIVEP-Gripe 
sivep <- read_csv2("Dados/sivep_identificado.csv")


Observe que objeto {sivep} possui 10196 registros contendo as seguintes variáveis (colunas) que analisaremos para realizar a nossa avaliação:

  • nu_notific,
  • nome,
  • sexo,
  • data_nasc,
  • idade,
  • cpf, e
  • nome_mae.

Para conhecer melhor esse banco, vamos visualizar os 100 primeiros registros da tabela {sivep}, conforme o script a seguir. Copie-o em sue RStudio.


DT::datatable(head(sivep, 100))


Tabela 8: Base de dados fictícia do SIVEP.


Observe que há duplicações de registros, por vezes idênticos, mas por vezes com campos diferentes tais como nome, nome da mãe, CPF e data de nascimento. Nessa primeira etapa vamos usar o algoritmo de deduplicação para achar essas duplicidades.


Atenção

Todos os bancos de dados utilizados para análises neste curso se encontram no menu lateral “Arquivos” do curso. Lembre-se de fazer o download do material do curso diretamente do Ambiente Virtual de Aprendizagem do curso e arquivá-los em um diretório que você deverá indicar para que o R os localize.


4.2 Gerando e filtrando os pares

Vamos um pouco mais adiante em nosso linkage. Em primeiro lugar, precisamos especificar que estamos deduplicando, ou seja, comparando o banco de dados do SIVEP-Gripe com ele mesmo. Dessa forma vamos identificar se há registros duplicados nessa base e resolver a duplicidade, caso seja necessário.

Para isso, utilizaremos o método de blocagem. Precisaremos, então, especificar a variável que usaremos como blocagem. Nesse caso será a variável sexo.

Apesar da pouca redução de dimensão que esta variável oferece, ela é bem confiável pois possui poucos erros e proporciona uma redução do número de pares considerável: indo de pouco menos de 52 milhões de pares para aproximadamente 26 milhões.

No código a seguir utilizamos a função pair_blocking() do pacote reclin e especificamos a blocagem por sexo. Já a função filter_pairs_for_deduplication() reduzirá o número de pares a serem comparados levando em conta a blocagem e o fato de que você está comparando o banco contra ele mesmo. Vamos lá!

Primeiro, armazenaremos no objeto {pares_blocagem} todos os pares a serem comparados.

Acompanhe o script a seguir e replique-o em seu RStudio:

# Realizando a blocagem dos dados pela variável "sexo" com uso da função 
# pair_blocking()
pares_blocagem <- pair_blocking(x = sivep, y = sivep, blocking_var = c("sexo")) |>
  
  # Filtrando os pares duplicados com a função filter_pairs_for_deduplication()
  filter_pairs_for_deduplication()  

# Visualizando a tabela resultante  
pares_blocagem
#> Simple blocking
#>   Blocking variable(s): sexo
#>   First data set:  10 196 records
#>   Second data set: 10 196 records
#>   Total number of pairs: 25 985 290 pairs
#> 
#> ldat with 25 985 290 rows and 2 columns
#>              x     y
#> 1            1     3
#> 2            1     4
#> 3            1     6
#> 4            1     7
#> 5            1     8
#> 6            1    10
#> 7            1    11
#> 8            1    12
#> 9            1    13
#> 10           1    16
#> :            :     :
#> 25985281 10192 10193
#> 25985282 10192 10194
#> 25985283 10192 10195
#> 25985284 10192 10196
#> 25985285 10193 10194
#> 25985286 10193 10195
#> 25985287 10193 10196
#> 25985288 10194 10195
#> 25985289 10194 10196
#> 25985290 10195 10196


Observe que ao visualizarmos o objeto {pares_blocagem} o R apresentará no Painel Console algumas informações sobre o processo de blocagem:

  • Simple blocking: indica que se trata de um método simples de blocagem, isto é, quando os nomes das variáveis utilizadas são iguais entre si.
  • First data set e Second data set: número de registros em cada banco de dados. Como neste exemplo comparamos a mesma base consigo própria, temos 10.196 registros.
  • Total number of pairs: indica o total de pares encontrados. Neste exemplo, foram encontrados quase 26 milhões de pares compatíveis. Isto representa perto de 25% do total de pares que seriam comparados caso todos os mais de 10 mil registros fossem comparados um a um.

Após estas informações, o R retorna uma amostra da tabela listando as linhas que foram pareadas. Este objeto será utilizado nos próximos passos do linkage. Vamos adiante.


4.3 Aplicando o método de linkage determinístico

Agora aplicaremos o linkage do tipo determinístico. Isto porque com ele o pareamento dos indivíduos no banco de dados é feito pela correspondência exata entre registros. Vamos lá!

  1. Como primeira etapa, iremos realizar o linkage informando quais variáveis queremos comparar. Em nosso exemplo, iremos utilizar as variáveis nome, data de nascimento, cpf e nome da mãe.

  2. Então precisaremos comparar se os valores das variáveis são iguais. Ao aplicar esta etapa poderemos obter os valores TRUE (verdadeiro) ou FALSE (falso). Para que você possa compreender melhor, se um par de registros no qual as quatro variáveis escolhidas fossem TRUE (verdadeiras) representaria um linkage com alta acurácia entre estes registros.

Observe o script a seguir com as duas etapas descritas anteriormente, e realize esta comparação em seu computador. Replique o código em seu RStudio:

# Criando objeto com o nome p_deter com resultados do linkage determinístico
p_deter <- pares_blocagem|>
  
  # Comparando os pares pelas variáveis de nome, data de nascimento, cpf e
  # nome da mãe para realização do linkage determinístico
  compare_pairs(by = c("nome", "data_nasc", "cpf", "nome_mae"))


Perceba que o objeto {p_deter} armazenou as informações de quais registros foram comparados de acordo com a blocagem anterior e quais colunas de cada um desses pares apresentam correspondência completa de acordo com o critério de linkage determinístico.

A partir dos objetos criados até aqui, poderemos realizar algumas análises extraindo informações sobre o linkage. Agora, verificaremos quantos e quais são as correspondências (matchs) perfeitas que conseguimos realizar na etapa anterior e armazenados no objeto {p_deter}. Em seu RStudio, rode as seguintes linhas de código:

# Criando objeto com correspondências perfeitas
pares_iguais <- p_deter |>
  
  # Transformando em um objeto de tabela no formato tibble
  as_tibble() |>
  
  # Filtrando apenas os registros em que todas as correspondências são iguais
  filter(nome & data_nasc & cpf & nome_mae)

# Visualizando os registros em que todas as correspondências são iguais
pares_iguais
#> # A tibble: 16 × 6
#>        x     y nome  data_nasc cpf   nome_mae
#>    <dbl> <int> <lgl> <lgl>     <lgl> <lgl>   
#>  1   528  3372 TRUE  TRUE      TRUE  TRUE    
#>  2   933  6984 TRUE  TRUE      TRUE  TRUE    
#>  3   978  3026 TRUE  TRUE      TRUE  TRUE    
#>  4  1023  9323 TRUE  TRUE      TRUE  TRUE    
#>  5  1829  1830 TRUE  TRUE      TRUE  TRUE    
#>  6  2129  3740 TRUE  TRUE      TRUE  TRUE    
#>  7  2223  5120 TRUE  TRUE      TRUE  TRUE    
#>  8  2550  6312 TRUE  TRUE      TRUE  TRUE    
#>  9  3546  8218 TRUE  TRUE      TRUE  TRUE    
#> 10  4382  5132 TRUE  TRUE      TRUE  TRUE    
#> 11  5021  6366 TRUE  TRUE      TRUE  TRUE    
#> 12  5344  7502 TRUE  TRUE      TRUE  TRUE    
#> 13  5953  6263 TRUE  TRUE      TRUE  TRUE    
#> 14  6057  6231 TRUE  TRUE      TRUE  TRUE    
#> 15  6787  9039 TRUE  TRUE      TRUE  TRUE    
#> 16  7769  9719 TRUE  TRUE      TRUE  TRUE


Observe que, neste caso, temos 16 registros idênticos. Note que o valor para o primeiro registo de x[1] (528) e y[1] (3372) indicam a linha que esses registros duplicados aparecem na base de dados {sivep}. Assim, a tabela resultante {pares_iguais} apresenta todos os pares idênticos para as variáveis que escolhemos.

Agora vamos visualizar quais são esses registros. Para isso, podemos utilizar a função slice(). Acompanhe o código a seguir e replique-o em seu RStudio:

sivep |> 
  # Selecionando no objeto SIVEP-Gripe a primeira linha dos registros duplicados 
  # no objeto `iguais` com a função slice()
  slice(pares_iguais$x[1], pares_iguais$y[1]) |> 
  
  # Visualizando a tabela com a função kable() 
  kable()



sivep |> 
  # Selecionando no objeto SIVEP-Gripe a nona linha dos registros duplicados 
  # no objeto `iguais` com a função slice()
  slice(pares_iguais$x[9],pares_iguais$y[9]) |> 
  
  # Visualizando a tabela com a função kable() 
  kable()



Conseguiu visualizar?

Com o resultado obtido seria possível nesse ponto simplesmente apagar do SIVEP-Gripe do Estado de Rosas todas as linhas correspondentes aos valores em y visto que são idênticos ao menos para essas quatro variáveis (atributos).

Considere que este é o banco de dados do SIVEP-Gripe e que ele pode nos informar sobre as reinfecções, reinternação, transferências de pacientes para outros hospitais, ou seja, ele pode conter duplicação de pacientes não por erro, mas porque houve necessidade. Em uma rotina de vigilância é preciso sempre analisar com cuidado esses casos de duplicata e decidir como tratá-los a partir das regras do sistema de informação.

Nesse exercício, tomaremos a decisão de manter todos os registros para a fase seguinte onde faremos um linkage do tipo probabilístico.


Atenção

Lembre-se que o R trabalha com os dados em memória, e como vimos, esses objetos oriundos do linkage são em geral grandes. Por exemplo, o objeto {p_deter} tem em aproximadamente 6.6 MB. Assim, quando não se vai usar mais um objeto convém ir apagando-o.

Outra recomendação nesse sentido é que se use a função gc() (Garbage Collection), que como o nome indica otimiza a memória após o uso de objetos maiores.

Acompanhe o script a seguir e replique-o em seu RStudio:

# Removendo o objeto `p_deter`
rm(p_deter)

# Otimizando o uso de memória na sessão de R
gc()
#>           used (Mb) gc trigger   (Mb)  max used   (Mb)
#> Ncells 1359632 72.7    2197014  117.4   2197014  117.4
#> Vcells 2514418 19.2  141220573 1077.5 171904409 1311.6


Você pode ter encontrado um resultado diferente do que apresentamos aqui no curso em seu computador. Não se preocupe! O resultado apresentado em seu output pode ser divergente do visualizado aqui porque a quantidade de memória RAM existente em cada computador, que processa o mesmo código aqui escrito, determinará os valores exibidos. Assim, mesmo se os valores exibidos sejam diferentes o processo é o mesmo e os resultados semelhantes.


4.4 Aplicando o método de linkage probabilístico

Agora, iremos realizar um linkage probabilístico. Para isso, utilizaremos todas as etapas armazenadas no objeto {pares_blocagem}, criado anteriormente, e aplicaremos a ele novamente a função compare_pairs().

Dessa vez vamos especificar o nome das variáveis a serem comparadas adicionando o argumento by. Também vamos especificar o método para calcular a similaridade de cada uma das variáveis!

Neste exemplo, vamos usar a distância de jaro winkler (semelhante à distância de Levenshtein, só que mais sensível à detecção de similaridades). Para saber mais clique aqui e acesse a Wikipedia.

Para usarmos jaro winkler, vamos especificar no argumento default_comparator da função compare_pairs() uma outra função chamada jaro_winkler(), do pacote reclin. Essa função especifica o ponto de corte de 0,9 para o nível de similaridade que aceitaremos (o padrão é 0,95).

Acompanhe o script a seguir e replique-o em seu RStudio:

# Criando o objeto 'pares_link_prob' com o resultado do linkage probabilístico
pares_link_prob <- pares_blocagem |>
  
  # Realizando o linkage probabilístico com a função compare_pairs()
  compare_pairs(by = c("nome", "data_nasc", "cpf", "nome_mae"),
                default_comparator = jaro_winkler(threshold = 0.9))

# Visualizando o objeto com resultado do linkage
pares_link_prob
#> Compare
#>   By: nome, data_nasc, cpf, nome_mae
#> 
#> Simple blocking
#>   Blocking variable(s): sexo
#>   First data set:  10 196 records
#>   Second data set: 10 196 records
#>   Total number of pairs: 25 985 290 pairs
#> 
#> ldat with 25 985 290 rows and 6 columns
#>              x     y      nome data_nasc       cpf  nome_mae
#> 1            1     3 0.5079365 0.7833333 0.5714286 0.5151515
#> 2            1     4 0.4148629 0.7523810 0.6517857 0.5667388
#> 3            1     6 0.4474206 0.6777778 0.6761905 0.5200337
#> 4            1     7 0.5414926 0.7047619 0.6428571 0.5685426
#> 5            1     8 0.5264550 0.6666667 0.5714286 0.5275673
#> 6            1    10 0.6139971 0.7523810 0.5634921 0.5463869
#> 7            1    11 0.4076479 0.6666667 0.6517857 0.5642602
#> 8            1    12 0.5125985 0.7333333 0.5476190 0.5015152
#> 9            1    13 0.5507937 0.6500000 0.5476190 0.4632035
#> 10           1    16 0.5414926 0.7285714 0.5476190 0.5012626
#> :            :     :         :         :         :         :
#> 25985281 10192 10193 0.5420635 0.6777778 0.6137566 0.5236842
#> 25985282 10192 10194 0.5105820 0.6777778 0.5476190 0.5087719
#> 25985283 10192 10195 0.4682540 0.7333333 0.6137566 0.5397233
#> 25985284 10192 10196 0.5006901 0.6222222 0.5000000 0.4737037
#> 25985285 10193 10194 0.6749158 0.6777778 0.5238095 0.5980861
#> 25985286 10193 10195 0.5150794 0.8250000 0.6137566 0.5036995
#> 25985287 10193 10196 0.5544686 0.6777778 0.4801587 0.5649708
#> 25985288 10194 10195 0.5105820 0.6666667 0.5000000 0.5959632
#> 25985289 10194 10196 0.6883483 0.8041667 0.6507937 0.5788596
#> 25985290 10195 10196 0.6255242 0.6500000 0.5000000 0.6038509


Atenção

Caso seu computador possua memória RAM inferior a 16 GB você poderá encontrar lentidão no processamento dos scripts deste curso. Sim, pode demorar alguns minutos até que se possa obter o output desejado.

Se possuir outros programas, aplicativos ou abas da internet abertos, feche-os! Assim você consumirá menos memória.


O objeto que criamos {pares_link_prob} irá guardar as informações dos registros que apresentaram as correspondências de acordo com os critérios de probabilidade utilizados na função compare_pairs(). Perceba que ele é muito semelhante ao que obtivemos com {p_deter}, porém, ao invés de retornar TRUE ou FALSE, ele retornou um escore de similaridade que varia de 0 a 1 para cada uma das variáveis em consideração.

Usando esses escores de similaridade para cada variável podemos construir uma nova variável que, por padrão (default), é chamada simsum e contém a soma dos escores de similaridade. Essa soma é criada pela função score_simsum() do pacote reclin.

Tendo calculado a variável simsum vamos usar agora a função select_threshold(), também do pacote reclin, para selecionar os pares a partir de um ponto de corte. O valor do ponto de corte é a fração de similaridade onde você deseja selecionar. No nosso exemplo, utilizamos apenas quatro variáveis e, por isso, o valor máximo do nosso escore de similaridade é 4. Dessa forma, você deve especificar uma fração que represente a similaridade desejada.

Para resolver a nossa avaliação comparando os registros de óbitos do SIM e SIVEP-Gripe vamos utilizar o valor de 3,55, que corresponde a um corte de similaridade 0,875 (3,5 / 4). Ou seja, de uma maneira geral, bons resultados são atingidos com valores próximos a 0,90 (o que no nosso exercício seria 3,6/4). Como próximo passo, em seguida, vamos executar o objeto criado p3.

Acompanhe o script a seguir e replique-o em seu RStudio:


p3 <- pares_link_prob |> 
  
  # Calculando o escore de similaridade com a função score_simsum()
  score_simsum() |> 
  
  # Definindo um ponto de corte de 3.5 com a função select_threshold()
  select_threshold(threshold = 3.5)

# Visualizando o objeto com resultado do linkage
p3
#> Compare
#>   By: nome, data_nasc, cpf, nome_mae
#> 
#> Simple blocking
#>   Blocking variable(s): sexo
#>   First data set:  10 196 records
#>   Second data set: 10 196 records
#>   Total number of pairs: 25 985 290 pairs
#> 
#> ldat with 25 985 290 rows and 8 columns
#>              x     y      nome data_nasc       cpf  nome_mae   simsum select
#> 1            1     3 0.5079365 0.7833333 0.5714286 0.5151515 2.377850  FALSE
#> 2            1     4 0.4148629 0.7523810 0.6517857 0.5667388 2.385768  FALSE
#> 3            1     6 0.4474206 0.6777778 0.6761905 0.5200337 2.321423  FALSE
#> 4            1     7 0.5414926 0.7047619 0.6428571 0.5685426 2.457654  FALSE
#> 5            1     8 0.5264550 0.6666667 0.5714286 0.5275673 2.292118  FALSE
#> 6            1    10 0.6139971 0.7523810 0.5634921 0.5463869 2.476257  FALSE
#> 7            1    11 0.4076479 0.6666667 0.6517857 0.5642602 2.290361  FALSE
#> 8            1    12 0.5125985 0.7333333 0.5476190 0.5015152 2.295066  FALSE
#> 9            1    13 0.5507937 0.6500000 0.5476190 0.4632035 2.211616  FALSE
#> 10           1    16 0.5414926 0.7285714 0.5476190 0.5012626 2.318946  FALSE
#> :            :     :         :         :         :         :        :      :
#> 25985281 10192 10193 0.5420635 0.6777778 0.6137566 0.5236842 2.357282  FALSE
#> 25985282 10192 10194 0.5105820 0.6777778 0.5476190 0.5087719 2.244751  FALSE
#> 25985283 10192 10195 0.4682540 0.7333333 0.6137566 0.5397233 2.355067  FALSE
#> 25985284 10192 10196 0.5006901 0.6222222 0.5000000 0.4737037 2.096616  FALSE
#> 25985285 10193 10194 0.6749158 0.6777778 0.5238095 0.5980861 2.474589  FALSE
#> 25985286 10193 10195 0.5150794 0.8250000 0.6137566 0.5036995 2.457535  FALSE
#> 25985287 10193 10196 0.5544686 0.6777778 0.4801587 0.5649708 2.277376  FALSE
#> 25985288 10194 10195 0.5105820 0.6666667 0.5000000 0.5959632 2.273212  FALSE
#> 25985289 10194 10196 0.6883483 0.8041667 0.6507937 0.5788596 2.722168  FALSE
#> 25985290 10195 10196 0.6255242 0.6500000 0.5000000 0.6038509 2.379375  FALSE


Com o objeto criado {p3} temos os pares devidamente classificados e podemos agora calcular quantas possíveis duplicidades foram identificadas. Faremos isso calculando a frequência do valores identificados pela variável select como TRUE. Para isso, basta utilizarmos a função count() do pacote dplyr. Acompanhe o script a seguir e replique-o em seu RStudio:

p3 |> 
  
  # Convertendo em um objeto de tabela no formato tibble
  as_tibble() |> 
  
  # Contando os valores da coluna select com a função count()
  count(select)
#> # A tibble: 2 × 2
#>   select        n
#>   <lgl>     <int>
#> 1 FALSE  25985102
#> 2 TRUE        188


Observe que de acordo com os resultados apresentados no objeto {p3} foram identificados 188 registros como possíveis duplicidades (valores iguais a TRUE).

Para ilustrar esse exercício, segue a seguir a Tabela 9 mostrando o impacto dos valores que poderiam ser usados como ponto de corte na função select_threshold(). Note que se usarmos 3.99, que equivale a uma similaridade de 99,75%, somente 16 pares são detectados, os mesmos apontados por nosso linkage determinístico.


Tabela 9: Valores de similaridade (%) e respectivos pares, a partir da escolha de valores de corte.


No exemplo que estamos utilizando, temos o controle prévio de que 200 duplicidades foram criadas para nosso exercício. Assim, a posteriori, o valor de 3,3 (82,5%) pode ser mais adequado.

Por sua vez, na prática, esta é uma decisão para minimizar os falsos negativos não deixando escapar possíveis duplicidades e minimizar os falsos positivos que vão consumir energia caso se prossiga a comparação com uma revisão manual. Com esse parâmetro em 3,5, identificamos 94% das duplicidades.

Vamos adicionar agora o número de notificações ao nosso objeto p3 para identificarmos os pares e adicionar os números. Acompanhe o script a seguir e replique-o em seu RStudio:

p3 <- p3 |> 
  
  # Adicionando a variável de identificação
  add_from_x(nu_not_x = "nu_notific") |> 
  add_from_y(nu_not_y = "nu_notific")


Pronto. Agora vamos listar as variáveis selecionadas ordenadas por similaridade (simsum) da menor para a maior.

Acompanhe o script a seguir e replique-o em seu RStudio:

# Criando objeto com o registro de duplicidades denominado reg_dup
reg_dup <- p3 |>
  
  # Transformando em um objeto de tabela no formato tibble
  as_tibble() |>
  
  # Filtrando apenas os valores verdadeiros (TRUE) na coluna select com a função 
  # filter()
  filter(select) |>
  
  # Selecionando apenas as colunas de interesse com a função select()
  select(x, y, simsum, select, nu_not_x, nu_not_y) |>
  
  # Reordenando as linhas de acordo com a coluna simsum, com uso da função arrange()
  arrange(simsum)

# Visualizando o objeto de registro de duplicidades
reg_dup
#> # A tibble: 188 × 6
#>        x     y simsum select nu_not_x nu_not_y
#>    <dbl> <int>  <dbl> <lgl>     <dbl>    <dbl>
#>  1    19  2301   3.53 TRUE   10059521 14378854
#>  2  2716  5250   3.63 TRUE   15174637 20001041
#>  3   195  2312   3.67 TRUE   10389866 14399150
#>  4  5074  9982   3.70 TRUE   19625124 95911775
#>  5  1134  5912   3.71 TRUE   12267310 21239686
#>  6   774  3166   3.72 TRUE   11545407 16096758
#>  7  3566  8351   3.73 TRUE   16883275 65485742
#>  8  7384  8581   3.73 TRUE   47417237 69735956
#>  9  2735  6931   3.74 TRUE   15205964 38497474
#> 10  2658  4698   3.76 TRUE   15058156 18878152
#> # … with 178 more rows


Perceba que o objeto {reg_dup} contém os 188 registros que foram identificados como duplicidades pelo algoritimo de linkage.

Caso você queira fazer uma revisão manual desses registros, pode-se obter uma lista de duplicidades. Para isso, utilize a função deduplicate_equivalence() do pacote reclin, que inclui uma chave de duplicação para cada registro, ou seja, os registros duplicados recebem a mesma chave.

Acompanhe o script a seguir e replique-o em seu RStudio:

# Criando novo objeto com a chave de duplicação de cada registro
res <- deduplicate_equivalence(pairs = p3)


Observe em seu RStudio que o objeto {`res``} possui uma nova coluna contendo o registro das duplicidades encontradas. Nesse caso, cada conjunto de registros duplicados possui um rótulo (numeração) diferente.

Acompanhe o script a seguir e replique-o em seu RStudio:

# Criando um novo objeto com as duplicidades encontradas
dup_grupos <- res |> 
  
  # Agrupando os registros de acordo com os códigos da coluna duplicate_groups, 
  # com uso da função group_by()
  group_by(duplicate_groups) |> 
  
  # Subagrupando a tabela de valores duplicados e salvando-os como uma lista em 
  # cada linha
  nest() |> 
  
  # Criando uma nova coluna denominada pares com o número de duplicatas com o uso 
  # da função mutate()
  mutate(pares = map_dbl(data, nrow))


Com o objeto res podemos criar um objeto que agrega os registros duplicados em uma lista e também criamos uma variável chamada pares que indica quantos indivíduos foram identificados naquele grupo.

Nosso interesse são os grupos que têm mais de um indivíduo. Assim, selecionando esses registros, obtemos uma lista de possíveis duplicidades. Acompanhe o script a seguir e replique-o em seu RStudio:

# Criando um novo objeto com a lista de duplicidades
lista_dup <- dup_grupos |>
  
  # Filtrando os pares com mais de um registro
  filter(pares > 1) |> 
  
  # Desagrupando os valores da lista presentes na "coluna" data
  unnest(data) 
# Visualizando o início da tabela de duplicidades
kable(head(lista_dup))


Tabela 10: Tabela de duplicidades.


Caso queira, a lista pode ser salva em formato texto ou csv para ser investigada pela equipe responsável pelo sistema. Para isso, utilize o script a seguir e replique-o em seu RStudio:

# Salvando a lista de duplicidades em um arquivo .csv
write_csv2(lista_dup, file = 'lista_duplicidades.csv')


Para limpar automaticamente as duplicidades identificadas, basta eliminar os registros duplicados que constam do objeto reg_dup. Nesse exemplo, vamos remover os registros com chave em nu_not_y.

Em sua rotina de análises é sempre recomendável que seja feita uma análise mais detalhada que considere a completitude dos dados avaliados, que liste quais as informações mais recentes, e outras eventuais discrepâncias entre registros identificados.

Vamos lá. Acompanhe o script a seguir e replique-o em seu RStudio:

# Criando um vetor com os registros de duplicidades a partir do objeto reg_dup
registros_remover <- reg_dup$nu_not_y

# Criando um novo objeto sem as duplicidades
sivep_dedup <- sivep |> 
  
  # Filtrando os registros com duplicidades indicados no objeto remover com a 
  # função filter()
  filter(!(nu_notific %in% registros_remover ))


E, por fim, vamos comparar o número de linhas em cada um e confirmar que sivep_dedup tem 188 linhas a menos. Acompanhe o script a seguir e replique-o em seu RStudio:


# Subtraindo o número de linhas no objeto sivep com o número de linhas no objeto 
# sivep_dedup
nrow(sivep) - nrow(sivep_dedup)
#> [1] 188


Fomos apresentando o passo a passo para a deduplicação, mas alguns passos não são necessários (como por exemplo o linkage determinístico). Assim tudo pode ser feito de uma forma mais direta como, por exemplo, descrito no script a seguir:

p3 <- pair_blocking(sivep, sivep,blocking_var ="sexo") |> 
   filter_pairs_for_deduplication() |> 
   compare_pairs(c("nome","data_nasc","cpf","nome_mae"),
   default_comparator = jaro_winkler(0.9)) |> 
   score_simsum() |>  
   select_threshold(3.5) |> 
   add_from_x( nu_not_x= "nu_notific") |> 
   add_from_y( nu_not_y = "nu_notific")

E para criar uma versão do banco deduplicada (sem nenhuma revisão), replique o código a seguir:

reg_dup <- p3 |> 
   as_tibble() |> 
   filter(select ) |> 
   select(x,y, simsum,select, nu_not_x ,nu_not_y) |> 
   arrange(simsum)


sivep_dedup <- sivep |> 
   filter(!(nu_notific %in% reg_dup$nu_not_y ))