Como comparar data.frame para achar arquivos duplicados

Para uma melhor compreensão de como é feito, em geral, o trabalho em data science, vamos definir os procedimentos ou passos a serem considerados na análise. Os procedimentos que apresentamos decorrem das ideias descritas no livro (Grolemund,2017) e podem ser observados na figura abaixo.

Como comparar data.frame para achar arquivos duplicados

Diagrama de ferramentas para Data Science em (Grolemund,2017)

Pensando em um projeto com dados retangulares, devemos ter as seguintes etapas:

Passo 1: Formulação da pergunta de pesquisa

Neste primeiro passo propõe-se que sejam definidos os objetivos da pesquisa, para compreender mais profundamente o que, como e o porquê do projeto.

Passo 2: Recuperação dos dados (ou, garimpagem dos dados)

Em seguida, prossegue-se obtendo dados da web, de bancos de dados tipo MySQL ou de qualquer outra fonte. Associado a este passo existe a etapa “Import” mostrada na figura anterior.

Passo 3: Preparação de dados

Neste momento se procede à compreensão e preparação dos dados para a análise. Os dados devem ficar num formato tipo dados “tidy” (arrumado - tradução livre). Estes últimos fornecem uma maneira padrão de organizar os valores dentro de um conjunto de dados.

Por exemplo: disponibilizados um conjunto de dados, poderiamos considerar remover os valores falsos, fisicamente impossíveis ou inconsistentes. As informações devem ser combinadas e arrumadas no formato adequado de dados tidy (etapa descrita no diagrama anterior).

Passo 4: Exploração de dados

É o momento de compreender ainda melhor os dados fazendo uma análise profunda e detalhada, a partir da manipulação e visualização dos mesmos. As etapas “Transform” e “Visualise” pertecem a este passo.

Como exemplos do trabalho a fazer na etapa “Trasformação” estão a criação de dummies, agregação de dados e redução do número de variáveis. Já neste ponto os dados se encontram na melhor forma possível, ou seja, na mais natural para interagir com os mesmos. As etapas “Tidy” e “Trasform” quando juntas são chamadas de “wrangling” (retorcer, forjar os dados - tradução opinativa) (Grolemund,2017)

Muitas vezes, no procedimento de exploração de dados, é preciso gráficos para visualizar as distintas categorias de uma variável ou a correlacão dela com o resto das variáveis. Com este fim, na etapa “Visualise”, procuramos estabelecer um sistema de gráficos para facilitar, por exemplo, a visualização de dados de grandes dimensões.

Caso necessário, pode existir um passo intermediário para o tratamento dos valores faltantes e os outliers. Este é conhecido com o nome de “Data Cleaning” (limpeza de dados - tradução livre).

Passo 5 - Modelagem dos dados

Responderemos as perguntas de pesquisa realizadas no passo 1, mediante uma modelagem adequada dos dados.

Passo 6 - Apresentação

O útimo passo da análise é explicar ou comunicar os resultados. Para este passo o R também conta com ferramentas importantes como o rmarkdown e knitr, que permitem realizar relatórios e apresentações integrando códigos e resultados. A etapa relacionada a este passo é “Communicate”.

O progresso dos passos 1 ao passo 6 não é linear de acordo com (Cielen, 2016). Durante os procedimentos, é normal dar um passo atrás e retornar a uma etapa anterior de forma a estar preparado para o próximo passo. Por exemplo, na identificação dos outliers feita no procedimento de exploração de dados pode se notar um erro de importacão ocorrido no procedimento de recuperação de dados, o que implica voltar para consertar o problema.

Ao longo deste material e das aulas as principais ferramentas para se trabalhar com dados na linguagem R serão apresentadas. Estas foram basicamente desenvolvidas para auxiliar o trabalho a fazer em cada etapa dos passos acima.

Dentre as ferramentas estão o pacote readr para a etapa “Import”, o tibble e tidyr para a etapa “Tidy”, dplyr para a etapa “Trasform”, ggplot2 para “Visualise” e modelr e broom para o “Model”. Os pacotes escolhidos neste material pertencem ao conjunto de pacotes tidyverse no R. Todos os pacotes contidos no tidyverse são projetados para trabalhar com dados tidy.

Como comparar data.frame para achar arquivos duplicados

A seguir, descreveremos mediantes exemplos, as funcionalidades dos pacotes listados no tidyverse para o análise de dados. Ainda que os pacotes do tidyverse possam ser carregados conjuntamente, preferimos carregá-los individualmente, para que fique mais claro em quais pontos eles são utilizados. Os pacotes que serão apresentados possuem diferentes funcionalidades, o objetivo desse material é apresentar as principais funções e despertar nos alunos a curiosidade e disposição de usá-los. Recomenda-se pesquisar sobre os pacotes usando o Google, a função help() e o site do tidyverse.

O tibble (classe tbl_df) é um tipo especial de data frame, como explicado em (Müller,2018). Um data frame é um conjunto de dados que mantém os dados retangulares em linhas e colunas, como uma tabela, e pode ter colunas com tipos diferentes. O tibble fornece uma forma moderna de trabalhar com o data frame porque possui uma verificação mais rigorosa e uma melhor formatação se comparado ao data frame tradicional. Além disso, oferece um melhor método de impressão, o qual é útil ao trabalhar com grandes conjuntos de dados.

O tibble e outros pacotes deste material podem ser instalados a partir do CRAN11 The Comprehensive R Archive Network. No seguinte exemplo de código será instalado o tibble utilizando a função install.packages(), que recebe como primeiro argumento o nome do pacote entre aspas.

install.packages("tibble")

Após a instalação, para carregar o pacote se utiliza a função library() ou require(). Por padrão, library() retorna um erro se o pacote solicitado não existir, enquanto require() retorna um valor lógico, sendo FALSE se o pacote solicitado não for encontrado e TRUE se o pacote estiver carregado.

library(tibble)

Antes de começarmos a trabalhar com o tibble vamos ilustrar algumas funcões dos objetos de tipo data frame tradicional do R, para depois expor algumas diferenças em funcionalidade com os objetos de tipo tibble.

Para criar um data frame, basta usar a função data.frame(). A seguir mostramos como criar um data frame com 4 vetores colunas de tipos diferentes e comprimento 5:

rm(list = ls()) col1 = c(6, 7, 9, 10, 11) col2 = c("a1", "b1", "c1","d1", "e1") col3 = letters[1:5] col4 = rep(TRUE, 5) df = data.frame(col1, col2, col3, col4) df ## col1 col2 col3 col4 ## 1 6 a1 a TRUE ## 2 7 b1 b TRUE ## 3 9 c1 c TRUE ## 4 10 d1 d TRUE ## 5 11 e1 e TRUE

Podemos, por exemplo:

  1. Acessar à coluna de nome col2 mediante o operador $:
df$col2 ## [1] a1 b1 c1 d1 e1 ## Levels: a1 b1 c1 d1 e1
  1. Indexar o data frame mediante colchetes. Neste caso, obtendo a segunda linha toda:
df[2,] ## col1 col2 col3 col4 ## 2 7 b1 b TRUE

Observe que a indexação nos data frames tradicionais do R podem retornar tipos diferentes. Para obter a classe dos objetos é utilizada a função class():

t1<- df[,2] class(t1) ## [1] "factor" t2<- df[,2:4] class(t2) ## [1] "data.frame" t3<- df[1,1] class(t3) ## [1] "numeric"

Uma limitação importante dos data frames tradicionais é modificar o tipo de variável que foi inserida no mesmo. Observe o exemplo abaixo. Ao obter a classe dos vetores col1 e col2 e das colunas do data frame do mesmo nome, observe que a classe do vetor col1 coincide com a classe da coluna do mesmo nome do data frame, mas o resultado foi diferente para a segunda coluna. O vetor col2 é de tipo character mas a coluna col2 do data frame mudou o tipo para factor.

class(col1) ## [1] "numeric" class(col2) ## [1] "character" class(df$col1) ## [1] "numeric" class(df$col2) ## [1] "factor" compare <- data.frame(class_cols = c(class(col1), class(col2)), class_df = c(class(df$col1),class(df$col2))) compare ## class_cols class_df ## 1 numeric numeric ## 2 character factor

Para se criar um data frame sem o problema anterior é preciso especificar como FALSE o argumento stringsAsFactors da função de criação, com o qual a coluna 2 do data frame tem o tipo esperado:

df2 = data.frame(col1, col2, col3, col4,stringsAsFactors = FALSE) class(df2$col2) ## [1] "character"
  1. Os data frames possuem nomes de colunas e nomes de linhas, que podem ser obtido pelas funcões rownames() e colnames(), respectivamente. O número de linhas e colunas podem ser verificados com a função nrow() e ncol().
rownames(df) ## [1] "1" "2" "3" "4" "5" colnames(df) ## [1] "col1" "col2" "col3" "col4" nrow(df) ## [1] 5 ncol(df) ## [1] 4
  1. Removendo e adicionando linhas e colunas de um data frame;

Neste caso foi eliminada toda a segunda linha e a quarta coluna:

df<- df[-2,] df<- df[-4] df ## col1 col2 col3 ## 1 6 a1 a ## 3 9 c1 c ## 4 10 d1 d ## 5 11 e1 e rownames(df) ## [1] "1" "3" "4" "5"

Agora, observa-se que o nome da última linha é 5, mas o número real de linhas é 4, o qual pode ser verificado mediante a função nrow():

nrow(df) ## [1] 4

Para adicionar uma nova coluna de nome newcol4 foi utlizada a função cbind(). Observe que a coluna terá o valor FALSE repetido pelas 4 linhas do data frame correspondente:

df<- cbind(df, data.frame(newcol4 = rep(FALSE,nrow(df)))) df ## col1 col2 col3 newcol4 ## 1 6 a1 a FALSE ## 3 9 c1 c FALSE ## 4 10 d1 d FALSE ## 5 11 e1 e FALSE

Outra forma de adicionar uma coluna é mediante o operador $. Neste caso foi criada uma nova coluna de nome col5 e terá também o valor FALSE repetido nrow() vezes:

df$col5 = rep(FALSE,nrow(df)) df ## col1 col2 col3 newcol4 col5 ## 1 6 a1 a FALSE FALSE ## 3 9 c1 c FALSE FALSE ## 4 10 d1 d FALSE FALSE ## 5 11 e1 e FALSE FALSE

