[Parte 1] — 7 Passos para Manipulação de Dados com dplyr

Fernando Gama
8 min readDec 10, 2018

--

Neste tutorial tentarei ajudá-lo a aprender ou mesmo desmistificar a biblioteca dplyr de forma objetiva e prática. A minha proposta aqui será objetiva porque faremos um passo a passo sem rodeios e, prática porque você poderá replicar esse código ao longo da leitura desse artigo. Vale destacar que iremos tratar apenas de um subconjunto de possibilidades (Parte 1), afinal a biblioteca é bastante rica em funcionalidades.

Antes de começarmos, é necessário (ou recomendável) que essas ferramentas/bibliotecas estejam previamente instaladas em sua máquina.

  1. MySQL e/ou MySQL Workbench
  2. Ambiente R
  3. RStudio (IDE)

Objetivo: Conectar o R a um arquivo CSV e também ao MySQL para extrair dados de uma tabela e realizar manipulações via dplyr.

Configurações iniciais:

- Instalação dos pacotes: nós precisaremos apenas de dois pacotes que podem ser instalados dentro do R utilizando os comandos:

install.packages(“dplyr”)
install.packages(“RMySQL”)

- Download dos arquivos: neste tutorial utilizaremos uma mesma base de dados (vendas de games).

  1. CSV: <https://github.com/ffgama/datasets/blob/master/games.csv>
  2. SQL: <https://github.com/ffgama/datasets/blob/master/games.sql> ou você poderá criar uma base de dados no MySQL e importar o CSV.
  • Descrição da base: a base de dados foi extraída originalmente de uma competição de análise na plataforma Kaggle e possui registros de vendas de videogames.
  • Dicionário de dados: a descrição das features é apresentada logo abaixo.
Dicionário de dados da base games

PASSO 1: Extração e Transformação dos dados brutos.

