6 Transformação de dados

A transformação de dados é uma tarefa usualmente dolorosa e demorada, podendo tomar a maior parte do tempo da análise. No entanto, como nosso interesse geralmente é na modelagem dos dados, essa tarefa é muitas vezes negligenciada.

“(…) The fact that data science exists as a field is a colossal failure of statistics. To me, [what I do] is what statistics is all about. It is gaining insight from data using modelling and visualization. Data munging and manipulation is hard and statistics has just said that’s not our domain.”

Hadley Wickham

6.1 Pacotes dplyr e tidyr

O dplyr é um dos pacotes mais úteis para realizar manipulação de dados, e procura aliar simplicidade e eficiência de uma forma bastante elegante. Os scripts em R que fazem uso inteligente dos verbos dplyr e as facilidades do operador pipe tendem a ficar mais legíveis e organizados, sem perder velocidade de execução.

Por ser um pacote que se propõe a realizar um dos trabalhos mais árduos da análise estatística, e por atingir esse objetivo de forma elegante, eficaz e eficiente, o dplyr pode ser considerado como uma revolução no R.

6.1.1 Trabalhando com tibbles

A tibble nada mais é do que um data.frame, mas com um método de impressão mais adequado. Outras diferenças podem ser estudadas neste link.

Vamos assumir que temos a seguinte base de dados:

d_cjsg
## # A tibble: 184,250 × 14
##                                                      arq    id cd_acordao
##                                                    <chr> <chr>      <chr>
## 1  /home/storage/abj/raw/TJSP/cjsg/cjsg_mes01/00001.html     1    9381267
## 2  /home/storage/abj/raw/TJSP/cjsg/cjsg_mes01/00001.html     2    8671548
## 3  /home/storage/abj/raw/TJSP/cjsg/cjsg_mes01/00001.html     3    8634338
## 4  /home/storage/abj/raw/TJSP/cjsg/cjsg_mes01/00001.html     4    8536605
## 5  /home/storage/abj/raw/TJSP/cjsg/cjsg_mes01/00001.html     5    8509346
## 6  /home/storage/abj/raw/TJSP/cjsg/cjsg_mes01/00001.html     6    8490681
## 7  /home/storage/abj/raw/TJSP/cjsg/cjsg_mes01/00001.html     7    8466583
## 8  /home/storage/abj/raw/TJSP/cjsg/cjsg_mes01/00001.html     8    8449087
## 9  /home/storage/abj/raw/TJSP/cjsg/cjsg_mes01/00001.html     9    8429536
## 10 /home/storage/abj/raw/TJSP/cjsg/cjsg_mes01/00001.html    10    8331899
## # ... with 184,240 more rows, and 11 more variables: n_processo <chr>,
## #   comarca <chr>, data_julgamento <chr>, data_registro <chr>,
## #   ementa <chr>, orgao_julgador <chr>, outros_numeros <chr>,
## #   relatora <chr>, classe_assunto <chr>, txt_ementa <chr>, result <chr>

6.1.2 As cinco funções principais do dplyr

  • filter
  • mutate
  • select
  • arrange
  • summarise

6.1.3 Características

  • O input é sempre uma tibble, e o output é sempre um tibble.
  • No primeiro argumento colocamos o tibble, e nos outros argumentos colocamo o que queremos fazer.
  • A utilização é facilitada com o emprego do operador %>%

6.1.4 Vantagens

  • Utiliza C e C++ por trás da maioria das funções, o que geralmente torna o código mais eficiente.
  • Pode trabalhar com diferentes fontes de dados, como bases relacionais (SQL) e data.table.

6.1.5 select

  • Utilizar starts_with(x), contains(x), matches(x), one_of(x), etc.
  • Possível colocar nomes, índices, e intervalos de variáveis com :.
d_cjsg %>% 
  select(id, cd_acordao, comarca, relator = relatora)