Para adicionar uma linha é utilizada a função rbind():

df<- rbind(df, data.frame(col1= 12, col2= "d1", col3= "f", newcol4 = FALSE, col5 = TRUE)) df ## col1 col2 col3 newcol4 col5 ## 1 6 a1 a FALSE FALSE ## 3 9 c1 c FALSE FALSE ## 4 10 d1 d FALSE FALSE ## 5 11 e1 e FALSE FALSE ## 11 12 d1 f FALSE TRUE

A frequência de ocorrência dos termos de qualquer coluna pode ser obitida pela função table(). Neste caso d1 aparece duas vezes na coluna de nome col2, b1 nehuma e as demais apenas uma vez:

table(df$col2) ## ## a1 b1 c1 d1 e1 ## 1 0 1 2 1

O data frame conta com correspondência parcial para suas colunas, o que pode levar a um erro se esse fato não for levado em consideração. Basta acesar a uma coluna do data frame usando só um fragmento do nome, desde que não haja coincidência com os outros nomes das colunas. Neste caso, será acessada a coluna newcol4 mediante um fragmento do seu nome:

df$new ## [1] FALSE FALSE FALSE FALSE FALSE

Uma vez conhecidas as principais funcionalidades de um data frame, se apresentarão alguns comados para o tipo especial tibble. Para isto, será criado um novo objeto de tipo tibble, com duas colunas e duas linhas. A primeira coluna terá tipo numeric e nome col1, e a segunda terá tipo factor e nome newcol2:

Criando um tibble:

library(tibble) tb<- tibble(col1 = numeric(), newcol2 = factor()) tb <- add_row(tb, col1 = 4, newcol2 = "A") tb <- add_row(tb, col1 = 5, newcol2 = "B") tb ## # A tibble: 2 x 2 ## col1 newcol2 ## <dbl> <fct> ## 1 4 A ## 2 5 B

Cada variável pode ser do tipo numbers(int, dbl), character(chr), logical(lgl) ou factor(fctr). Vamos trabalhar algumas funcionalidades:

  1. Realizando indexações mediante colchetes:
tb[1,1] ## # A tibble: 1 x 1 ## col1 ## <dbl> ## 1 4 tb[,2] ## # A tibble: 2 x 1 ## newcol2 ## <fct> ## 1 A ## 2 B
  1. Acessando a coluna newcol2:
tb$newcol2 ## [1] A B ## Levels: A B

O acesso à coluna newcol2 fazendo uso da correspondência parcial retorna NULL:

tb$new
  1. Convertendo um data frame em um tibble

Partindo de um data frame previamente criado ou carregado, é possivel convertê-lo para o formato tibble. Para mostrar esta funcionalidade, é carregado o data frame hflights contido no pacote de mesmo nome.

Esta base de dados contém todos os voos que partem dos aeroportos de Houston IAH (George Bush Intercontinental) e HOU (Houston Hobby). O data frame contém 227.496 linhas e 21 colunas:

  • Year, Month, DayofMonth: data de partida
  • DayOfWeek: dia da semana de partida
  • DepTime, ArrTime: horários de partida e chegada
  • UniqueCarrier: abreviatura única para uma companhia aérea
  • FlightNum: número do voo
  • TailNum: número do avião
  • ActualElapsedTime: tempo percorrido pelo voo
  • AirTime: tempo de duração do voo
  • ArrDelay, DepDelay: atrassos de chegada e partida
  • Origin, Dest: códigos dos aeroportos de origem e destino
  • Distance: distância da trajetória do voo
  • TaxiIn, TaxiOut: tempo de taxi-in e taxi-out
  • Cancelled: indicador de cancelamento de voo
  • CancellationCode: motivo do cancelamento
  • Diverted: indicador de desvio

Carregando o data frame hflights:

library(hflights)

Primeiramente, conferindo que hflights é de tipo data frame e mostrando as primeiras linhas com a função head():

class(hflights) ## [1] "data.frame" head(hflights) ## Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier ## 5424 2011 1 1 6 1400 1500 AA ## 5425 2011 1 2 7 1401 1501 AA ## 5426 2011 1 3 1 1352 1502 AA ## 5427 2011 1 4 2 1403 1513 AA ## 5428 2011 1 5 3 1405 1507 AA ## 5429 2011 1 6 4 1359 1503 AA ## FlightNum TailNum ActualElapsedTime AirTime ArrDelay DepDelay Origin ## 5424 428 N576AA 60 40 -10 0 IAH ## 5425 428 N557AA 60 45 -9 1 IAH ## 5426 428 N541AA 70 48 -8 -8 IAH ## 5427 428 N403AA 70 39 3 3 IAH ## 5428 428 N492AA 62 44 -3 5 IAH ## 5429 428 N262AA 64 45 -7 -1 IAH ## Dest Distance TaxiIn TaxiOut Cancelled CancellationCode Diverted ## 5424 DFW 224 7 13 0 0 ## 5425 DFW 224 6 9 0 0 ## 5426 DFW 224 5 17 0 0 ## 5427 DFW 224 9 22 0 0 ## 5428 DFW 224 9 9 0 0 ## 5429 DFW 224 6 13 0 0

Segundo o obtido anteriormente, este conjunto de dados ainda não está no formato tibble. Para converter o data frame tradicional em tibble é utlizada a função as_data_frame():

hflights2 <- as_data_frame(hflights) class(hflights2) ## [1] "tbl_df" "tbl" "data.frame"

O cabeçalho da tabela hflights2 agora mostra uma aparência diferente:

head(hflights2) ## # A tibble: 6 x 21 ## Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum ## <int> <int> <int> <int> <int> <int> <chr> <int> ## 1 2011 1 1 6 1400 1500 AA 428 ## 2 2011 1 2 7 1401 1501 AA 428 ## 3 2011 1 3 1 1352 1502 AA 428 ## 4 2011 1 4 2 1403 1513 AA 428 ## 5 2011 1 5 3 1405 1507 AA 428 ## 6 2011 1 6 4 1359 1503 AA 428 ## # ... with 13 more variables: TailNum <chr>, ActualElapsedTime <int>, ## # AirTime <int>, ArrDelay <int>, DepDelay <int>, Origin <chr>, ## # Dest <chr>, Distance <int>, TaxiIn <int>, TaxiOut <int>, ## # Cancelled <int>, CancellationCode <chr>, Diverted <int>

Se for preciso, é possivel mudar do tipo tibble de volta para o data frame com a função as.data.frame(). Para obter uma breve descrição contendo o tipo das colunas é utilizada a função glimpse():

glimpse(hflights2) ## Observations: 227,496 ## Variables: 21 ## $ Year <int> 2011, 2011, 2011, 2011, 2011, 2011, 2011, 20... ## $ Month <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,... ## $ DayofMonth <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1... ## $ DayOfWeek <int> 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6,... ## $ DepTime <int> 1400, 1401, 1352, 1403, 1405, 1359, 1359, 13... ## $ ArrTime <int> 1500, 1501, 1502, 1513, 1507, 1503, 1509, 14... ## $ UniqueCarrier <chr> "AA", "AA", "AA", "AA", "AA", "AA", "AA", "A... ## $ FlightNum <int> 428, 428, 428, 428, 428, 428, 428, 428, 428,... ## $ TailNum <chr> "N576AA", "N557AA", "N541AA", "N403AA", "N49... ## $ ActualElapsedTime <int> 60, 60, 70, 70, 62, 64, 70, 59, 71, 70, 70, ... ## $ AirTime <int> 40, 45, 48, 39, 44, 45, 43, 40, 41, 45, 42, ... ## $ ArrDelay <int> -10, -9, -8, 3, -3, -7, -1, -16, 44, 43, 29,... ## $ DepDelay <int> 0, 1, -8, 3, 5, -1, -1, -5, 43, 43, 29, 19, ... ## $ Origin <chr> "IAH", "IAH", "IAH", "IAH", "IAH", "IAH", "I... ## $ Dest <chr> "DFW", "DFW", "DFW", "DFW", "DFW", "DFW", "D... ## $ Distance <int> 224, 224, 224, 224, 224, 224, 224, 224, 224,... ## $ TaxiIn <int> 7, 6, 5, 9, 9, 6, 12, 7, 8, 6, 8, 4, 6, 5, 6... ## $ TaxiOut <int> 13, 9, 17, 22, 9, 13, 15, 12, 22, 19, 20, 11... ## $ Cancelled <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... ## $ CancellationCode <chr> "", "", "", "", "", "", "", "", "", "", "", ... ## $ Diverted <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...

É possível também alterar a aparência de impressão padrão, por exemplo com “print_max = Inf”" imprime-se todas as linhas:

options(tibble.print_max = Inf) hflights2

Segundo os exemplos estudados, o tibble comparado com o data frame tradicional (veja esse comentários com a função help(tibble)):

  • Nunca converte um tipo character como factor
  • A indexação com colchetes sempre retorna um tibble
  • Não faz correspondência parcial. Retorna NULL se a coluna não existe com o nome especificado

Uma sugestão importante é evitar o trabalho com nomes de linhas, mesmo sendo uma funcionalidade do tibble e do data frame. No caso do tibble, um warning será levantado ao tentar atribuir nomes de linhas não NULL (Müller,2018).

Os conjuntos de dados tidy (organizados) são fáceis de manipular, modelar e visualizar. Conforme em (Wickham,2014), dados tidy é uma maneira padrão de mapear o significado de um conjunto de dados com sua estrutura. Um conjunto de dados está arrumado ou não, dependendo de como linhas, colunas e células são combinadas com observações, variáveis e valores.

Nos dados tidy, cumpre-se que:

  • Cada variável deve ter sua própria coluna
  • Cada observação deve ter sua própria linha
  • Cada valor deve ter sua própria célula

Carregando o pacote tidyr:

library(tidyr)

O pacote tidyr fornece algumas funções para alterar o layout do conjunto de dados:

  1. gather(): colapso de colunas em linhas. Você deve usar essa função quando você tiver colunas que não são variáveis.

Utilizada principalmente quando as colunas da base não representam nomes de variáveis, mas sim seus valores. No exemplo abaixo as colunas lojaA e lojaB representam os valores do preço dessas lojas para os produtos P1 e P2:

