Curso de Auditoria de Dados

Flávio Brito


Análise de Padrões

O objetivo deste estudo é apresentar algumas técnicas para análise de padrões em dados. Utilizaremos a linguagem R e seus pacotes.

Vamos utilizar o pacote bpa - Basic Pattern Analysis. Este pacote possui funções especiais em análise de padrões em dados. É um conjunto de ferraamentas para pré-processamento de dados que ajuda a economizar linhas e linhas de código em busca de padrões de dados sejam conjuntos de caracteres, números ou combinações de números e caracteres. É util para limpeza de dados e estudo de padrões e anomalias.


In [6]:
install.packages("bpa", repos = "https://cloud.r-project.org")


package 'bpa' successfully unpacked and MD5 sums checked

The downloaded binary packages are in
	C:\Users\flavi\AppData\Local\Temp\RtmpAzlaRF\downloaded_packages

Carregando a biblioteca bpa


In [9]:
library(bpa)

Carregando os dados de exemplo do pacote


In [11]:
data(messy, package = "bpa")

In [16]:
head(messy)
attach(messy)


GenderDatePhone
1Female 16Aug2001 571 972 510
2Male 2009-08-21 090 875 285
3M 01/22/2004 (079)-200-150
4male 09/02/2008 (129)-006-808
5Male February 19 2006016 651 851
6Female 16Nov2015 (492)-455-108

Pode-se perceber imediatamente que os valores possuem formatos mistos. Isto é muito comum quando os dados são inseridos manualmente dentro de um sistema e por não ter uma crística de dentrada acabam sendo aceitos pelo sistema transacional, dificultando assim a padronização dos mesmos.

Utilização básica


In [20]:
get_pattern("(079)-200-150")


"(999)-999-999"

In [21]:
get_pattern("016 651 851")


"999w999w999"

In [25]:
get_pattern("016 651 851", ws_char = "<BRANCO>")


"999<BRANCO>999<BRANCO>999"

Buscando padrões dentro de um Data Frame

Agora examinemos algumas variáveis, buscando não só descobrir os padrões como também a frequência de cada um na variável. Voltemos aos dados. Busquemos padrões na variável Date


In [26]:
messy$Date %>%
  get_pattern %>%  # extrai o padrão
  table %>%        # tabula as fraquências
  as.data.frame    # apresenta o resultado como um data frame


.Freq
199/99/9999259
29999-99-99262
399Aaa9999241
4Aaaaaaaaaw99w999919
5Aaaaaaaaw99w999956
6Aaaaaaaw99w999945
7Aaaaaaw99w999924
8Aaaaaw99w999936
9Aaaaw99w999942
10Aaaw99w999916

Perceba que temos 259 registros no campo Date com formato 99/99/9999 (Ex:01/22/2004) e 241 com formato 99Aaa9999(Ex:16Aug2001) , por exemplo.

Analisando os dados da variável alvo:


In [28]:
messy$Date %>%
  unique %>%    # extract unique values
  head(50)      # look at first 50 observations


  1. "16Aug2001"
  2. "2009-08-21"
  3. "01/22/2004"
  4. "09/02/2008"
  5. "February 19 2006"
  6. "16Nov2015"
  7. "2004-07-12"
  8. "24Sep2013"
  9. "November 01 2007"
  10. "2007-08-15"
  11. "August 22 2009"
  12. "2003-05-29"
  13. "2011-04-02"
  14. "October 29 2004"
  15. "2004-09-13"
  16. "25Nov2009"
  17. "02/12/2010"
  18. "23Jan2008"
  19. "06/30/2006"
  20. "2009-07-24"
  21. "December 02 2013"
  22. "14Jun2014"
  23. "2009-04-19"
  24. "09/03/2009"
  25. "November 25 2007"
  26. "18Jan2015"
  27. "2009-03-05"
  28. "10/24/2006"
  29. "09/09/2008"
  30. "September 08 2012"
  31. "12/31/2011"
  32. "11/12/2009"
  33. "09/23/2002"
  34. "10/09/2002"
  35. "2004-12-11"
  36. "2001-08-23"
  37. "02/09/2004"
  38. "November 02 2010"
  39. "03/14/2007"
  40. "24Dec2004"
  41. "March 10 2004"
  42. "November 05 2012"
  43. "2010-02-11"
  44. "12/25/2009"
  45. "October 25 2007"
  46. "2011-07-22"
  47. "April 01 2014"
  48. "18Mar2009"
  49. "06Feb2015"
  50. "2015-12-10"

Padronizar os dados através de basic pattern analysis fornece uma representação muito mais clara a respeito dos dados que são frequentemente mais usados durante a etapa de pré-processamento

Analisando todas as variáveis do Data frame de uma só vez


