title | author | date | editor | reviewers | translator | translation-editor | translation reviewer | difficulty | collection | activity | topics | abstract | layout | review-ticket | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Manipulação e controle de dados no R |
|
2017-08-01 |
|
|
|
|
|
2 |
lessons |
transforming |
|
This tutorial explores how scholars can organize 'tidy' data, understand R packages to manipulate data, and conduct basic data analysis. |
lesson |
60 |
Nesta lição assumimos que você possui algum conhecimento da linguagem R. Se ainda não completou a lição "R Basics with Tabular Data", recomendamos que o faça primeiro. Ter experiência com outras linguagens de programação também pode ser útil. Se está buscando por onde começar, recomendamos os excelentes tutoriais de Python do Programming Historian.
Ao fim desta lição, você:
- Saberá como tornar seus dados bem ordenados (tidy) e entenderá por que isso é importante
- Terá assimilado o uso do pacote dplyr e sua aplicação na manipulação e controle de dados
- Estará familiarizado com o operador pipe
%>%
na linguagem R e verá como ele pode auxiliar na criação de códigos mais legíveis - Terá ganho experiência com análise exploratória de dados através de exemplos básicos de manipulação de dados.
Os dados que você encontra disponíveis em todo lugar raramente estão em formato adequado para serem analisados, e você precisará manipulá-los antes de explorar as perguntas que o interessa. Isso pode tomar mais tempo que a própria análise dos dados! Neste tutorial, vamos aprender técnicas básicas para manipulação, gestão e controle de dados usando R. Especificamente, nos debruçaremos sobre a filosofia do "tidy data" conforme articulada por Hadley Wickham.
De acordo com Wickham, os dados estão tidy ou bem-organizados quando satisfazem três critérios chave:
- Cada unidade de observação está em uma linha
- Cada variável está em uma coluna
- Cada valor possui sua própria célula.
Estar atento a estes critérios nos permite reconhecer quando nossos dados estão adequados ou não. Também nos fornece um esquema padrão e um conjunto de soluções para lidar com alguns dos problemas mais comuns encontrados em datasets "mal-arranjados", como por exemplo:
- Nomes de colunas como valores ao invés de nomes de variáveis
- Múltiplas variáveis contidas em uma única coluna
- Variáveis armazenadas tanto em linhas quanto em colunas
- Unidades de observação de diferentes categorias armazenadas na mesma tabela
- Uma única unidade de observação armazenada em múltiplas tabelas.
Talvez o mais importante seja que manter os dados nesse formato nos permite utilizar uma série de pacotes do "tidyverse,", concebidos para trabalhar especificamente com dados neste formato tidy. Dessa forma, assegurando-nos de que os dados de entrada e de saída estão bem organizados, precisaremos apenas de um pequeno conjunto de ferramentas para resolver um grande número de questões. Podemos combinar, manipular e dividir os datasets que criamos, conforme considerarmos mais adequado.
Neste tutorial focaremos no pacote dplyr presente no tidyverse, mas é importante mencionar alguns outros que serão vistos na lição:
- magittr -- Este pacote nos garante acesso ao operador pipe
%>%
, que torna nosso código mais legível. - ggplot2 -- Este pacote utiliza a "Gramática de Gráficos"[1] para fornecer uma forma fácil de visualizar nossos dados.
- tibble -- Este pacote nos fornece uma releitura dos tradicionais data frames, mais fáceis de serem trabalhados e visualizados.
Você deve instalar o "tidyverse", se ainda não o fez, e carregá-lo antes de começarmos. Além disso, certifique-se de que possui instaladas a versão mais recente do R e a versão mais recente do RStudio compatíveis com o seu sistema operacional.
Copie o código a seguir em seu RStudio. Para executá-lo, você precisa selecionar as linhas e pressionar Ctrl+Enter (Command+Enter no Mac OS):
# Instala e carrega a biblioteca tidyverse
# Não se preocupe caso demore um pouco
install.packages("tidyverse")
library(tidyverse)
Vejamos um exemplo de como o dplyr pode auxiliar historiadores. Vamos utilizar o pacote "dados"[2] e importar alguns indicadores socioeconômicos de países entre 1952 e 2007.
O pacote "remotes" permite a instalação de pacotes R a partir de repositórios remotos, incluindo o GitHub, como é o caso de "dados".
# Instala e carrega as bibliotecas "remotes" e "dados"
install.packages("remotes")
library(remotes)
remotes::install_github("cienciadedatos/dados")
library(dados)
Em seguida, para termos acesso ao dataset "dados_gapminder" que se encontra no pacote "dados", basta executar o seguinte código:
# Cria o objeto dados_socioeconomicos_paises e atribui a ele os elementos de dados_gapminder
dados_socioeconomicos_paises <- dados_gapminder
Os dados Gapminder contêm a progressão de países ao longo do tempo, observando as estatísticas de alguns índices. Após importar o dataset, você notará que ele possui seis variáveis: país, continente, ano, expectativa de vida, população e PIB per capita. Os dados já estão em um formato tidy, possibilitando uma infinidade de opções para exploração futura.
Neste exemplo, vamos visualizar o crescimento populacional de Brasil e Argentina ao longo dos anos. Para isso utilizaremos o pacote dplyr a fim de filtrar os dados que contenham apenas informação dos países de nosso interesse. Em seguida, empregaremos o ggplot2 para visualizar tais dados. Este exercício é apenas uma breve demonstração do que é possível fazer com o dplyr, portanto, não se preocupe se você não entender o código por enquanto.
# Filtra os países desejados (Brasil e Argentina)
dados_brasil_argentina <- dados_socioeconomicos_paises %>%
filter(pais %in% c("Brasil", "Argentina"))
# Visualiza a população dos dois países
ggplot(data = dados_brasil_argentina, aes(x = ano, y = populacao, color = pais)) +
geom_line() +
geom_point()
{% include figure.html filename="img/brasil_argentina_populacao.png" caption="Gráfico da população de Brasil e Argentina, ao longo dos anos" %}
Como podemos observar, a população absoluta do Brasil é consideravelmente maior em comparação com a população da Argentina. Embora isso pareça óbvio devido ao tamanho do território brasileiro, o código nos fornece uma base sobre a qual podemos formular uma infinidade de questões similares. Por exemplo, com uma pequena mudança no código podemos criar um gráfico similar com dois países diferentes, como Portugal e Bélgica.
# Filtra os países desejados (Portugal e Bélgica)
dados_portugal_belgica <- dados_socioeconomicos_paises %>%
filter(pais %in% c("Portugal", "Bélgica"))
# Visualiza a população dos dois países
ggplot(data = dados_portugal_belgica, aes(x = ano, y = populacao, color = pais)) +
geom_line() +
geom_point()
{% include figure.html filename="img/portugal_belgica_populacao" caption="Gráfico da população de Portugal e Bégica, ao longo dos anos" %}
Promover mudanças rápidas no código e reanalisar nossos dados é parte fundamental da análise exploratória de dados (AED). Ao invés de tentar "provar" uma hipótese, a análise exploratória nos ajuda a entender melhor os dados e a levantar questões sobre eles. Para os historiadores, a AED fornece um meio fácil de saber quando se aprofundar mais em um tema e quando voltar atrás, e esta é uma área onde o R se sobressai.
Antes de olharmos para o dplyr, precisamos entender o que é o operador pipe %>%
no R, uma vez que iremos utilizá-lo em muitos exemplos adiante. Como mencionado anteriormente, este operador é parte do pacote magrittr, criada por Stefan Milton Bache e Hadley Wickham, e está incluída no tidyverse. Seu nome é uma referência ao pintor surrealista Rene Magritte, criador da obra "A Traição das Imagens", que mostra um cachimbo com a frase "isto não é um cachimbo" (ceci n'est pas une pipe, em francês).
O operador pipe %>%
permite que você passe o que está à sua esquerda como a primeira variável em uma função especificada à sua direita. Embora possa parecer estranho no início, uma vez que você aprenda a usar o pipe descobrirá que ele torna seu código mais legível, evitando instruções aninhadas. Não se preocupe se estiver um pouco confuso por agora. Tudo ficará mais claro à medida que observarmos os exemplos.
Vamos dizer que estamos interessados em obter a raiz quadrada de cada população e, então, somar todas as raízes antes de calcular a média. Obviamente, essa não é uma medição útil, mas demonstra a rapidez com que o código R pode se tornar difícil de ler. Normalmente, usaríamos declarações aninhadas:
mean(sum(sqrt(dados_socioeconomicos_paises$populacao)))
## [1] 6328339
Veja que com tantos comandos aninhados fica difícil lembrar de quantos parênteses você precisa no final, tornando o código complicado de ler. Para atenuar esse problema, algumas pessoas criam vetores temporários entre cada chamada de função.
# Obtém a raiz quadrada da população de todos os países
vetor_raiz_populacao <- sqrt(dados_socioeconomicos_paises$populacao)
# Obtém a soma de todas as raízes da variável temporária
soma_vetor_raizes_populacao <- sum(vetor_raiz_populacao)
# Obtém a média da variável temporária
media_soma_vetor_raizes_populacao <- mean(soma_vetor_raizes_populacao)
# Exibe a média
media_soma_vetor_raizes_populacao
## [1] 6328339
Embora você obtenha o mesmo resultado, este código é muito mais legível. No entanto, se você esquecer de excluir os vetores temporários, seu espaço de trabalho pode se tornar confuso. O operador pipe faz esse trabalho por você. Aqui está o mesmo código usando o operador pipe:
dados_socioeconomicos_paises$populacao %>% sqrt %>% sum %>% mean
## [1] 6328339
Este código é mais fácil de ler que os anteriores e você pode torná-lo ainda mais limpo escrevendo em linhas diferentes.
# Certifique-se de colocar o operador ao final da linha
dados_socioeconomicos_paises$populacao %>%
sqrt %>%
sum %>%
mean
## [1] 6328339
Note que os vetores ou data frames criados pelo operador pipe são descartados quando se completa a operação. Se você quiser salvar o resultado da operação, será preciso atribuí-lo a uma nova variável:
vetor_permanente_media_soma_populacao <- dados_socioeconomicos_paises$populacao %>%
sqrt %>%
sum %>%
mean
vetor_permanente_media_soma_populacao
## [1] 6328339
Agora que adquirimos uma compreensão do operador pipe, estamos prontos para começar a analisar e manipular alguns dados. Ao longo da lição vamos continuar trabalhando com os dados_gapminder:
# Certifique-se de que o pacote "dados" está instalado e carregado antes de proceder abaixo
dados_gapminder
## # A tibble: 1,704 x 6
## pais continente ano expectativa_de_vida populacao pib_per_capita
## <fct> <fct> <int> <dbl> <int> <dbl>
## 1 Afeganistão Ásia 1952 28.8 8425333 779.
## 2 Afeganistão Ásia 1957 30.3 9240934 821.
## 3 Afeganistão Ásia 1962 32.0 10267083 853.
## 4 Afeganistão Ásia 1967 34.0 11537966 836.
## 5 Afeganistão Ásia 1972 36.1 13079460 740.
## 6 Afeganistão Ásia 1977 38.4 14880372 786.
## 7 Afeganistão Ásia 1982 39.9 12881816 978.
## 8 Afeganistão Ásia 1987 40.8 13867957 852.
## 9 Afeganistão Ásia 1992 41.7 16317921 649.
## 10 Afeganistão Ásia 1997 41.8 22227415 635.
## # … with 1,694 more rows
Como você pode observar, este dataset contém o nome do país, seu continente e o ano de registro, além dos indicadores de expectativa de vida, total da população e PIB per capita dos determinados anos. Conforme mencionamos acima, antes de analisar os dados é importante verificar se estes estão bem ordenados no formato tidy. Relembrando os três critérios discutidos, podemos dizer que sim, o dataset encontra-se organizado e pronto para ser trabalhado com o pacote dplyr.
Dplyr também é parte do tidyverse, fornecendo funções para manipulação e tranformação dos dados. Porque estamos mantendo nossos dados bem organizados, precisaremos apenas de um pequeno conjunto de ferramentas para explorá-los. Em comparação com o pacote básico do R, usando o dplyr nosso código fica geralmente mais rápido, e há a garantia de que os dados resultantes (output) estarão bem ordenados uma vez que os dados de entrada (input) também estarão. Talvez o mais importante seja que o dplyr torna nosso código mais fácil de ser lido e utiliza "verbos" que são, na maioria das vezes, intuitivos. Cada função do dplyr corresponde a um desses verbos, sendo cinco principais: filtrar (filter
), selecionar (select
), ordenar (arrange
), modificar (mutate
) e sumarizar (summarise
). Vamos observar individualmente como cada uma dessas funções funciona na prática.
Se olharmos para dados_gapminder, vamos observar a presença de seis colunas, cada uma contendo diferentes informações. Podemos escolher, para nossa análise, visualizar apenas algumas dessas colunas. A função select()
do dplyr nos permite fazer isso. O primeiro argumento da função é o data frame que desejamos manipular e os seguintes são os nomes das colunas que queremos manter:
# Remove as colunas de dados_gapminder usando select()
# Note que não é necessário acrescentar o nome da coluna com o símbolo $ (dólar) ao final de dados_gapminder visto que o dplyr automaticamente assume que "," (vírgula) representa E (AND em inglês)
select(dados_gapminder, pais, ano, expectativa_de_vida)
## # A tibble: 1,704 x 3
## pais ano expectativa_de_vida
## <fct> <int> <dbl>
## 1 Afeganistão 1952 28.8
## 2 Afeganistão 1957 30.3
## 3 Afeganistão 1962 32.0
## 4 Afeganistão 1967 34.0
## 5 Afeganistão 1972 36.1
## 6 Afeganistão 1977 38.4
## 7 Afeganistão 1982 39.9
## 8 Afeganistão 1987 40.8
## 9 Afeganistão 1992 41.7
## 10 Afeganistão 1997 41.8
## # … with 1,694 more rows
Vejamos como escrever o mesmo código utilizando o operador pipe %>%
:
dados_gapminder %>%
select(pais, ano, expectativa_de_vida)
## # A tibble: 1,704 x 3
## pais ano expectativa_de_vida
## <fct> <int> <dbl>
## 1 Afeganistão 1952 28.8
## 2 Afeganistão 1957 30.3
## 3 Afeganistão 1962 32.0
## 4 Afeganistão 1967 34.0
## 5 Afeganistão 1972 36.1
## 6 Afeganistão 1977 38.4
## 7 Afeganistão 1982 39.9
## 8 Afeganistão 1987 40.8
## 9 Afeganistão 1992 41.7
## 10 Afeganistão 1997 41.8
## # … with 1,694 more rows
Fazer referência a cada uma das colunas que desejamos manter apenas para nos livrar de uma é um tanto tedioso. Podemos usar o símbolo de menos (-) para demonstrar que queremos remover uma coluna.
dados_gapminder %>%
select(-continente)
## # A tibble: 1,704 x 5
## pais ano expectativa_de_vida populacao pib_per_capita
## <fct> <int> <dbl> <int> <dbl>
## 1 Afeganistão 1952 28.8 8425333 779.
## 2 Afeganistão 1957 30.3 9240934 821.
## 3 Afeganistão 1962 32.0 10267083 853.
## 4 Afeganistão 1967 34.0 11537966 836.
## 5 Afeganistão 1972 36.1 13079460 740.
## 6 Afeganistão 1977 38.4 14880372 786.
## 7 Afeganistão 1982 39.9 12881816 978.
## 8 Afeganistão 1987 40.8 13867957 852.
## 9 Afeganistão 1992 41.7 16317921 649.
## 10 Afeganistão 1997 41.8 22227415 635.
## # … with 1,694 more rows
A função filter()
faz o mesmo que a função select, mas ao invés de escolher o nome da coluna, podemos usá-lo para filtrar linhas usando um teste de requisito. Por exemplo, se quisermos selecionar somente os registros dos países em 2007:
dados_gapminder %>%
filter(ano == 2007)
## # A tibble: 142 x 6
## pais continente ano expectativa_de_vida populacao pib_per_capita
## <fct> <fct> <int> <dbl> <int> <dbl>
## 1 Afeganistão Ásia 2007 43.8 31889923 975.
## 2 Albânia Europa 2007 76.4 3600523 5937.
## 3 Argélia África 2007 72.3 33333216 6223.
## 4 Angola África 2007 42.7 12420476 4797.
## 5 Argentina Américas 2007 75.3 40301927 12779.
## 6 Austrália Oceania 2007 81.2 20434176 34435.
## 7 Áustria Europa 2007 79.8 8199783 36126.
## 8 Bahrein Ásia 2007 75.6 708573 29796.
## 9 Bangladesh Ásia 2007 64.1 150448339 1391.
## 10 Bélgica Europa 2007 79.4 10392226 33693.
## # … with 132 more rows
A função mutate()
permite adicionar uma coluna ao seu dataset. No momento, temos país e continente em duas colunas separadas. Podemos utilizar a função paste()
para combinar as duas informações e especificar um separador. Vamos colocá-las em uma única coluna chamada "localizacao".
dados_gapminder %>%
mutate(localizacao = paste(pais, continente, sep = ", "))
## # A tibble: 1,704 x 7
## pais continente ano expectativa_de_vida populacao pib_per_capita localizacao
## <fct> <fct> <int> <dbl> <int> <dbl> <chr>
## 1 Afeganistão Ásia 1952 28.8 8425333 779. Afeganistão, Ásia
## 2 Afeganistão Ásia 1957 30.3 9240934 821. Afeganistão, Ásia
## 3 Afeganistão Ásia 1962 32.0 10267083 853. Afeganistão, Ásia
## 4 Afeganistão Ásia 1967 34.0 11537966 836. Afeganistão, Ásia
## 5 Afeganistão Ásia 1972 36.1 13079460 740. Afeganistão, Ásia
## 6 Afeganistão Ásia 1977 38.4 14880372 786. Afeganistão, Ásia
## 7 Afeganistão Ásia 1982 39.9 12881816 978. Afeganistão, Ásia
## 8 Afeganistão Ásia 1987 40.8 13867957 852. Afeganistão, Ásia
## 9 Afeganistão Ásia 1992 41.7 16317921 649. Afeganistão, Ásia
## 10 Afeganistão Ásia 1997 41.8 22227415 635. Afeganistão, Ásia
## # … with 1,694 more rows
Novamente, é preciso lembrar que o dplyr não salva os dados nem transforma o original. Em vez disso, ele cria um data frame temporário em cada etapa. Se você deseja manter os dados, é necessário criar uma variável permanente.
dados_gapminder_localizacao <- dados_gapminder %>%
mutate(localizacao = paste(pais, continente, sep = ", "))
# Visualiza a nova tabela criada com a localização adicionada
dados_gapminder_localizacao
## # A tibble: 1,704 x 7
## pais continente ano expectativa_de_vida populacao pib_per_capita localizacao
## <fct> <fct> <int> <dbl> <int> <dbl> <chr>
## 1 Afeganistão Ásia 1952 28.8 8425333 779. Afeganistão, Ásia
## 2 Afeganistão Ásia 1957 30.3 9240934 821. Afeganistão, Ásia
## 3 Afeganistão Ásia 1962 32.0 10267083 853. Afeganistão, Ásia
## 4 Afeganistão Ásia 1967 34.0 11537966 836. Afeganistão, Ásia
## 5 Afeganistão Ásia 1972 36.1 13079460 740. Afeganistão, Ásia
## 6 Afeganistão Ásia 1977 38.4 14880372 786. Afeganistão, Ásia
## 7 Afeganistão Ásia 1982 39.9 12881816 978. Afeganistão, Ásia
## 8 Afeganistão Ásia 1987 40.8 13867957 852. Afeganistão, Ásia
## 9 Afeganistão Ásia 1992 41.7 16317921 649. Afeganistão, Ásia
## 10 Afeganistão Ásia 1997 41.8 22227415 635. Afeganistão, Ásia
## # … with 1,694 more rows
A função arrange()
nos permite ordenar as colunas de novas formas. Atualmente, nosso conjunto de dados está organizado em ordem alfabética pelo nome do país. Vamos ordená-lo em ordem decrescente de acordo com o total da população.
dados_gapminder %>%
arrange(desc(populacao))
## # A tibble: 1,704 x 6
## pais continente ano expectativa_de_vida populacao pib_per_capita
## <fct> <fct> <int> <dbl> <int> <dbl>
## 1 China Ásia 2007 73.0 1318683096 4959.
## 2 China Ásia 2002 72.0 1280400000 3119.
## 3 China Ásia 1997 70.4 1230075000 2289.
## 4 China Ásia 1992 68.7 1164970000 1656.
## 5 Índia Ásia 2007 64.7 1110396331 2452.
## 6 China Ásia 1987 67.3 1084035000 1379.
## 7 Índia Ásia 2002 62.9 1034172547 1747.
## 8 China Ásia 1982 65.5 1000281000 962.
## 9 Índia Ásia 1997 61.8 959000000 1459.
## 10 China Ásia 1977 64.0 943455000 741.
## # … with 1,694 more rows
A última função do dplyr que veremos é a summarise()
, usada geralmente para criar uma tabela contendo dados estatísticos resumidos que podemos plotar. Vamos utilizar a função summarise()
para calcular a média da expectativa de vida dos países, considerando todo o conjunto de dados_gapminder.
dados_gapminder %>%
summarise(mean(expectativa_de_vida))
## # A tibble: 1 x 1
## `mean(expectativa_de_vida)`
## <dbl>
## 1 59.5
Agora, após termos visto os cinco principais verbos do dplyr, podemos criar rapidamente uma visualização dos nossos dados. Vamos criar um gráfico de barras mostrando o número de países com expectativa de vida maior que 50 anos, em 2007.
expectativa_vida_2007 <- dados_gapminder %>%
filter(ano == 2007) %>%
mutate(expectativa_2007 = ifelse(expectativa_de_vida >= 50, "Maior ou igual a 50 anos", "Menor que 50 anos"))
ggplot(expectativa_vida_2007) +
geom_bar(aes(x = expectativa_2007, fill = expectativa_2007)) +
labs(x = "A expectativa de vida é maior que 50 anos?")
{% include figure.html filename="img/expectativa_vida_2007.png" caption="Expectativa de vida nos países em 2007" %}
Novamente, fazendo uma pequena mudança em nosso código, podemos ver também o número de países com expectativa de vida maior que 50 anos, em 1952.
expectativa_vida_1952 <- dados_gapminder %>%
filter(ano == 1952) %>%
mutate(expectativa_1952 = ifelse(expectativa_de_vida >= 50, "Maior ou igual a 50 anos", "Menor que 50 anos"))
ggplot(expectativa_vida_1952) +
geom_bar(aes(x = expectativa_1952, fill = expectativa_1952)) +
labs(x = "A expectativa de vida é maior que 50 anos?")
({% include figure.html filename="img/expectativa_vida_1952.png" caption="Expectativa de vida nos países em 1952" %}
Este tutorial deve encaminhar seus conhecimentos para pensar sobre como organizar e manipular dados usando R. Posteriormente, você provavelmente vai querer visualizar esses dados de alguma forma, usando gráficos, como fizemos em partes desta lição. Recomendamos que comece a estudar o ggplot2, pacote com uma coleção de ferramentas que funcionam bem em conjunto com o dplyr. Além disso, você deve buscar conhecer as outras funções do pacote dplyr que não vimos aqui, para aprimorar suas habilidades de manipulação de dados. Por enquanto, esta lição deve proporcionar um bom ponto de partida, cobrindo muitos dos principais problemas que você irá encontrar.
-
A lição original faz referência ao livro “The Grammar of Graphics” (2005) de Wilkinson]. ↩
-
O pacote "dados" disponibiliza a tradução de conjuntos de dados originalmente em inglês encontrados em outros pacotes de R. Está disponível em https://github.com/cienciadedatos/dados ↩