tb<- tibble(Produto = factor(), LojaA = numeric(), lojaB= numeric()) tb <- add_row(tb, Produto = "P1", LojaA = 5, lojaB = 5.50) tb <- add_row(tb, Produto = "P2", LojaA = 10, lojaB = 12) tb ## # A tibble: 2 x 3 ## Produto LojaA lojaB ## <fct> <dbl> <dbl> ## 1 P1 5 5.5 ## 2 P2 10 12

Aplicando a função gather() foi criada uma coluna de nome Lojas para representar lojaA e lojaB, e outra coluna de nome Preço com os valores do preço de cada produto nas diferentes lojas:

tb2<- gather(tb, Lojas,Preco, LojaA:lojaB) tb2 ## # A tibble: 4 x 3 ## Produto Lojas Preco ## <fct> <chr> <dbl> ## 1 P1 LojaA 5 ## 2 P2 LojaA 10 ## 3 P1 lojaB 5.5 ## 4 P2 lojaB 12
  1. spread(): espalha linhas em colunas. Comportamento inverso à função gather().
tb3<- spread(tb2, Lojas,Preco) tb3 ## # A tibble: 2 x 3 ## Produto LojaA lojaB ## <fct> <dbl> <dbl> ## 1 P1 5 5.5 ## 2 P2 10 12
  1. separate(): separa uma coluna em múltiplas colunas.

Por exemplo, no tibble anterior de nome tb2, será adicionada uma nova coluna de nome DiaMes para o dia do mês no qual foi observado o preço para cada produto, seguindo o formato “dia/mes” :

col<- c("03/06","04/07","03/06","06/07") tb2<- add_column(tb2, DiaMes = col) tb2 ## # A tibble: 4 x 4 ## Produto Lojas Preco DiaMes ## <fct> <chr> <dbl> <chr> ## 1 P1 LojaA 5 03/06 ## 2 P2 LojaA 10 04/07 ## 3 P1 lojaB 5.5 03/06 ## 4 P2 lojaB 12 06/07

Depois de aplicar separate, foram criadas uma coluna de nome Dia e a outra de nome Mes com os valores que continham a coluna DiaMes mas agora separados pelo character “/” :

tb4<- separate(tb2,DiaMes,c("Dia","Mes"),sep = "/") tb4 ## # A tibble: 4 x 5 ## Produto Lojas Preco Dia Mes ## <fct> <chr> <dbl> <chr> <chr> ## 1 P1 LojaA 5 03 06 ## 2 P2 LojaA 10 04 07 ## 3 P1 lojaB 5.5 03 06 ## 4 P2 lojaB 12 06 07
  1. unite(): une multiplas colunas em uma só. Comportamento inverso à função separate().
tb5 <- unite(tb4, col = "DiaMes", Dia, Mes, sep = "/") tb5 ## # A tibble: 4 x 4 ## Produto Lojas Preco DiaMes ## <fct> <chr> <dbl> <chr> ## 1 P1 LojaA 5 03/06 ## 2 P2 LojaA 10 04/07 ## 3 P1 lojaB 5.5 03/06 ## 4 P2 lojaB 12 06/07

A função read.csv() pode ser usada para ler um arquivo no formato csv. A varianteread.csv2() é utilizada em países que usam uma vírgula “,” como ponto decimal e um ponto e vírgula “;” como separadores de campo. A função write.csv() ou a variante write.csv2() pode ser usada para exportar um arquivo no formato csv.

Para carregar e salvar grandes arquivos de forma mais rápida é usado o pacote readr. Ele fornece substituições para funções como read.csv(), sendo a função análoga read_csv(). Esta função é muito mais rápida que a função em base R e fornece algumas outras características agradáveis, como medidores de progresso, conforme em (Peng,2015).

library(readr)

Carregando o arquivo “mtcars.csv” (Motor Trend Car Road Tests), o qual contem 32 observações e 11 variáveis relativos aos veículos dos anos 1973-1974 . Note que os dados resultantes da importação tem o tipo tbl_df:

car <- read_csv(readr_example("mtcars.csv"), col_names = TRUE) ## Parsed with column specification: ## cols( ## mpg = col_double(), ## cyl = col_integer(), ## disp = col_double(), ## hp = col_integer(), ## drat = col_double(), ## wt = col_double(), ## qsec = col_double(), ## vs = col_integer(), ## am = col_integer(), ## gear = col_integer(), ## carb = col_integer() ## ) class(car) ## [1] "tbl_df" "tbl" "data.frame"

mpg Miles/(US) gallon
cyl Number of cylinders
disp Displacement (cu.in.)
hp Gross horsepower
drat Rear axle ratio
wt Weight (1000 lbs)
qsec 1/4 mile time
vs Engine (0 = V-shaped, 1 = straight)
am Transmission (0 = automatic, 1 = manual)
gear Number of forward gears
carb Number of carburetors

A função read_csv() tenta adivinhar automaticamente o tipo de dados de cada coluna, mas para um resultado mais preciso pode ser especificado o tipo das colunas:

car <- read_csv(readr_example("mtcars.csv"), col_types = cols( mpg = col_double(), cyl = col_integer(), disp = col_double(), hp = col_integer(), drat = col_double(), vs = col_integer(), wt = col_double(), qsec = col_double(), am = col_integer(), gear = col_integer(), carb = col_integer() ) )

Para salvar o arquivo em formato csv:

write_csv(car, path = "car.csv")

O operador pipe permite o “encadeamento” de chamadas de várias funções. Como cada função separada retorna um objeto, é permitido que as funções sejam encadeadas em uma única declaração, sem precisar de variáveis para armazenar os resultados intermediários.

De acordo com (Baumer,2017), a sintaxe do Pipe retém a lógica passo a passo do nosso código original, ao mesmo tempo que é facilmente legível e eficiente em relação à memória e a criação de data frames temporários.

A função permite tornar os códigos em R mais simples para o usuário, que passa a poder realizar múltiplas operações em uma única linha. Ele ajuda a organizar melhor o código, tornando muito mais fácil mantê-lo depois.

No R, o operador pipe é o " %>% " (tecla de atalho: crtl+shift+M). Ele captura o resultado de uma declaração e o torna a entrada da próxima declaração. Ao descrevê-lo, é possível pensar nisso como “EM SEGUIDA FAÇA”.

Para uma melhor comprensão, são apresentadas as regras gerais do Pipe:

  • f(x) pode ser reescrito como: x %>% f
  • f(x, y) pode ser reescrito como: x %>% f(y)
  • g(f(x)) pode ser reescrito como: x %>% f %>% g

Carregando o pacote que fornece o Pipe:

library(magrittr)

Para exemplificar as vantagens deste operador, serão comparadas duas implementações: sem e com o operador pipe para obter as duas primeiras linhas do data frame hflights com os valores da coluna Distance maior que 300.

Sem pipe:

head(subset(hflights,Distance > 300),2) ## Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier ## 23655 2011 1 1 6 1756 2112 AA ## 23656 2011 1 2 7 1823 2132 AA ## FlightNum TailNum ActualElapsedTime AirTime ArrDelay DepDelay Origin ## 23655 1294 N3DGAA 136 113 -3 1 IAH ## 23656 1294 N3CCAA 129 112 17 28 IAH ## Dest Distance TaxiIn TaxiOut Cancelled CancellationCode Diverted ## 23655 MIA 964 9 14 0 0 ## 23656 MIA 964 6 11 0 0

Com pipe:

hflights %>% subset(Distance > 300) %>% head(2)

Apesar de o operador pipe ser muito útil e fácil, ele não guarda os resultados intermediários. Em um encadeamento, pode-se estar interessado não apenas no resultado final, mas também em resultados intermediários. Para visualizar ou salvar estes resultados intermediários é preciso ter uma sintaxe simples para evitar quebrar a sequência principal. Para isto, o pacote pipeR, de acordo com (Ren,2016), define uma sintaxe unificada e intuitiva. O pacote foi projetado para ajudar a organizar os códigos de forma consistente, seguindo a mesma lógica do operador pipe.

library(pipeR)

Guardando o resultado intermediário na variável de nome hflightsInter:

hflights %>>% subset(Cancelled == 0) %>>% (~ hflightsInter) %>>% nrow() ## [1] 224523

Poderia ter o número de linhas sem guardar os dados na hflightsInter, usando apenas o operador pipe:

hflights %>% subset(Cancelled == 0) %>% nrow() ## [1] 224523

Utilizando a função head para hflightsInter:

head(hflightsInter) ## Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier ## 5424 2011 1 1 6 1400 1500 AA ## 5425 2011 1 2 7 1401 1501 AA ## 5426 2011 1 3 1 1352 1502 AA ## 5427 2011 1 4 2 1403 1513 AA ## 5428 2011 1 5 3 1405 1507 AA ## 5429 2011 1 6 4 1359 1503 AA ## FlightNum TailNum ActualElapsedTime AirTime ArrDelay DepDelay Origin ## 5424 428 N576AA 60 40 -10 0 IAH ## 5425 428 N557AA 60 45 -9 1 IAH ## 5426 428 N541AA 70 48 -8 -8 IAH ## 5427 428 N403AA 70 39 3 3 IAH ## 5428 428 N492AA 62 44 -3 5 IAH ## 5429 428 N262AA 64 45 -7 -1 IAH ## Dest Distance TaxiIn TaxiOut Cancelled CancellationCode Diverted ## 5424 DFW 224 7 13 0 0 ## 5425 DFW 224 6 9 0 0 ## 5426 DFW 224 5 17 0 0 ## 5427 DFW 224 9 22 0 0 ## 5428 DFW 224 9 9 0 0 ## 5429 DFW 224 6 13 0 0

O pacote purrr dispõe de ferramentas com uma expressividade similar a uma linguagem de programação funcional. Este contém funções que eliminam a necessidade de muitos ciclos de forma consistente e o código fica muito mais fácil de escrever e entender.

library(purrr)

As funções map() abstraem a iteração em apenas uma linha. Por padrão, a função retorna uma lista com um elemento para cada saída. Para obter os dados como sendo um tipo de vetor é preciso informar qual será o seu tipo utilizando algumas das funções para essa tarefa. Por exemplo:

  • Construir um vetor de tipo logical: é usada a função map_lgl()
  • Construir um vetor de tipo integer: é usada a função map_int()
  • Construir um vetor de tipo double: é usada a função map_dbl()
  • Construir um vetor de tipo character: é usada a função map_chr()