In [31]:
messy %>%
    bpa %>%
    head(10)


GenderDatePhone
1Aaaaaa 99Aaa9999 999w999w999
2Aaaa 9999-99-99 999w999w999
3A 99/99/9999 (999)-999-999
4aaaa 99/99/9999 (999)-999-999
5Aaaa Aaaaaaaaw99w9999999w999w999
6Aaaaaa 99Aaa9999 (999)-999-999
7Aaaaaa 9999-99-99 (999)w999w999
8Aaaaaa 99Aaa9999 999-999-999
9aaaa Aaaaaaaaw99w9999999w999w999
10Aaaaaa 9999-99-99 999-999-999

Com muitos dados, muitas vezes será mais útil exibir uma lista contendo apenas os padrões únicos para cada coluna de um frame.


In [33]:
# Retorna somente os padôes únicos em formato de lista
bpa(messy, unique_only = TRUE)


$Gender

     A   aaaa   Aaaa aaaaaa Aaaaaa 
   189    110    312     98    291 

$Date

       99/99/9999        9999-99-99         99Aaa9999 Aaaaaaaaaw99w9999 
              259               262               241                19 
 Aaaaaaaaw99w9999   Aaaaaaaw99w9999    Aaaaaaw99w9999     Aaaaaw99w9999 
               56                45                24                36 
     Aaaaw99w9999       Aaaw99w9999 
               42                16 

$Phone

(999)-999-999 (999)w999w999   999-999-999   999w999w999 
          242           250           276           232 

Finalmente, nós incluímos a função match_pattern para extrair os valores de um vetor que coincidam com um padrão especificado. Por exemplo, o fragmento de código a seguir irá extrair os valores exclusivos de que coincidirem com o padrão padronizado Gender Aaaa.


In [36]:
# Extrai de dentro de Gender os valores que coincidem com o padrão "Aaaa"
match_pattern(messy$Gender, pattern = "Aaaa", unique_only = TRUE)


"Male"

Estudo de Caso - Pagamento de Impostos


In [37]:
library(bpa)

In [40]:
nf <-read.csv2("./dados/NotaFiscal.csv", header = TRUE)

In [41]:
head(nf)


CNPJUFDataNFClassificacaoValor
121.704.783/0001-64RJ 01/09/2016 90 ME R$30.000,00
221.704.783/0001-64RJ 02/09/2016 91 ME R$40.000,00
303.117.734/0001-43SP 03/09/2016 2000 MEI R$444,00
476.313.316/0001-03SP 04/09/2016 111 MEI R$4,00
506.062.510/0001-70SP 05/09/2016 222 R$4.444,00
616.474.789/0001-52GO 06/09/2016 33333 R$55,00

In [42]:
nf %>%
    bpa%>%
head(10)


CNPJUFDataNFClassificacaoValor
199.999.999/9999-99AA 99/99/9999 99 AA wA$99.999,99w
299.999.999/9999-99AA 99/99/9999 99 AA wA$99.999,99w
399.999.999/9999-99AA 99/99/9999 9999 AAA wA$999,99w
499.999.999/9999-99AA 99/99/9999 999 AAA wA$9,99w
599.999.999/9999-99AA 99/99/9999 999 wA$9.999,99w
699.999.999/9999-99AA 99/99/9999 99999 wA$99,99w
799.999.999/9999-99AA 99/99/9999 9999999 AAA wA$999,99w
899.999.999/9999-99AA 99/99/9999 999 AA wA$999,99w
999.999.999/9999-99AA 99/99/9999 999 wA$9.999,99w
1099.999.999/9999-99AA 99/99/9999 99 AAA wA$9.999.999,99w

In [45]:
# Retorna somente os padôes únicos em formato de lista
bpa(nf, unique_only = TRUE)


$CNPJ

99.999.999/9999-99 
                10 

$UF

AA 
10 

$Data

99/99/9999 
        10 

$NF

     99     999    9999   99999 9999999 
      3       4       1       1       1 

$Classificacao

     AA AAA 
  3   3   4 

$Valor

        wA$9,99w     wA$9.999,99w wA$9.999.999,99w        wA$99,99w 
               1                2                1                1 
   wA$99.999,99w       wA$999,99w 
               2                3 

Busca NF por tamanho


In [48]:
nf$NF %>%
  get_pattern %>%  # extrai o padrão
  table %>%        # tabula frequências
  as.data.frame    # apresenta o dado como data frame


.Freq
1993
29994
399991
4999991
599999991

Encontrar NF com padrão 99


In [60]:
# Extrai de dentro de Gender os valores que coincidem com o padrão "99"
match_pattern(nf$NF, pattern = "99", unique_only = TRUE)


  1. 90
  2. 91
  3. 89