# coletar os dados
extract_data <- read.csv(“
https://raw.githubusercontent.com/ffgama/datasets/master/games.csv", header = TRUE, sep=”,”)
#
estrutura do dataset
str(extract_data)

Console:

Estrutura do dataset (dimensão 16598 x 11)

Para simplificar, trabalharemos apenas com as primeiras 500 instâncias do dataset. E em seguida aplicaremos uma transformação delegando à função apply(), que ficará encarregada de inserir uma coluna com a soma acumulativa do total de vendas globais — repetiremos esse processo quando via dplyr e RMySQL.

# coletar apenas as primeiras 500 instâncias
dataset_game<- extract_data[1:500,]
# criando nova coluna
dataset_game <- data.frame(dataset_game, Global_Sales_Acc = apply(as.matrix(dataset_game$Global_Sales), 2, cumsum))
head(dataset_game)

Console:

Primeiras 6 linhas do dataset após a transformação

PASSO 2: Carga e exploração do pacote dplyr.

# carga do pacote
library(dplyr)
#
resumo estatístico das features
dataset_game %>% head() %>% summary()

Uma vez que o pacote dplyr esteja instalado, carregamos dentro do ambiente e em seguida aplicamos a primeira operação. Observe a presença do operador pipe %>%. Por meio deste operador, podemos executar uma série de funções em sequência. A partir do código, você faz a seguinte leitura: “O objeto (dataset_game) que armazena o meu conjunto de dados é entregue à função head() para que as primeiras 6 instâncias sejam extraídas e, que, posteriormente sejam entregues a função summary() que imprimirá como resultado o resumo estatístico das features.”

Ou seja, não precisamos, por exemplo, guardar as 6 primeiras linhas em um objeto para depois aplicar alguma outra função. Tampouco, passar o objeto para dentro das funções. Portanto, essa sequência de operações em cascata além de tornar o código mais limpo, permite que realizemos inúmeras operações de forma mais eficiente. Observe o resultado abaixo.

Console:

Resumo estatístico das features (apenas das 6 primeiras instâncias) via dplyr

PASSO 3: Comando FILTER:

# filtro em um conjunto de instâncias onde o fabricante seja a Nintendo com vendas na Europa igual ou superior a 5 milhões no ano de 2006.
filter(dataset_game, Publisher == “Nintendo”, EU_Sales >= 5 & Year == 2006)

Console:

Resultado após a aplicação da função filter().

Uma outra alternativa para filtrar dados com range de valores é optar pelo operador %in%, conforme abaixo:

# filtro em um conjunto de instâncias que contenham registros de vendas da Fabricante Nintendo cujo ano seja 2014, 2015 e 2016.
filter(dataset_game, Publisher == “Nintendo”, Year %in% c(2014:2016))

Console:

Resultado de vendas da Nintendo entre 2014 a 2016. Este último ano, não teve registros conforme mostra o resultado do nosso dataset.

PASSO 3: Comando SELECT:

# selecionar apenas um conjunto de colunas que sejam de interesse, neste caso: Publisher, Genre e Global_Sales.
select_game <- select(dataset_game, Publisher, Genre, Global_Sales)
head(select_game)

O comando select é bastante intuitivo você passa o objeto e em seguida as colunas que você deseja manter.

Console:

As 3 colunas retornadas do comando select.

Podemos também fatiar o nosso conjunto de dados utilizando o slice() e utilizar o operador (:) para buscar um range de colunas do nosso interesse, conforme o script abaixo:

# fatiando o conjunto de dados recuperando as 15 primeiras linhas e retornando as colunas desejadas (Nome até Fabricante).
slice_game <- slice(select(dataset_game, Name:Publisher), 1:15)
slice_game

Console:

Resultado após o slice.

Em casos onde aparecerem colunas, dentro do intervalo acima, que talvez desejamos excluir, podemos utilizar o operador (-), conforme o script abaixo:

# removendo a coluna plataforma
game_slice <- slice(select(slice_game, -(Platform)))
game_slice

Console:

Compare com a imagem anterior e note que a coluna Platform, de fato, foi removida.

Por fim é possível aplicar as funções filter() e select() conjuntamente:

# combinando filter e select. As colunas: Name, Publisher e Global_Sales são selecionadas e em seguida aplica-se um filtro para selecionar apenas o total de vendas globais acima de 15 milhões.
filter(select(dataset_game, Name, Publisher, Global_Sales), Global_Sales>=15)

Console:

Resultado obtido após a combinação de filter e select

Como vimos, o pipe (%>%) pode ser útil quando desejamos encadear o resultado de uma função com outra. Nos exemplos acima criamos dois objetos (select_game e slice_game). Isso poderia ter sido evitado se utilizássemos a estrutura que apresentamos no PASSO 2. Observe:

# mesmo resultado da última figura
dataset_game %>%
select(Name, Publisher, Global_Sales) %>%
filter(Global_Sales >= 15)

Confronte o resultado deste comando com a última figura. Ficou convencido com a praticidade da notação? ;) Vamos seguir com ela então?

NOTA: A ordem que você passa como argumento para o select é considerada ou respeitada pelo dplyr. OK?

PASSO 4: Comando ARRANGE:

# ordenando os resultados pelo valor total de vendas
dataset_game %>%
select(Name, Publisher, Global_Sales) %>%
filter(Global_Sales >= 15) %>%
arrange(Global_Sales)

Observe que apenas adicionamos a função arrange para ordenar os resultados — Sim, não se surpreenda com algumas similaridades com operações DML do SQL.

Console:

Ordem crescente (defatult) da função arrange.

Por default o arrange ordena por ordem crescente. Se quisermos ordenar por ordem decrescente é possível utilizar o comando desc().

arrange(desc(Global_Sales))

PASSO 5: Comando MUTATE:

# criando colunas a partir de outras colunas
dataset_game %>%
# colunas de interesse
select(Name, Year, Global_Sales) %>%
# vendas globais acima de 20 milhões
filter(Global_Sales >= 20) %>%
# decrescente
arrange(desc(Global_Sales)) %>%
# cria duas colunas a partir das colunas existentes
mutate(Short_Year = substring(Year, 3,4), Sales_Acc = cumsum(Global_Sales))