Por exemplo, defina uma função a ser aplicada ao vetor v:

rm(list = ls()) f <- function(x){sqrt(x) + 1} v <- c(4,9,16,25,36,49,64,81)

Uma solução óbvia seria usar a função “for” para resolver esse problema:

sol <- NULL for(i in 1:length(v)){ sol[i] <- f(v[i]) } round(sol,2) ## [1] 3 4 5 6 7 8 9 10

Contudo, utilizando a função map() o código fica sem ciclos para percorrer o vetor:

resp<- map(v, f) resp ## [[1]] ## [1] 3 ## ## [[2]] ## [1] 4 ## ## [[3]] ## [1] 5 ## ## [[4]] ## [1] 6 ## ## [[5]] ## [1] 7 ## ## [[6]] ## [1] 8 ## ## [[7]] ## [1] 9 ## ## [[8]] ## [1] 10

Também é possível especificar o tipo double para o vetor de saída:

resp2<- map_dbl(v,f) resp2 ## [1] 3 4 5 6 7 8 9 10

A função map() pode ser aplicada satisfatoriamte em tibbles e utilizando o operador pipe:

tb<- tibble(col1 = numeric(), col2 = numeric()) tb <- add_row(tb, col1 = 4, col2 = 1) tb <- add_row(tb, col1 = 5, col2 = 4) tb <- add_row(tb, col1 = 4, col2 = 3) tb ## # A tibble: 3 x 2 ## col1 col2 ## <dbl> <dbl> ## 1 4 1 ## 2 5 4 ## 3 4 3

Neste caso, para calcular a média de cada coluna:

tb %>% map_dbl(mean) ## col1 col2 ## 4.333333 2.666667

Dada a relevância de manipular os dados em um data frame, é imprescindível ter boas ferramentas para lidar com eles. O dplyr é um pacote que facilita o trabalho com dados, com uma gramática de manipulação de dados simples e flexível (filtragem, reordenamento, colapso, entre outras). Ele foi construído com o intuito de obter uma forma mais rápida e expressiva de tratar os dados (Peng,2015). O tibble é a versão de data frame mais conveniente para usar com dplyr.

Uma contribuição importante do pacote é que a sua gramática, que contém funções verbais que são comuns para manipulação de dados. As funções verbais, detalhadas em (Baumer,2017), são:

  • select(): subconjunto das colunas ou variáveis do dataset
  • filter(): subconjunto das linhas ou observações
  • mutate(): adicionar ou modificar colunas
  • arrange(): reordenar as linhas com respeito a determinadas colunas
  • summarise() [em conjunto com groupby()]: reduz cada grupo numa única linha sob alguma medida estatística

O data frame é sempre o primeiro argumento das funções verbais. Todas seguem a mesma sintaxe: primeiro o data frame, seguido do operador pipe e, por fim, o nome da função verbal com outros argumentos entre parênteses (Ismay,2018). As funções verbais não modificam o data frame original.

library(dplyr)

As funções verbais correspondem aos comandos SQL da seguinte forma:

  • select ~ SELECT
  • filter ~ WHERE
  • arrange ~ ORDER
  • summarise ~ sum, min, sd
  • mutate ~ +, *, log

Descreveremos como é feito o trabalho com as funções verbais. Para isso primeiramente converteremos o data frame hflights em tibble e atribuimos ele para uma variável de nome hflights2.

Função select()

Selecionando colunas 14 e 15 do tibble de nome hflights2 com a função select(). Antes, vamos relembrar as variáveis que temos na nossa tabela hflights

Esta base de dados contém todos os voos que partem dos aeroportos de Houston IAH (George Bush Intercontinental) e HOU (Houston Hobby). O data frame contém 227.496 linhas e 21 colunas:

  • Year, Month, DayofMonth: data de partida
  • DayOfWeek: dia da semana de partida
  • DepTime, ArrTime: horários de partida e chegada
  • UniqueCarrier: abreviatura única para uma companhia aérea
  • FlightNum: número do voo
  • TailNum: número do avião
  • ActualElapsedTime: tempo percorrido pelo voo
  • AirTime: tempo de duração do voo
  • ArrDelay, DepDelay: atrassos de chegada e partida
  • Origin, Dest: códigos dos aeroportos de origem e destino
  • Distance: distância da trajetória do voo
  • TaxiIn, TaxiOut: tempo de taxi-in e taxi-out
  • Cancelled: indicador de cancelamento de voo
  • CancellationCode: motivo do cancelamento
  • Diverted: indicador de desvio
## [1] "tbl_df" "tbl" "data.frame" head(select(hflights2,14,15)) ## # A tibble: 6 x 2 ## Origin Dest ## <chr> <chr> ## 1 IAH DFW ## 2 IAH DFW ## 3 IAH DFW ## 4 IAH DFW ## 5 IAH DFW ## 6 IAH DFW

Selecionando colunas Origin e Dest:

head(select(hflights2,Origin,Dest)) ## # A tibble: 6 x 2 ## Origin Dest ## <chr> <chr> ## 1 IAH DFW ## 2 IAH DFW ## 3 IAH DFW ## 4 IAH DFW ## 5 IAH DFW ## 6 IAH DFW

Selecionando da coluna DepTime até a coluna Dest, excluido a coluna TailNum:

head(select(hflights2,DepTime:Dest,-TailNum)) ## # A tibble: 6 x 10 ## DepTime ArrTime UniqueCarrier FlightNum ActualElapsedTime AirTime ## <int> <int> <chr> <int> <int> <int> ## 1 1400 1500 AA 428 60 40 ## 2 1401 1501 AA 428 60 45 ## 3 1352 1502 AA 428 70 48 ## 4 1403 1513 AA 428 70 39 ## 5 1405 1507 AA 428 62 44 ## 6 1359 1503 AA 428 64 45 ## # ... with 4 more variables: ArrDelay <int>, DepDelay <int>, Origin <chr>, ## # Dest <chr>

O dplyr também contém um conjunto de funções auxiliares que podem ajudar a selecionar grupos de variáveis, entre elas starts_with(), ends_with() e contains(), para as colunas que começam, terminan e contém um padrão específico.

Por exemplo, para selecionar as colunas TailNum, TaxiIn, TaxiOut, que começam com “Ta”, foi utilizanda a função auxiliar starts_with():

head(select(hflights2,starts_with("Ta"))) ## # A tibble: 6 x 3 ## TailNum TaxiIn TaxiOut ## <chr> <int> <int> ## 1 N576AA 7 13 ## 2 N557AA 6 9 ## 3 N541AA 5 17 ## 4 N403AA 9 22 ## 5 N492AA 9 9 ## 6 N262AA 6 13

Função filter()

No filter pode ser considerados os operadores: >, >=, <, <=, ==, !=, is.na, !is.na

Filtrando os voos que tiveram MIA como destino:

MIADest <- filter(hflights2, Dest =="MIA") glimpse(MIADest) ## Observations: 2,463 ## Variables: 21 ## $ Year <int> 2011, 2011, 2011, 2011, 2011, 2011, 2011, 20... ## $ Month <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,... ## $ DayofMonth <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1... ## $ DayOfWeek <int> 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6,... ## $ DepTime <int> 1756, 1823, 1755, 1757, 1751, 1746, 1757, 17... ## $ ArrTime <int> 2112, 2132, 2106, 2122, 2100, 2120, 2108, 21... ## $ UniqueCarrier <chr> "AA", "AA", "AA", "AA", "AA", "AA", "AA", "A... ## $ FlightNum <int> 1294, 1294, 1294, 1294, 1294, 1294, 1294, 12... ## $ TailNum <chr> "N3DGAA", "N3CCAA", "N3ARAA", "N3DFAA", "N3B... ## $ ActualElapsedTime <int> 136, 129, 131, 145, 129, 154, 131, 131, 133,... ## $ AirTime <int> 113, 112, 112, 108, 107, 106, 107, 107, 110,... ## $ ArrDelay <int> -3, 17, -9, 7, -15, 5, -7, -15, 8, 80, 41, -... ## $ DepDelay <int> 1, 28, 0, 2, -4, -9, 2, -6, 15, 99, 53, -7, ... ## $ Origin <chr> "IAH", "IAH", "IAH", "IAH", "IAH", "IAH", "I... ## $ Dest <chr> "MIA", "MIA", "MIA", "MIA", "MIA", "MIA", "M... ## $ Distance <int> 964, 964, 964, 964, 964, 964, 964, 964, 964,... ## $ TaxiIn <int> 9, 6, 5, 26, 11, 34, 9, 11, 7, 3, 7, 7, 36, ... ## $ TaxiOut <int> 14, 11, 14, 11, 11, 14, 15, 13, 16, 11, 10, ... ## $ Cancelled <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... ## $ CancellationCode <chr> "", "", "", "", "", "", "", "", "", "", "", ... ## $ Diverted <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...

Filtrando os voos que tiveram MIA ou SEA como destino. Para este exemplo será utilizado o operador %in% por ter mais de uma opção de destino. O resultado será comprovado com a funçao unique(), que mostra os elementos que não estão duplicados.

MIA_SEA <- filter(hflights2, Dest %in% c("MIA","SEA")) result <- MIA_SEA$Dest unique(MIA_SEA$Dest) ## [1] "MIA" "SEA"

Agora, queremos saber todos os voos onde TaxiIn + TaxiOut > AirTime, ou seja, o avião demorou mais tempo taxiando que voando o trajeto origem-destino.

head(filter(hflights2, TaxiIn + TaxiOut > AirTime)) ## # A tibble: 6 x 21 ## Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier FlightNum ## <int> <int> <int> <int> <int> <int> <chr> <int> ## 1 2011 1 24 1 731 904 AA 460 ## 2 2011 1 30 7 1959 2132 AA 533 ## 3 2011 1 24 1 1621 1749 AA 1121 ## 4 2011 1 10 1 941 1113 AA 1436 ## 5 2011 1 31 1 1301 1356 CO 241 ## 6 2011 1 31 1 2113 2215 CO 1533 ## # ... with 13 more variables: TailNum <chr>, ActualElapsedTime <int>, ## # AirTime <int>, ArrDelay <int>, DepDelay <int>, Origin <chr>, ## # Dest <chr>, Distance <int>, TaxiIn <int>, TaxiOut <int>, ## # Cancelled <int>, CancellationCode <chr>, Diverted <int>