## # A tibble: 184,250 × 4
##       id cd_acordao             comarca                  relator
##    <chr>      <chr>               <chr>                    <chr>
## 1      1    9381267           São Paulo           Encinas Manfré
## 2      2    8671548           Guarulhos           Edison Brandão
## 3      3    8634338              Osasco             Ivan Sartori
## 4      4    8536605          Adamantina          Walter da Silva
## 5      5    8509346             Limeira Guilherme de Souza Nucci
## 6      6    8490681           São Paulo         Roberto Solimene
## 7      7    8466583              Suzano             Poças Leitão
## 8      8    8449087 Presidente Prudente             Ivan Sartori
## 9      9    8429536           São Paulo           Willian Campos
## 10    10    8331899           São Paulo     Luis Soares de Mello
## # ... with 184,240 more rows
d_cjsg %>% 
  select(cd_acordao:comarca, classe_assunto)
## # A tibble: 184,250 × 4
##    cd_acordao                n_processo             comarca
##         <chr>                     <chr>               <chr>
## 1     9381267 0081568-68.2012.8.26.0050           São Paulo
## 2     8671548 2132739-15.2014.8.26.0000           Guarulhos
## 3     8634338 2204759-04.2014.8.26.0000              Osasco
## 4     8536605 2179832-71.2014.8.26.0000          Adamantina
## 5     8509346 2055376-49.2014.8.26.0000             Limeira
## 6     8490681 0014476-05.2014.8.26.0050           São Paulo
## 7     8466583 0067859-48.2014.8.26.0000              Suzano
## 8     8449087 0054802-60.2014.8.26.0000 Presidente Prudente
## 9     8429536 2128810-71.2014.8.26.0000           São Paulo
## 10    8331899 2002343-13.2015.8.26.0000           São Paulo
## # ... with 184,240 more rows, and 1 more variables: classe_assunto <chr>
d_cjsg %>% 
  select(n_processo, starts_with('data_'))
## # A tibble: 184,250 × 3
##                   n_processo data_julgamento data_registro
##                        <chr>           <chr>         <chr>
## 1  0081568-68.2012.8.26.0050      29/01/2015    27/04/2016
## 2  2132739-15.2014.8.26.0000      27/01/2015    04/08/2015
## 3  2204759-04.2014.8.26.0000      27/01/2015    22/07/2015
## 4  2179832-71.2014.8.26.0000      22/01/2015    16/06/2015
## 5  2055376-49.2014.8.26.0000      27/01/2015    02/06/2015
## 6  0014476-05.2014.8.26.0050      29/01/2015    27/05/2015
## 7  0067859-48.2014.8.26.0000      29/01/2015    19/05/2015
## 8  0054802-60.2014.8.26.0000      27/01/2015    13/05/2015
## 9  2128810-71.2014.8.26.0000      29/01/2015    06/05/2015
## 10 2002343-13.2015.8.26.0000      27/01/2015    29/03/2015
## # ... with 184,240 more rows

6.1.6 filter

  • Parecido com subset.
  • Condições separadas por vírgulas é o mesmo que separar por &.
d_cjsg %>% 
  select(id, cd_acordao, comarca, relator = relatora) %>% 
  filter(comarca == 'São Paulo')
## # A tibble: 41,488 × 4
##       id cd_acordao   comarca               relator
##    <chr>      <chr>     <chr>                 <chr>
## 1      1    9381267 São Paulo        Encinas Manfré
## 2      6    8490681 São Paulo      Roberto Solimene
## 3      9    8429536 São Paulo        Willian Campos
## 4     10    8331899 São Paulo  Luis Soares de Mello
## 5     12    8317638 São Paulo Sérgio Mazina Martins
## 6     13    8314983 São Paulo         Péricles Piza
## 7     14    8314866 São Paulo         Péricles Piza
## 8     17    8293299 São Paulo        Ivo de Almeida
## 9     19    8284691 São Paulo        Edison Brandão
## 10    21    8274010 São Paulo  Cesar Mecchi Morales
## # ... with 41,478 more rows
library(lubridate)
d_cjsg %>% 
  select(id, cd_acordao, comarca, data_julgamento, relator = relatora) %>% 
  filter(comarca %in% c('Campinas', 'Sorocaba') &
         (day(dmy(data_julgamento)) >= 29 | day(dmy(data_julgamento)) < 25))