O comando mutate() permite a criação de novas colunas a partir de colunas já existentes. Selecionamos algumas colunas (Name, Year, Global_Sales) em seguida aplicamos um filtro na coluna Global_Sales e depois ordenamos essas vendas na forma decrescente. Por fim, aplicamos o comando mutate para criar duas novas colunas, passsando:

  1. Short_Year: coleta dentro da string (Year) a 3ª e 4ª posição, ou seja, pretendo extrair o ano abreviado (por ex., 2016 seria igual a 06).
  2. Sales_Acc: soma acumulada das vendas globais (tal como fizemos no PASSO 1), porém, dessa vez, empregando o dplyr.

Console:

Novas colunas criadas utilizando o mutate.

PASSO 6: Comando GROUP BY:

# group_by
dataset_game %>%
# colunas de interesse
select(Name, Year, Publisher, Global_Sales) %>%
# vendas globais acima de 20 milhões
filter(Global_Sales >= 20) %>%
# decrescente
arrange(desc(Global_Sales)) %>%
# cria duas colunas a partir das colunas existentes
mutate(Sales_Acc = cumsum(Global_Sales)) %>%
# agrupando por Fabricante
group_by(Publisher) %>%
# soma acumulada por Fabricante
summarise(Tot_Acc_Publisher = sum(Global_Sales))

Aqui, realizamos o mesmo processo que os passos anteriores com algumas pequenas modificações para facilitar a visualização dos resultados no console. O comando group_by(), além de conhecido para quem manipula dados no SQL, é bem intuitivo. No nosso exemplo estamos agrupando os resultados por fabricante e logo em seguida, armazenando a soma total de vendas para cada fabricante. Observe o resultado.

Console:

Total acumulado de vendas por fabricante.

NOTA: Não estranhe ao notar o termo “tibble”. Trata-se de um tipo de dataframe adaptável a lidar com grandes conjuntos de dados. Também pode ser compreendido como uma forma otimizada de exibir dados, de forma resumida, no console.

PASSO 7: Conectando ao MySQL:

# carga do pacote
library(RMySQL)
# abrindo a conexão com o servidor de banco de dados
con <- dbConnect(MySQL(), db=”games”, user=”root”, password=”1234", host=”localhost”)
# retornando as tabelas desse banco de dados
dbListTables(con, “games”)

Como último passo podemos conectar o R diretamente ao MySQL passando como parâmetro para dbConnect(): o driver de conexão, o nome do banco de dados, usuário, senha e o host. Em seguida, pedimos para listar todas as tabelas presentes no banco e, assim, ele retornará apenas uma única tabela — que é o dataset que estamos trabalhando agora e que você certamente importou para dentro do MySQL (conforme sugerido no início deste tutorial).

# manipulando os dados da tabela como um dataframe
dataset_games <- dbReadTable(con, “vgsales”)
dim(dataset_games)

# leitura do arquivo e criação de uma coluna que armazena soma acumulativa das vendas globais (Global_Sales).
dbGetQuery(con, “SELECT *, SUM(Global_Sales) OVER (ROWS UNBOUNDED PRECEDING) as Cumulative_Sales
FROM vgsales”)

O RMySQL fornece um conjunto de funções nos quais poderemos manipular, utilizando a própria linguagem SQL dentro do R. No script acima, empregamos o dbReadTable para fazer a leitura da tabela, passando como parâmetro a conexão e o nome da tabela. Depois, por meio do dbGetQuery realizamos um SELECT e criamos dinamicamente uma coluna a partir de um comando SQL.

Para encerrar o tutorial, se desejarmos realizar o mesmo procedimento — extrair informação de uma tabela presente em uma tabela no MySQL e depois criar uma coluna baseado em uma outra, poderemos fazer isso com o dplyr. Uma linha de código é o suficiente, observe (coloquei o head só para ajudar na visualização do console):

dataset_games %>% mutate(Cumulative_Sales = cumsum(Global_Sales)) %>% head()

Console:

Bom é isso pessoal. Obrigado por ter chego até aqui. Até breve!

--

--

Fernando Gama

Data Scientist - MSc. Computer Science, Data Analytics, Machine Learning, Text Mining and Visualization