O pacote dplyr funciona perfeitamente junto ao operador pipe. Para mostrar esta funcionalidade, vamos obter um tibble apenas com as colunas AirTime e Distance, onde “Distance >= 3500 milhas” (~ 5.600 km):

hflights2 %>% select(AirTime,Distance) %>% filter(Distance>3500) # Você pode querer olhar a tabela hflights2 %>% select(AirTime,Distance) %>% filter(Distance>3500) %>% View() # Você pode querer ver o tempo de voo em horas Air_Dist <- hflights2 %>% select(AirTime,Distance) %>% filter(Distance>3500) Air_Dist <- add_column(Air_Dist, hora = Air_Dist$AirTime/60) head(Air_Dist,10) ## comentário: quebrei a cabeça nesse exercício pois se vc fizer o que fiz abaixo você não consegue usar o add_column hora <- Air_Dist[,1]/60 #Air_Dist <- add_column(Air_Dist, hora) ## primeira alternativa que encontrei hora <- as.vector(hora) head(join_table <- cbind(Air_Dist,hora))

Função mutate()

A função mutate adciona novas variáveis e preserva as variáveis já existentes. Adicionando ao hflights2 uma nova coluna de nome Day_Month combinando as variáveis DayofMonth e Month,utilizando o separador “/”:

MutCol<- mutate(hflights2, Day_Month = paste(DayofMonth,Month, sep= '/')) glimpse(MutCol) ## Observations: 227,496 ## Variables: 22 ## $ Year <int> 2011, 2011, 2011, 2011, 2011, 2011, 2011, 20... ## $ Month <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,... ## $ DayofMonth <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1... ## $ DayOfWeek <int> 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6,... ## $ DepTime <int> 1400, 1401, 1352, 1403, 1405, 1359, 1359, 13... ## $ ArrTime <int> 1500, 1501, 1502, 1513, 1507, 1503, 1509, 14... ## $ UniqueCarrier <chr> "AA", "AA", "AA", "AA", "AA", "AA", "AA", "A... ## $ FlightNum <int> 428, 428, 428, 428, 428, 428, 428, 428, 428,... ## $ TailNum <chr> "N576AA", "N557AA", "N541AA", "N403AA", "N49... ## $ ActualElapsedTime <int> 60, 60, 70, 70, 62, 64, 70, 59, 71, 70, 70, ... ## $ AirTime <int> 40, 45, 48, 39, 44, 45, 43, 40, 41, 45, 42, ... ## $ ArrDelay <int> -10, -9, -8, 3, -3, -7, -1, -16, 44, 43, 29,... ## $ DepDelay <int> 0, 1, -8, 3, 5, -1, -1, -5, 43, 43, 29, 19, ... ## $ Origin <chr> "IAH", "IAH", "IAH", "IAH", "IAH", "IAH", "I... ## $ Dest <chr> "DFW", "DFW", "DFW", "DFW", "DFW", "DFW", "D... ## $ Distance <int> 224, 224, 224, 224, 224, 224, 224, 224, 224,... ## $ TaxiIn <int> 7, 6, 5, 9, 9, 6, 12, 7, 8, 6, 8, 4, 6, 5, 6... ## $ TaxiOut <int> 13, 9, 17, 22, 9, 13, 15, 12, 22, 19, 20, 11... ## $ Cancelled <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... ## $ CancellationCode <chr> "", "", "", "", "", "", "", "", "", "", "", ... ## $ Diverted <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... ## $ Day_Month <chr> "1/1", "2/1", "3/1", "4/1", "5/1", "6/1", "7...

Agora, vamos calcular a velocidade média em quilometros por hora. Adicionando uma nova coluna Speed que seguirá a seguinte fórmula: Speed = \(((Distance*1.6)/AirTime)*60\):

Sp<- mutate(hflights2,Speed = ((Distance*1.6) / AirTime) * 60) glimpse(Sp) ## Observations: 227,496 ## Variables: 22 ## $ Year <int> 2011, 2011, 2011, 2011, 2011, 2011, 2011, 20... ## $ Month <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,... ## $ DayofMonth <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1... ## $ DayOfWeek <int> 6, 7, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6,... ## $ DepTime <int> 1400, 1401, 1352, 1403, 1405, 1359, 1359, 13... ## $ ArrTime <int> 1500, 1501, 1502, 1513, 1507, 1503, 1509, 14... ## $ UniqueCarrier <chr> "AA", "AA", "AA", "AA", "AA", "AA", "AA", "A... ## $ FlightNum <int> 428, 428, 428, 428, 428, 428, 428, 428, 428,... ## $ TailNum <chr> "N576AA", "N557AA", "N541AA", "N403AA", "N49... ## $ ActualElapsedTime <int> 60, 60, 70, 70, 62, 64, 70, 59, 71, 70, 70, ... ## $ AirTime <int> 40, 45, 48, 39, 44, 45, 43, 40, 41, 45, 42, ... ## $ ArrDelay <int> -10, -9, -8, 3, -3, -7, -1, -16, 44, 43, 29,... ## $ DepDelay <int> 0, 1, -8, 3, 5, -1, -1, -5, 43, 43, 29, 19, ... ## $ Origin <chr> "IAH", "IAH", "IAH", "IAH", "IAH", "IAH", "I... ## $ Dest <chr> "DFW", "DFW", "DFW", "DFW", "DFW", "DFW", "D... ## $ Distance <int> 224, 224, 224, 224, 224, 224, 224, 224, 224,... ## $ TaxiIn <int> 7, 6, 5, 9, 9, 6, 12, 7, 8, 6, 8, 4, 6, 5, 6... ## $ TaxiOut <int> 13, 9, 17, 22, 9, 13, 15, 12, 22, 19, 20, 11... ## $ Cancelled <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... ## $ CancellationCode <chr> "", "", "", "", "", "", "", "", "", "", "", ... ## $ Diverted <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... ## $ Speed <dbl> 537.6000, 477.8667, 448.0000, 551.3846, 488.... max(Sp$Speed, na.rm = T) ## [1] 1221.818 min(Sp$Speed, na.rm = T) ## [1] 158.1176 boxplot(Sp$Speed, na.rm = T)

Como comparar data.frame para achar arquivos duplicados

hist(Sp$Speed)

Como comparar data.frame para achar arquivos duplicados

Função arrange()

Ordena as linhas de acordo com a variável. Ordenando os valores da coluna DepTime em ordem crescente:

arrange(hflights2,DepTime) %>% head(n=10) ## # A tibble: 10 x 21 ## Year Month DayofMonth DayOfWeek DepTime ArrTime UniqueCarrier ## <int> <int> <int> <int> <int> <int> <chr> ## 1 2011 1 1 6 1 621 CO ## 2 2011 3 11 5 1 557 CO ## 3 2011 4 29 5 1 510 CO ## 4 2011 6 24 5 1 515 CO ## 5 2011 11 15 2 1 55 XE ## 6 2011 12 24 6 1 642 CO ## 7 2011 12 9 5 1 633 CO ## 8 2011 7 8 5 2 53 WN ## 9 2011 12 30 5 2 611 CO ## 10 2011 7 8 5 3 521 CO ## # ... with 14 more variables: FlightNum <int>, TailNum <chr>, ## # ActualElapsedTime <int>, AirTime <int>, ArrDelay <int>, ## # DepDelay <int>, Origin <chr>, Dest <chr>, Distance <int>, ## # TaxiIn <int>, TaxiOut <int>, Cancelled <int>, CancellationCode <chr>, ## # Diverted <int>

Organizando o data frame para que os voos do mesmo destino estejam juntos:

arrange(hflights2,DepTime) %>% glimpse()

Obtendo um tibble com as colunas UniqueCarrier e Distance, onde Distance é ordenada em ordem decrescente:

library(tidyverse) hflights2 %>% select(UniqueCarrier,Distance) %>% arrange(desc(Distance))

Função summarise()

As funções summarise são utilizadas em conjunto com as seguintes funções de agregação:

  • min(): valor mínimo
  • max(): valor máximo
  • mean(): valor médio
  • sd(): desvio padrão
  • var(): variância

Retornando o menor valor de tempo de voo:

hflights2 %>% summarise(min_airtime = min(AirTime,na.rm = TRUE)) ## # A tibble: 1 x 1 ## min_airtime ## <dbl> ## 1 11 # sem usar o pipe # summarise(hflights2,min_airtime = min(AirTime,na.rm = TRUE))

Para cada companhia aérea, calculando a média dos tempos de voo. É possível ignorar os valores NA’s da coluna AirTime adicionando a opção na.rm = TRUE na função mean():

MedFly <- hflights2 %>% group_by(UniqueCarrier) %>% summarise(Time_avg = mean(AirTime, na.rm = TRUE)) MedFly ## # A tibble: 15 x 2 ## UniqueCarrier Time_avg ## <chr> <dbl> ## 1 AA 69.7 ## 2 AS 254. ## 3 B6 184. ## 4 CO 145. ## 5 DL 97.8 ## 6 EV 104. ## 7 F9 125. ## 8 FL 92.7 ## 9 MQ 93.8 ## 10 OO 113. ## 11 UA 157. ## 12 US 134. ## 13 WN 86.7 ## 14 XE 83.2 ## 15 YV 122. # Posso querer saber a distância média para ter uma melhor noção do tempo. MedDist<- hflights2 %>% group_by(UniqueCarrier) %>% summarise(Dist_avg = mean(Distance,na.rm= TRUE)) MedDist ## # A tibble: 15 x 2 ## UniqueCarrier Dist_avg ## <chr> <dbl> ## 1 AA 484. ## 2 AS 1874 ## 3 B6 1428 ## 4 CO 1098. ## 5 DL 723. ## 6 EV 776. ## 7 F9 883. ## 8 FL 685. ## 9 MQ 651. ## 10 OO 820. ## 11 UA 1178. ## 12 US 981. ## 13 WN 607. ## 14 XE 589. ## 15 YV 939. MedDist_time <- add_column(MedDist,Med_Fly = MedFly$Time_avg) MedDist_time ## # A tibble: 15 x 3 ## UniqueCarrier Dist_avg Med_Fly ## <chr> <dbl> <dbl> ## 1 AA 484. 69.7 ## 2 AS 1874 254. ## 3 B6 1428 184. ## 4 CO 1098. 145. ## 5 DL 723. 97.8 ## 6 EV 776. 104. ## 7 F9 883. 125. ## 8 FL 685. 92.7 ## 9 MQ 651. 93.8 ## 10 OO 820. 113. ## 11 UA 1178. 157. ## 12 US 981. 134. ## 13 WN 607. 86.7 ## 14 XE 589. 83.2 ## 15 YV 939. 122.