## # A tibble: 6,262 × 5
##       id cd_acordao  comarca data_julgamento                relator
##    <chr>      <chr>    <chr>           <chr>                  <chr>
## 1     33    8221266 Sorocaba      29/01/2015 Alcides Malossi Junior
## 2    136    8211543 Campinas      29/01/2015        Walter da Silva
## 3    174    8211235 Sorocaba      22/01/2015        Walter da Silva
## 4    188    8211081 Sorocaba      29/01/2015        Walter da Silva
## 5    190    8211053 Campinas      29/01/2015        Walter da Silva
## 6    229    8206214 Sorocaba      29/01/2015      Ricardo Tucunduva
## 7    312    8194316 Sorocaba      29/01/2015           Poças Leitão
## 8    354    8193920 Campinas      29/01/2015           Sérgio Ribas
## 9    417    8193329 Campinas      29/01/2015           Poças Leitão
## 10   427    8193274 Sorocaba      29/01/2015           Poças Leitão
## # ... with 6,252 more rows
d_cjsg %>% 
  select(comarca) %>% 
  filter(str_detect(comarca, '^[gG]'))
## # A tibble: 6,463 × 1
##      comarca
##        <chr>
## 1  Guarulhos
## 2  Guarulhos
## 3  Guarulhos
## 4  Guarulhos
## 5      Guará
## 6  Guarulhos
## 7  Guarulhos
## 8  Guarulhos
## 9  Guarulhos
## 10 Guarulhos
## # ... with 6,453 more rows

6.1.7 mutate

  • Parecido com transform, mas aceita várias novas colunas iterativamente.
  • Novas variáveis devem ter o mesmo length que o nrow do bd oridinal ou 1.
library(stringr)
d_cjsg %>% 
  select(id, n_processo, data_julgamento) %>% 
  mutate(ano_julgamento = year(dmy(data_julgamento)),
         ano_proc = str_sub(n_processo, 12, 15),
         ano_proc = as.numeric(ano_proc),
         tempo_anos = ano_julgamento - ano_proc)
## # A tibble: 184,250 × 6
##       id                n_processo data_julgamento ano_julgamento ano_proc
##    <chr>                     <chr>           <chr>          <dbl>    <dbl>
## 1      1 0081568-68.2012.8.26.0050      29/01/2015           2015     2012
## 2      2 2132739-15.2014.8.26.0000      27/01/2015           2015     2014
## 3      3 2204759-04.2014.8.26.0000      27/01/2015           2015     2014
## 4      4 2179832-71.2014.8.26.0000      22/01/2015           2015     2014
## 5      5 2055376-49.2014.8.26.0000      27/01/2015           2015     2014
## 6      6 0014476-05.2014.8.26.0050      29/01/2015           2015     2014
## 7      7 0067859-48.2014.8.26.0000      29/01/2015           2015     2014
## 8      8 0054802-60.2014.8.26.0000      27/01/2015           2015     2014
## 9      9 2128810-71.2014.8.26.0000      29/01/2015           2015     2014
## 10    10 2002343-13.2015.8.26.0000      27/01/2015           2015     2015
## # ... with 184,240 more rows, and 1 more variables: tempo_anos <dbl>

6.1.8 arrange

  • Simplesmente ordena de acordo com as opções.
  • Utilizar desc para ordem decrescente.
library(stringr)
d_cjsg %>% 
  select(id, n_processo, data_julgamento) %>% 
  mutate(ano_julgamento = year(dmy(data_julgamento)),
         ano_proc = str_sub(n_processo, 12, 15),
         ano_proc = as.numeric(ano_proc)) %>% 
  mutate(tempo_anos = ano_julgamento - ano_proc) %>% 
  arrange(desc(tempo_anos))
