Introdução ao tidyr

O pacote tidyr tem como principal objetivo transformar um data frame para o formato tidy, ou limpo. Segundo a filosofia do tidyverse, um dado limpo é o que apresenta as seguintes propriedades:

  • Cada variável é uma coluna.
  • Cada linha é uma observação.
  • Cada valor é uma célula.
Ilustração de dados no formato tidy

Ilustração de dados no formato tidy

A seguir vamos apresentar dois tibbles. Dê uma olhada e pense qual dos dois está no formato tidy, de acordo com a filosofia tidyverse:

# A tibble: 2 x 3
  uf    `2017` `2018`
  <chr>  <dbl>  <dbl>
1 RJ        10     11
2 SP        11     10
# A tibble: 4 x 3
  uf    Ano   valor
  <chr> <chr> <dbl>
1 RJ    2017     10
2 SP    2017     11
3 RJ    2018     11
4 SP    2018     10

De acordo com a filosofia do pacote, um dado limpo é aquele com formato long, ou seja, com mais linhas. O outro formato é chamado de wide, com mais colunas. No caso deste exemplo, ano é uma variável, logo é necessário existir uma coluna com os valores de ano. O valor relacionado a UF naqueles anos também é outra variável, então precisa de uma coluna pra representá-lo. Além disso, a própria UF precisa de uma coluna.

Todo o pacote dplyr (caso não conheça, veja este tutorial) se baseia na suposição de que o tibble utilizado está no formato tidy.

O tidyr possui duas funções principais:

  • gather: Transforma um tibble wide em long, ou seja, transforma os dados no formato tidy.

  • spread: Transforma um tibble long em wide, ou seja, transforma dados que estão no formato tidy em formato não tidy.

Além disso, existem duas funções que podem ser importantes na nossa análise: separate e unite, que separa uma coluna em duas e vice versa.

Instalação

Podemos instalar o tidyr isoladamente ou instalar todo o tidyverse.

install.packages("tidyverse") # Ou install.packages("tidyr")

require(tidyverse) # ou require(tidyr)

Para este tutorial utilizaremos o pipe e outras funções que são carregadas ao ativar o dplyr. Então, caso tenhamos carregado apenas o tidyr, será necessário também ativar o dplyr.

gather

Vamos criar um tibble no formato wide e transformá-lo em um dado tidy:

dados_wide <- tibble(uf = c("RJ", "SP"), `2017` = c(10, 11), `2018` = c(11, 10))
dados_wide
# A tibble: 2 x 3
  uf    `2017` `2018`
  <chr>  <dbl>  <dbl>
1 RJ        10     11
2 SP        11     10

Por padrão, a função gather irá retornar um tibble com duas colunas, isso se não inserirmos nenhum parâmetro além do tibble. O primeiro parâmetro será o tibble, assim como nas funções do dplyr. Em seguida iremos informar os nomes das duas coluna a serem criadas: key e value (chave e valor). Além disso, podemos selecionar colunas que devam (ou não) ser transformadas para long. Por padrão todas as colunas são consideradas para a transformação. No nosso caso, a coluna uf não deve ser transformada, ou seja, ela deve continuar com "RJ" e "SP", as duas UFs que estão na base de dados. Então vamos informar que essa coluna não deve ser transformada.

dados_wide %>% 
  gather(key = Ano, value = valor, -uf)
# A tibble: 4 x 3
  uf    Ano   valor
  <chr> <chr> <dbl>
1 RJ    2017     10
2 SP    2017     11
3 RJ    2018     11
4 SP    2018     10

Também podemos usar as help functions na hora de selecionar as colunas. Caso não conheça essas funções, veja este outro tutorial. Então o seguinte código retorna o mesmo resultado mostrado acima:

dados_wide %>% 
  gather(key = Ano, value = valor, -contains("uf"))

spread

Agora vamos criar um tibble com o formato long para transformá-lo em wide.

dados_long <- tibble(uf = rep(c("RJ", "SP"), 2), Ano = rep(2017:2018, each = 2), valor = c(10, 11, 11, 10))

dados_long
# A tibble: 4 x 3
  uf      Ano valor
  <chr> <int> <dbl>
1 RJ     2017    10
2 SP     2017    11
3 RJ     2018    11
4 SP     2018    10

Basicamente teremos de informar qual coluna tem os valores que se tornarão colunas e qual a coluna tem os valores que preencherão as novas colunas:

dados_long %>% 
  spread(key = Ano, value = valor)
# A tibble: 2 x 3
  uf    `2017` `2018`
  <chr>  <dbl>  <dbl>
1 RJ        10     11
2 SP        11     10

Perceba que se dermos um gather nesse tibble resultante, voltaremos a obter dados_long.

unite e separate

Suponha que aquele primeiro tibble, no começo deste tutorial, ao invés de ter 2017 e 2018 como nomes de colunas, tivesse os nomes valor_2017 e valor_2018.

dados_wide
# A tibble: 2 x 3
  uf    valor_2017 valor_2018
  <chr>      <dbl>      <dbl>
1 RJ            10         11
2 SP            11         10

Dessa maneira, ao fazermos o gather, nossa coluna ano ficará da seguinte maneira:

dados_wide %>% 
  gather(Ano, valor, -uf)
# A tibble: 4 x 3
  uf    Ano        valor
  <chr> <chr>      <dbl>
1 RJ    valor_2017    10
2 SP    valor_2017    11
3 RJ    valor_2018    11
4 SP    valor_2018    10

Temos, então, que remover esse prefixo “valor_”, para que o tibble tenha apenas o ano, de fato. Existem várias maneiras de fazer isso, mas usaremos aqui a função separate, além do select para terminar de resolver nosso problema. Passaremos como argumentos para a função separate o tibble gerado acima (data), o nome da coluna que queremos separar (col), as colunas que serão criadas com a separação de col (into) e o padrão que deve separar o conteúdo de col (sep). O argumento sep é interpretado como uma expressão regular (regex). No nosso caso, o separador é um underline.

dados_separate <- dados_wide %>% 
  gather(Ano, valor, -uf) %>% 
  separate(col = Ano, into = c("val", "Ano2"))

dados_separate
# A tibble: 4 x 4
  uf    val   Ano2  valor
  <chr> <chr> <chr> <dbl>
1 RJ    valor 2017     10
2 SP    valor 2017     11
3 RJ    valor 2018     11
4 SP    valor 2018     10

Nessa situação a coluna val não tem valor pra gente, então vamos descartá-la com o select. Também vamos chamar Ano2 de Ano, apenas:

dados_separate %>% 
  select(uf, Ano = Ano2, valor)
# A tibble: 4 x 3
  uf    Ano   valor
  <chr> <chr> <dbl>
1 RJ    2017     10
2 SP    2017     11
3 RJ    2018     11
4 SP    2018     10

Suponha agora que tenhamos duas colunas que desejamos juntar em apenas uma. Para isso utilizamos a função unite. Vamos juntar novamente o prefixo “valor_” com o ano. O primeiro argumento da função é o tibble. Em seguida passamos o nome da nova coluna (col), que será a junção de outras colunas. Além disso precisamos informar os nomes das colunas que serão unidas (...) e o caractere que será utilizado para separar as informações das colunas (sep). Vamos, então, unir as colunas val e Ano2 na coluna Ano.

dados_separate %>% 
  unite(col = Ano, val, Ano2, sep = "_")
# A tibble: 4 x 3
  uf    Ano        valor
  <chr> <chr>      <dbl>
1 RJ    valor_2017    10
2 SP    valor_2017    11
3 RJ    valor_2018    11
4 SP    valor_2018    10