Contando a quantidade de voos para cada dia do ano. Será Utilizada a função n() para contar a quantidade de linhas no grupo:

total_voos_dia <- hflights2 %>% group_by(Month,DayofMonth) %>% summarise(total = n()) glimpse(total_voos_dia) ## Observations: 365 ## Variables: 3 ## $ Month <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... ## $ DayofMonth <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ... ## $ total <int> 552, 678, 702, 583, 590, 660, 661, 500, 602, 659, 5... total_voos_mes <- hflights2 %>% group_by(Month) %>% summarise(total = n()) total_voos_mes ## # A tibble: 12 x 2 ## Month total ## <int> <int> ## 1 1 18910 ## 2 2 17128 ## 3 3 19470 ## 4 4 18593 ## 5 5 19172 ## 6 6 19600 ## 7 7 20548 ## 8 8 20176 ## 9 9 18065 ## 10 10 18696 ## 11 11 18021 ## 12 12 19117

Selecionando as colunas Month, AirTime e UniqueCarrier [select(Month, AirTime, UniqueCarrier)] e obtendo as cinco primeiras informações [slice(1:5)] para cada mês do primeiro trimestre [filter(between(Month, 1,3))] Foi utilizada a função slice() (parecida com a função head mas seleciona os X primeiros itens de cada categoria diferente) para obter as cinco primeiras informações para cada grupo:

hflights %>% select(Month, AirTime, UniqueCarrier) %>% filter(between(Month, 1,3)) %>% group_by(Month) %>% slice(1:5) ## # A tibble: 15 x 3 ## # Groups: Month [3] ## Month AirTime UniqueCarrier ## <int> <int> <chr> ## 1 1 40 AA ## 2 1 45 AA ## 3 1 48 AA ## 4 1 39 AA ## 5 1 44 AA ## 6 2 73 AA ## 7 2 42 AA ## 8 2 40 AA ## 9 2 39 AA ## 10 2 40 AA ## 11 3 42 AA ## 12 3 49 AA ## 13 3 43 AA ## 14 3 45 AA ## 15 3 43 AA

Selecionando as colunas Month, AirTime e UniqueCarrier, filtrando para o primeiro trimestre e obtendo um ranking dos cincos valores mais altos de Airtime para estes meses:

hflights %>% select(Month, AirTime, UniqueCarrier) %>% filter(between(Month, 1,3)) %>% group_by(Month) %>% top_n(5,AirTime) %>% arrange(Month,AirTime) ## # A tibble: 16 x 3 ## # Groups: Month [3] ## Month AirTime UniqueCarrier ## <int> <int> <chr> ## 1 1 493 CO ## 2 1 493 CO ## 3 1 494 CO ## 4 1 496 CO ## 5 1 497 CO ## 6 2 499 CO ## 7 2 504 CO ## 8 2 507 CO ## 9 2 508 CO ## 10 2 549 CO ## 11 3 494 CO ## 12 3 494 CO ## 13 3 495 CO ## 14 3 496 CO ## 15 3 496 CO ## 16 3 500 CO

Funções join

Fazer um join ou um merge nada mais é do que juntar dois conjuntos de dados por meio de um ou mais campos em comum (chaves/key). Existem algumas vantagens de se utilizar o join (dplyr) em relação ao merge (Base R) e ao SQL:

  • Sempre preserva a ordem das linhas originais;
  • Sintaxe mais intuitiva;
  • Pode ser aplicado em diferentes tipos de dados.

Podemos dividir as funções do tipo join em 2 tipos:

  • Mutating joins (essa função lhe permite combinar 2 tabelas. Primeiramente ela faz um matching entre as observações através das variáveis-chave, em seguida, copia as variáveis de uma tabela para a a outra): left_join(), right_join(),inner_join() e full_join();

  • Filtering joins (junta tabelas da mesma maneira que a “Mutating joins”, contudo, afeta as observações e não apenas as variáveis): semi_join() e anti_join()

Temos ainda, no pacote dplyr, as funções union(), intersect(), setdiff(), setequal() que também serão úteis para unir e comparar um conjuntos de dados. Nossas aplicações serão baseadas no banco de dados relacional nycflights13. Use a função help() para entender um pouco mais sobre a nossa base, as principais variáveis estão descritas abaixo:

  • Airlines: permite procurar o nome completo do operador através do código abreviado
  • Airports: fornece informações sobre cada aeroporto, identificadas pelo código do aeroporto
  • Planes: fornece informações sobre cada avião, identificados pelo seu tailnum
  • Weather: dados climáticos para cada aeroporto de Nova York por hora

Como temos uma estrutura de banco de dados relacional, é importante descrevermos as chaves para unir as bases de dados:

  • flights se conecta à planes através de uma variável única, tailnum
  • flights se conecta à airlines através de uma variável única, carrier
  • flights se conecta à airports de duas formas: através das variáveis origin e dest
  • flights se conecta à weather através de origin (location), year, month, day e hour (time)

Vamos carregar o pacote. Temos aqui os dados de 336.776 voos que partiram de Nova Iorque em 2013.

library(nycflights13) glimpse(flights) ## Observations: 336,776 ## Variables: 19 ## $ year <int> 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013,... ## $ month <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,... ## $ day <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,... ## $ dep_time <int> 517, 533, 542, 544, 554, 554, 555, 557, 557, 55... ## $ sched_dep_time <int> 515, 529, 540, 545, 600, 558, 600, 600, 600, 60... ## $ dep_delay <dbl> 2, 4, 2, -1, -6, -4, -5, -3, -3, -2, -2, -2, -2... ## $ arr_time <int> 830, 850, 923, 1004, 812, 740, 913, 709, 838, 7... ## $ sched_arr_time <int> 819, 830, 850, 1022, 837, 728, 854, 723, 846, 7... ## $ arr_delay <dbl> 11, 20, 33, -18, -25, 12, 19, -14, -8, 8, -2, -... ## $ carrier <chr> "UA", "UA", "AA", "B6", "DL", "UA", "B6", "EV",... ## $ flight <int> 1545, 1714, 1141, 725, 461, 1696, 507, 5708, 79... ## $ tailnum <chr> "N14228", "N24211", "N619AA", "N804JB", "N668DN... ## $ origin <chr> "EWR", "LGA", "JFK", "JFK", "LGA", "EWR", "EWR"... ## $ dest <chr> "IAH", "IAH", "MIA", "BQN", "ATL", "ORD", "FLL"... ## $ air_time <dbl> 227, 227, 160, 183, 116, 150, 158, 53, 140, 138... ## $ distance <dbl> 1400, 1416, 1089, 1576, 762, 719, 1065, 229, 94... ## $ hour <dbl> 5, 5, 5, 5, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5,... ## $ minute <dbl> 15, 29, 40, 45, 0, 58, 0, 0, 0, 0, 0, 0, 0, 0, ... ## $ time_hour <dttm> 2013-01-01 05:00:00, 2013-01-01 05:00:00, 2013...

O pacote inclui, além da tabela flights, outras 4 tibbles (airlines, airports, planes, weather) relacionadas à esta:

glimpse(airlines) ## Observations: 16 ## Variables: 2 ## $ carrier <chr> "9E", "AA", "AS", "B6", "DL", "EV", "F9", "FL", "HA", ... ## $ name <chr> "Endeavor Air Inc.", "American Airlines Inc.", "Alaska... glimpse(airports) ## Observations: 1,458 ## Variables: 8 ## $ faa <chr> "04G", "06A", "06C", "06N", "09J", "0A9", "0G6", "0G7", ... ## $ name <chr> "Lansdowne Airport", "Moton Field Municipal Airport", "S... ## $ lat <dbl> 41.13047, 32.46057, 41.98934, 41.43191, 31.07447, 36.371... ## $ lon <dbl> -80.61958, -85.68003, -88.10124, -74.39156, -81.42778, -... ## $ alt <int> 1044, 264, 801, 523, 11, 1593, 730, 492, 1000, 108, 409,... ## $ tz <dbl> -5, -6, -6, -5, -5, -5, -5, -5, -5, -8, -5, -6, -5, -5, ... ## $ dst <chr> "A", "A", "A", "A", "A", "A", "A", "A", "U", "A", "A", "... ## $ tzone <chr> "America/New_York", "America/Chicago", "America/Chicago"... glimpse(planes) ## Observations: 3,322 ## Variables: 9 ## $ tailnum <chr> "N10156", "N102UW", "N103US", "N104UW", "N10575",... ## $ year <int> 2004, 1998, 1999, 1999, 2002, 1999, 1999, 1999, 1... ## $ type <chr> "Fixed wing multi engine", "Fixed wing multi engi... ## $ manufacturer <chr> "EMBRAER", "AIRBUS INDUSTRIE", "AIRBUS INDUSTRIE"... ## $ model <chr> "EMB-145XR", "A320-214", "A320-214", "A320-214", ... ## $ engines <int> 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2... ## $ seats <int> 55, 182, 182, 182, 55, 182, 182, 182, 182, 182, 5... ## $ speed <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N... ## $ engine <chr> "Turbo-fan", "Turbo-fan", "Turbo-fan", "Turbo-fan... glimpse(weather) ## Observations: 26,130 ## Variables: 15 ## $ origin <chr> "EWR", "EWR", "EWR", "EWR", "EWR", "EWR", "EWR", "E... ## $ year <dbl> 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 201... ## $ month <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... ## $ day <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ... ## $ hour <int> 0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ... ## $ temp <dbl> 37.04, 37.04, 37.94, 37.94, 37.94, 39.02, 39.02, 39... ## $ dewp <dbl> 21.92, 21.92, 21.92, 23.00, 24.08, 26.06, 26.96, 28... ## $ humid <dbl> 53.97, 53.97, 52.09, 54.51, 57.04, 59.37, 61.63, 64... ## $ wind_dir <dbl> 230, 230, 230, 230, 240, 270, 250, 240, 250, 260, 2... ## $ wind_speed <dbl> 10.35702, 13.80936, 12.65858, 13.80936, 14.96014, 1... ## $ wind_gust <dbl> 11.918651, 15.891535, 14.567241, 15.891535, 17.2158... ## $ precip <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... ## $ pressure <dbl> 1013.9, 1013.0, 1012.6, 1012.7, 1012.8, 1012.0, 101... ## $ visib <dbl> 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,... ## $ time_hour <dttm> 2012-12-31 22:00:00, 2012-12-31 23:00:00, 2013-01-...