## # A tibble: 184,250 × 6
##       id                n_processo data_julgamento ano_julgamento ano_proc
##    <chr>                     <chr>           <chr>          <dbl>    <dbl>
## 1   1797 0901097-67.1957.8.26.0050      30/04/2015           2015     1957
## 2  13650 0815784-50.1971.8.26.0050      12/11/2015           2015     1971
## 3   7222 9000001-18.1976.8.26.0309      16/07/2015           2015     1976
## 4   8228 9000001-74.1979.8.26.0224      23/02/2015           2015     1979
## 5   6512 0909882-46.1979.8.26.0050      26/05/2015           2015     1979
## 6   3439 9000001-81.1981.8.26.0005      26/02/2015           2015     1981
## 7   1469 0000014-17.1982.8.26.0292      29/01/2015           2015     1982
## 8  12850 0000784-59.1982.8.26.0114      02/07/2015           2015     1982
## 9   7040 0000019-02.1983.8.26.0584      27/01/2015           2015     1983
## 10  3920 2050003-20.1984.8.26.0281      26/02/2015           2015     1984
## # ... with 184,240 more rows, and 1 more variables: tempo_anos <dbl>

6.1.9 summarise

  • Retorna um vetor de tamanho 1 a partir de uma conta com as variáveis.
  • Geralmente é utilizado em conjunto com group_by.
  • Algumas funções importantes: n(), n_distinct().
d_cjsg %>% 
  select(id, n_processo, comarca, data_julgamento, orgao_julgador) %>% 
  mutate(ano_julgamento = year(dmy(data_julgamento)),
         ano_proc = str_sub(n_processo, 12, 15),
         ano_proc = as.numeric(ano_proc)) %>% 
  mutate(tempo_anos = ano_julgamento - ano_proc) %>% 
  arrange(desc(tempo_anos)) %>% 
  group_by(comarca, orgao_julgador) %>% 
  summarise(n = n(),
            media_anos = mean(tempo_anos),
            min_anos = min(tempo_anos),
            max_anos = max(tempo_anos)) %>% 
  filter(n > 5) %>% 
  arrange(desc(media_anos))
## Source: local data frame [4,351 x 6]
## Groups: comarca [271]
## 
##                  comarca                    orgao_julgador     n
##                    <chr>                             <chr> <int>
## 1                 Piraju 2ª Câmara Criminal Extraordinária     8
## 2         José Bonifácio 6ª Câmara Criminal Extraordinária     6
## 3           Miguelópolis 2ª Câmara Criminal Extraordinária     6
## 4                Piedade 3ª Câmara Criminal Extraordinária     6
## 5               Valinhos 1ª Câmara Criminal Extraordinária     6
## 6       Lençóis Paulista     2ª Câmara de Direito Criminal     8
## 7        Pindamonhangaba 5ª Câmara Criminal Extraordinária     8
## 8           Praia Grande 6ª Câmara Criminal Extraordinária     8
## 9  Santa Bárbara D Oeste 4ª Câmara Criminal Extraordinária     7
## 10             Ituverava 3ª Câmara Criminal Extraordinária     6
## # ... with 4,341 more rows, and 3 more variables: media_anos <dbl>,
## #   min_anos <dbl>, max_anos <dbl>
d_cjsg %>% 
  count(relatora, sort = TRUE) %>% 
  mutate(prop = n / sum(n), prop = scales::percent(prop))
## # A tibble: 111 × 3
##                    relatora     n  prop
##                       <chr> <int> <chr>
## 1             Sérgio Coelho  3424 1.86%
## 2    Miguel Marques e Silva  3352 1.82%
## 3              Poças Leitão  2859 1.55%
## 4           Walter da Silva  2834 1.54%
## 5           Francisco Bruno  2767 1.50%
## 6            Edison Brandão  2748 1.49%
## 7                Souza Nery  2739 1.49%
## 8              Carlos Bueno  2730 1.48%
## 9            Ivo de Almeida  2661 1.44%
## 10 Guilherme de Souza Nucci  2639 1.43%
## # ... with 101 more rows