Como comparar data.frame para achar arquivos duplicados

Estrutura relacional do nycflights13 em (Grolemund,2017)

Função inner_join()

A função inner_join(x, y) retorna todas as linhas de x onde existem valores correspondentes em y, mantendo as colunas de x e y. Se houver múltiplas combinações entre x e y todas as combinações das correspondências são retornadas. É o tipo mais simples de join, que combina pares de observações sempre que suas chaves são iguais.

Como comparar data.frame para achar arquivos duplicados

Ilustração de como funciona a função inner_join

O resultado da função inner_join é um novo data frame que contêm a chave, os valores de x e os valores de y. Usamos o argumento by para informar ao dplyr qual variável é a chave. Veja o exemplo abaixo: as tabelas flights e planes estão conectadas através da chave “tailnum”:

tab_inner_join <- inner_join(flights,planes, by="tailnum") dim(flights) ## [1] 336776 19 dim(planes) ## [1] 3322 9 dim(tab_inner_join) ## [1] 284170 27 head(tab_inner_join,10) ## # A tibble: 10 x 27 ## year.x month day dep_time sched_dep_time dep_delay arr_time ## <int> <int> <int> <int> <int> <dbl> <int> ## 1 2013 1 1 517 515 2 830 ## 2 2013 1 1 533 529 4 850 ## 3 2013 1 1 542 540 2 923 ## 4 2013 1 1 544 545 -1 1004 ## 5 2013 1 1 554 600 -6 812 ## 6 2013 1 1 554 558 -4 740 ## 7 2013 1 1 555 600 -5 913 ## 8 2013 1 1 557 600 -3 709 ## 9 2013 1 1 557 600 -3 838 ## 10 2013 1 1 558 600 -2 849 ## # ... with 20 more variables: sched_arr_time <int>, arr_delay <dbl>, ## # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>, ## # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, ## # time_hour <dttm>, year.y <int>, type <chr>, manufacturer <chr>, ## # model <chr>, engines <int>, seats <int>, speed <int>, engine <chr>

observação: tanto o merge() do R Base quanto o inner_join() do dplyr tentam descobrir as chaves em comum buscando campos com o mesmo nome. Mas vamos supor que os campos chave tivessem nomes diferentes (o que é bem comum). No R Base usamos by.x e by.y para especificar o nome do campo chave do primeiro e segundo data frame. Na função inner_join() do dplyr usamos um vetor no formato c(“chave.x” = “chave.y”).

A função inner_join() retorna todos os campos de ambos os data frames, mas somente as linhas em que as chaves são iguais. Podemos estranhar o fato da tabela (tab_inner_join) conter um número de linhas menor que a tabela flights, contudo, isso significa que existem aviões que não estão identificados na tabela plane. Uma boa forma de checar isso é usando o anti_join().

Função anti_join(x, y)

A função anti_join(x, y) retorna todas as linhas de x para as quais não existem valores correspondentes em y, mantendo apenas as colunas de x. É considerado um “filtering join”.

Como comparar data.frame para achar arquivos duplicados

Ilustração de como funciona a função anti_join()

tab_anti_join <- anti_join(flights,planes,by="tailnum") dim(tab_anti_join)[1] + dim(tab_inner_join)[1] ## [1] 336776 dim(flights)[1] ## [1] 336776

Observa-se que a quantidade de linhas cujas chaves estão em flights mas não estão em planes(representadas por tab_anti_join) somadas às linhas que estão em ambas (representadas por tab_inner_join) é exatamente a mesma que na base original flights, conforme esperado.

Função semi_join(x, y)

A função semi_join(x, y) retorna todas as linhas de x para as quais existem valores correspondente em y, mantendo apenas as x. A função semi_join(x, y) difere da função inner_join(x, y) porque a segunda retorna uma linha de “x” para cada valor correspondente de “y”, enquanto a primeira NUNCA irá duplicar valores x.

Pode-se dizer que é um “filtering join” complementar a função anti_join(x, y). Na prática, ela vai retornar as mesmas linhas que a função inner_join() (sem duplicar), e apenas vai exercer a função filtrar a tabela x. Isto é, diferentemente da função inner_join(), ela não retorna as colunas de y, apenas identifica se existe correpondência.

Como comparar data.frame para achar arquivos duplicados

Ilustração de como funciona a função semi_join(x, y)

tab_semi_join <- semi_join(flights,planes,by="tailnum") dim(tab_semi_join) ## [1] 284170 19 dim(tab_inner_join) ## [1] 284170 27

Neste exemplo, o número de linhas resultante das função semi_join() e inner_join() foram os mesmos pois não havia nenhum valor duplicado da variável chave tailnum na tabela planes.

Função full_join(x, y)

A função full_join(x, y) retorna todas as linhas e todas as colunas tanto de x quanto de y. Retorna “NA” no caso de não haja valor correspondente.

Como comparar data.frame para achar arquivos duplicados

Ilustração de como funciona a função full_join(x, y)

tab_full_join <- full_join(flights,planes,by="tailnum") dim(tab_full_join) ## [1] 336776 27 ## observe que algumas observações recebem NA tail(tab_full_join) ## # A tibble: 6 x 27 ## year.x month day dep_time sched_dep_time dep_delay arr_time ## <int> <int> <int> <int> <int> <dbl> <int> ## 1 2013 9 30 NA 1842 NA NA ## 2 2013 9 30 NA 1455 NA NA ## 3 2013 9 30 NA 2200 NA NA ## 4 2013 9 30 NA 1210 NA NA ## 5 2013 9 30 NA 1159 NA NA ## 6 2013 9 30 NA 840 NA NA ## # ... with 20 more variables: sched_arr_time <int>, arr_delay <dbl>, ## # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>, ## # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>, ## # time_hour <dttm>, year.y <int>, type <chr>, manufacturer <chr>, ## # model <chr>, engines <int>, seats <int>, speed <int>, engine <chr>

É interessante notar que como as bases flights e planes possuiam ambas, originalmente, uma coluna year, sendo que ela não foi usada como chave para o join (consideramos apenas o tailnum), o dplyr renomeou estas colunas como year.x e year.y para poder distinguir entre aquela que veio da base flights (base x) e aquela que veio da base planes(base y).

colnames(tab_full_join) ## [1] "year.x" "month" "day" "dep_time" ## [5] "sched_dep_time" "dep_delay" "arr_time" "sched_arr_time" ## [9] "arr_delay" "carrier" "flight" "tailnum" ## [13] "origin" "dest" "air_time" "distance" ## [17] "hour" "minute" "time_hour" "year.y" ## [21] "type" "manufacturer" "model" "engines" ## [25] "seats" "speed" "engine"

Função left_join(x, y)

A função left_join(x, y) retorna todas as linhas de x e todas as colunas, tanto de x quanto de y. Se houver múltiplas correspondências entre x e y, todas as combinações de correspondências serão retornadas.

tab_left_join <- left_join(flights,planes,by="tailnum") dim(tab_left_join) ## [1] 336776 27

Como comparar data.frame para achar arquivos duplicados

Ilustração de como funciona a função left_join(x, y)

As ferramentas de visualização precisam ter como entrada dados “tidy”“, porque descrevem a visualização como um mapeamento entre variáveis e propriedades estéticas do gráfico (por exemplo, posição, tamanho, forma e cor). É necessario para a maioria das ferramentas gráficas em R que os dados estejam neste formato (Wickham,2009)

É possível contruir diversos gráficos no R, mas eles não são os mais práticos para uma análise dinâmica de bases de dados. Nesse contexto, o pacote ggplot2 é uma alternativa interessante.

O ggplot2 é um pouco diferente de outros pacotes gráficos pois segue uma lógica distinta; não se trata de desenhar elementos na tela; a sintaxe do ggplot2 segue uma “gramática de gráficos estatísticos” baseada nas ideias de (Wilkinson,2005), de modo que a criação dos gráfico seja de uma forma declarativa (Wickham,2016).

Um gráfico estatístico pode ser definido como um mapeamento dos dados para propriedades estéticas (cores, formas, tamanhos) e geométricas (pontos, barras, linhas) da tela. Também podemos realizar transformações estatísticas e diferentes facetas para cada subconjunto dos dados. É a combinação de todas essas camadas que formam o gráfico estatístico.

Deste modo, os gráficos no ggplot2 são construídos por meio da adição de camadas. Cada camada representa um tipo de mapeamento ou personalização do gráfico.

Observe que o primeiro argumento da função ggplot é um data frame. A função aes() descreve como as variáveis são mapeadas em aspectos visuais de formas geométricas definidas pelos “geoms”. No exemplo abaixo, essas formas geométricas são barras, selecionados pela função geom_bar(), gerando, assim, um gráfico de barras. A combinação dessas duas camadas define o tipo de gráfico a construir.

A função ggplot requer, no mínimo:

  • Uma base de dados (data frame)
  • Definição de atributos estéticos (aesthetics)
  • A forma dos objetos geométricos (geom)

Podemos ainda acrescentar elementos e personalizar os gráficos com:

  • Transformações estatísticas
  • Facetas
  • Demais ajustes(legendas, eixos, escalas, etc).

O símbolo + é usado para adicionar camadas a um gráfico criado via ggplot().

No exemplo apresentado, destacamos a composição de camadas de um gráfico construído com ggplot() e sua sintaxe. Usamos um gráfico de barras (geom_bar) mas qualquer outro tipo de gráfico seguiria a mesma lógica. Algumas outras possibilidades importantes são:

  • geom_line: para retas definidas por pares (x,y)
  • geom_boxplot: para boxplots
  • geom_histogram: para histogramas
library(nycflights13) library(tidyverse) library(hflights) library(ggplot2)

Mudando o tipo das variáveis:

hflights$UniqueCarrier <- as.factor(hflights$UniqueCarrier) hflights$DayOfWeek <- as.factor(hflights$DayOfWeek)

Selecionando linhas com voos atrasados:

delay <- hflights[which(hflights$ArrDelay > 0), -(1:3)] # tirei as variáveis "Cancelled" "CancellationCode" "Diverted"

Vamos construir camada por camada o gráfico de atrasos por dia da semana por aeroporto.

  1. Acrescenta-se o data frame onde se encontram os dados:
ggplot(delay)

Como comparar data.frame para achar arquivos duplicados

Obtivemos uma tela em branco pois, apesar de termos definido os dados para a função, precisamos especificar como as observações serão mapeadas nos aspectos visuais do gráfico e quais formas geométricas serão utilizadas para isso. Cada camada do gráfico representará um tipo de mapeamento ou personalização.

ggplot(delay, aes(x=UniqueCarrier))
  1. Especifica-se a forma geométrica utilizada no mapeamento das observações (barras):
ggplot(delay, aes(x=UniqueCarrier)) + geom_bar(aes(group = DayOfWeek))

Como comparar data.frame para achar arquivos duplicados

  1. Personaliza-se o gráfico preenchendo o interior das barras com diferentes tons de acordo com o dia da semana e posiciona-se as legendas no centro do gráfico:
ggplot(delay, aes(UniqueCarrier)) + geom_bar(aes(group = DayOfWeek, fill = DayOfWeek))+ theme(legend.position=c(.1,.5))

Como comparar data.frame para achar arquivos duplicados

Gráficos estáticos, como aqueles construídos através do pacote ggplot, são muito úteis quando estamos realizando uma apresentação através de um relatório impresso, por exemplo. No entanto, ao apresentar análises via meio digital, gráficos dinâmicos podem deixar nossa apresentação mais compreensível e atrativa.

Atualmente, a ferramenta mais popular para criar gráficos dinâmicos no R é o plotly. É possível, ainda, utilizar o Plotly através do website. Exemplos de como fazer gráficos de barras, gráficos de área, histogramas, entre outros, são detalhados em (Plotly,2015).

No R, o nome do pacote é o próprio nome da ferramenta: plotly

library(plotly)

Vamos fazer aqui uma análise com um tipo de gráfico simples, de barras, com o objetivo de visualisar os dias das semana em que as pessoas mais viajam:

day_week <- hflights %>% group_by(DayOfWeek) %>% #agrupei os dados por dia da semana summarize(day_week_sum = n()) %>% #criei uma nova tabela com os dias da semana arrange(desc(day_week_sum)) # coloquei em ordem decrescente day_week # podemos observar que o dia em que as pessoas mais viajam é sexta. ## # A tibble: 7 x 2 ## DayOfWeek day_week_sum ## <fct> <int> ## 1 5 34972 ## 2 4 34902 ## 3 1 34360 ## 4 7 32058 ## 5 3 31926 ## 6 2 31649 ## 7 6 27629 day_week$DayOfWeek <- as.factor(day_week$DayOfWeek) levels(day_week$DayOfWeek) <- c("Seg","Ter","Qua","Qui","Sex","Sab","Dom") day_week #inserimos os dias da semana ## # A tibble: 7 x 2 ## DayOfWeek day_week_sum ## <fct> <int> ## 1 Sex 34972 ## 2 Qui 34902 ## 3 Seg 34360 ## 4 Dom 32058 ## 5 Qua 31926 ## 6 Ter 31649 ## 7 Sab 27629 plot_ly(day_week, x = ~DayOfWeek, y = ~day_week_sum, # no eixo x colocamos os dias da semana e no y a soma dos voos color = ~DayOfWeek, text = ~paste("p_day_week: ", day_week$day_week_sum), #texto que irá aparecer nas barras type = "bar") %>% layout(title = "Dias da semana mais populares de 2011", xaxis = list(title = "Dias da semana"), yaxis = list(title = "Total de passageiros"))

A vantagem aqui é poder saber o número exato de passageiros que pegaram um voo em cada data, ao passar o cursor em cima das respectivas barras.

Existe, ainda, a possibilidade de integração do ggplot com o plotly. Basta criar, como vimos anteriormente, o gráfico com o ggplot e então, executar a função ggplotly(), inserindo como argumento o nome do gráfico criado.

No modelagem dos dados é importante ter ferramentas que trabalhem bem com o operador pipe e com as funcões de manipulação e visualização de dados. Para tal, utilizaremos os pacotes modelr e broom do R.

library(modelr) library(broom)

Como exemplo, vamos estimar o valor esperado dos atrasos de chegada (coluna de nome ArrDelay) mediante regressão linear. Para formular a equação de regressão é preciso determinar as variáveis explicativas o independentes. O R também conta com ferramentas para este propósito, como o pacote corrplot, que mostra visualmente a matriz de correlação entre as varíaveis.

library(corrplot)

Filtrando o data frame para quando “Origin = IAH, DepDelay > 0 e ArrDelay > 0” e fazendo o gráfico de correlação entre as variáveis ArrDelay, DepDelay, AirTime, DepTime:

rm(hflights2) ?hflights ## starting httpd help server ... done hflights2 <- hflights %>% filter(Origin == "IAH", DepDelay > 0, ArrDelay > 0) %>% select(ArrDelay,DepDelay,AirTime,DepTime) %>% #varrival delay mutate(ArrDelay = as.integer(ArrDelay)) %>% mutate(DepDelay = as.integer(DepDelay)) %>% # departure delay mutate(AirTime = as.integer(AirTime)) %>% # fligth time mutate(DepTime = as.integer(DepTime)) # departure time hflights2 %>% cor(use = "everything", method = "spearman") %>% corrplot(type="lower", tl.col = "black", diag=FALSE)

Como comparar data.frame para achar arquivos duplicados

Como mostrado no gráfico anterior, as variáveis ArrDelay e DepDelay estão altamente correlacionadas.

Agora, vamos estimar um modelo simples:

Primeiramente serão particionados os dados nos conjuntos train e test com a função resample_partition(). Os dados serão divididos em 70% para treino e 30% para teste.

hflights2_part<- resample_partition(hflights2, c(test = 0.3, train = 0.7)) train <- as.data.frame(hflights2_part$train) test <- as.data.frame(hflights2_part$test)

A seguir estima-se um modelo de regresão linear com o objetivo de prever possíveis atrasos de chegada (coluna ArrDelay), a partir dos atrasos de partida (coluna DepDelay):

model <- lm(formula= ArrDelay ~ DepDelay, data = train)

Fazendo um resumo do modelo com a função summary():

summary(model) ## ## Call: ## lm(formula = ArrDelay ~ DepDelay, data = train) ## ## Residuals: ## Min 1Q Median 3Q Max ## -46.789 -6.995 -1.669 4.877 149.952 ## ## Coefficients: ## Estimate Std. Error t value Pr(>|t|) ## (Intercept) 3.419215 0.076374 44.77 <2e-16 *** ## DepDelay 0.946959 0.001522 622.38 <2e-16 *** ## --- ## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 ## ## Residual standard error: 12.63 on 40552 degrees of freedom ## Multiple R-squared: 0.9052, Adjusted R-squared: 0.9052 ## F-statistic: 3.874e+05 on 1 and 40552 DF, p-value: < 2.2e-16

Vamos simplificar o que observamos acima utilizando a funcão tidy():

tidy(model) ## term estimate std.error statistic p.value ## 1 (Intercept) 3.4192150 0.076374031 44.76934 0 ## 2 DepDelay 0.9469587 0.001521503 622.38373 0

Existem várias maneiras de verificar a precisão do modelo mediante o pacote modelr:

rsquare(model, train) ## [1] 0.9052332 rmse(model, train) ## [1] 12.62653 mae(model, train) ## [1] 8.637208

Para adicionar uma previsão dos valores da variável ArrDelay ao data frame é utilizada a função add_predictions(). Esta função adiciona uma nova coluna de nome pred ao data frame de teste:

hflights_pred <- test %>% add_predictions(model) glimpse(hflights_pred) ## Observations: 17,379 ## Variables: 5 ## $ ArrDelay <int> 44, 43, 6, 11, 35, 13, 11, 3, 14, 22, 6, 18, 31, 56, ... ## $ DepDelay <int> 43, 41, 2, 21, 40, 24, 25, 24, 31, 12, 8, 23, 33, 70,... ## $ AirTime <int> 41, 39, 49, 44, 44, 43, 44, 44, 45, 113, 117, 110, 11... ## $ DepTime <int> 1443, 1441, 722, 741, 2045, 2029, 2030, 2029, 2036, 1... ## $ pred <dbl> 44.138439, 42.244522, 5.313132, 23.305348, 41.297563,...

Baumer, B.; Kaplan, D.; Horton, N. Modern Data Science with R. 2017.

Cielen, D; Meysman, A; Ali, M. Introducing Data Science. 2016

Grolemund, G.; Wickham, H. R for Data Science. 2017. Disponível em: http://r4ds.had.co.nz/

Ismay, Ch.; Kim, A. An Introduction to Statistical and Data Sciences via R. 2018. Disponível em: https://ismayc.github.io/moderndiver-book/index.html

Kaggle Inc. The State of Data Science & Machine Learning. 2017. Disponível em: https://www.kaggle.com/surveys/2017.

Müller, K.; Wickham, H. tibble: Simple Data Frames. 2018. Disponível em: https://cran.r-project.org/web/packages/tibble/

Peng, R. R programming for DataScience. 2015. Disponível em: https://www.cs.upc.edu/~robert/teaching/estadistica/rprogramming.pdf

Ren, K. pipeR: Multi-Paradigm Pipeline Implementation. 2016. Disponível em: https://cran.r-project.org/web/packages/pipeR/

US Census Bureau. 2013 ACS PUMS DATA DICTIONARY. 2015. Disponível em: https://www2.census.gov/programs-surveys/acs/tech_docs/pums/data_dict/PUMSDataDict13.txt

US Census Bureau. 2013 American Community Survey. 2017. Disponível em: https://www.kaggle.com/census/2013-american-community-survey

Wickham, H. Tidy Data. 2014. Journal of Statistical Software Volume 59 (Issue 10). Disponível em: https://www.jstatsoft.org/index.php/jss/article/view/v059i10/v59i10.pdf.