6.1.10 gather

  • “Empilha” o banco de dados
library(tidyr)
d_cjsg %>% 
  select(cd_acordao:data_registro) %>% 
  gather(key, value, -cd_acordao) %>% 
  arrange(cd_acordao)
## # A tibble: 737,000 × 3
##    cd_acordao             key                     value
##         <chr>           <chr>                     <chr>
## 1     8137574      n_processo 0209050-18.2013.8.26.0000
## 2     8137574         comarca                 São Paulo
## 3     8137574 data_julgamento                22/01/2015
## 4     8137574   data_registro                22/01/2015
## 5     8137600      n_processo 0016319-58.2014.8.26.0000
## 6     8137600         comarca                 São Paulo
## 7     8137600 data_julgamento                22/01/2015
## 8     8137600   data_registro                22/01/2015
## 9     8137628      n_processo 0104838-68.2005.8.26.0050
## 10    8137628         comarca                 São Paulo
## # ... with 736,990 more rows

6.1.11 spread

  • “Joga” uma variável nas colunas
  • É essencialmente a função inversa de gather
d_cjsg %>% 
  distinct(cd_acordao, .keep_all = TRUE) %>% 
  select(cd_acordao:data_registro) %>% 
  gather(key, value, -cd_acordao) %>% 
  spread(key, value)
## # A tibble: 184,249 × 5
##    cd_acordao                  comarca data_julgamento data_registro
## *       <chr>                    <chr>           <chr>         <chr>
## 1     8137574                São Paulo      22/01/2015    22/01/2015
## 2     8137600                São Paulo      22/01/2015    22/01/2015
## 3     8137628                São Paulo      22/01/2015    22/01/2015
## 4     8137638                São Paulo      22/01/2015    22/01/2015
## 5     8137663 Espírito Santo do Pinhal      22/01/2015    22/01/2015
## 6     8137671     Presidente Venceslau      22/01/2015    22/01/2015
## 7     8137677       Paraguaçu Paulista      22/01/2015    22/01/2015
## 8     8137690                Guarulhos      22/01/2015    22/01/2015
## 9     8137695                   Osasco      22/01/2015    22/01/2015
## 10    8137696                Americana      22/01/2015    22/01/2015
## # ... with 184,239 more rows, and 1 more variables: n_processo <chr>

6.1.12 Funções auxiliares

  • unite junta duas ou mais colunas usando algum separador (_, por exemplo).
  • separate faz o inverso de unite, e uma coluna em várias usando um separador.
d_cjsg %>% 
  select(n_processo, classe_assunto) %>% 
  separate(classe_assunto, c('classe', 'assunto'), sep = ' / ', 
           extra = 'merge', fill = 'right') %>% 
  count(assunto, sort = TRUE)
## # A tibble: 287 × 2
##                                               assunto     n
##                                                 <chr> <int>
## 1                  Tráfico de Drogas e Condutas Afins 30993
## 2                                               Roubo 17556
## 3                                      Roubo Majorado 17461
## 4  Crimes de Tráfico Ilícito e Uso Indevido de Drogas 13635
## 5                                   Furto Qualificado 13275
## 6                         Pena Privativa de Liberdade 10801
## 7                                               Furto  9870
## 8                                Progressão de Regime  7068
## 9                                          Receptação  5978
## 10                Crimes do Sistema Nacional de Armas  5675
## # ... with 277 more rows

6.1.13 Um pouco mais de transformação de dados

  • Para juntar tabelas, usar inner_join, left_join, anti_join, etc.
  • Para realizar operações mais gerais, usar do.
  • Para retirar duplicatas, utilizar distinct.