4 Manipulando os dados
Neste capítulo, usaremos estes pacotes:
library(nycflights13)
library(tidyverse)
Após obter uma boa fonte de dados, e carregá-los para poder trabalhá-los no R, você certamente precisará realizar algumas limpezas e manipulações para que os dados estejam no ponto ideal para as fases finais de uma análise: execução de modelos econométricos, visualizações de dados, tabelas agregadas, relatórios etc. A realidade é que, na prática, os dados nunca estarão do jeito que você de fato precisa. Portanto, é fundamental dominar técnicas de manipulação de dados.
Entendamos a manipulação de dados como o ato de transformar, reestruturar, limpar, agregar e juntar os dados. Para se ter uma noção da importância dessa fase, alguns estudiosos da área de Ciência de Dados costumam afirmar que 80% do trabalho é encontrar uma boa fonte de dados, limpar e preparar os dados, sendo que os 20% restantes seriam o trabalho de aplicar modelos e realizar alguma análise propriamente dita.
80% of data analysis is spent on the process of cleaning and preparing the data (Dasu and Johnson, 2003).
Data preparation is not just a first step, but must be repeated many over the course of analysis as new problems come to light or new data is collected (Hadley Wickham).
4.1 Tipos de Variáveis e Colunas
Existem diversos tipos de objetos, e cada tipo “armazena” um conteúdo diferente, desde tabelas de dados recém-carregados a textos, números, ou simplesmente a afirmação de verdadeiro ou falso (Boleano).
<- 928
inteiro <- 5e2
outro.inteiro <- 182.93
decimal <- 'exportação'
caracter <- TRUE
logico <- FALSE outro.logico
Repare nas atribuições acima. Usaremos a função class()
para ver o tipo de cada uma:
class(inteiro)
## [1] "numeric"
class(outro.inteiro)
## [1] "numeric"
class(decimal)
## [1] "numeric"
class(caracter)
## [1] "character"
class(logico)
## [1] "logical"
class(outro.logico)
## [1] "logical"
Esses são alguns dos tipos básicos de objetos/variáveis no R. Para valores inteiros ou decimais, numeric
, character
para valores textuais e logical
para valores lógicos (verdadeiro ou falso). Existe também o tipo integer
, que representa apenas números inteiros, sem decimais, porém, na maioria das vezes, o R interpreta o integer
como numeric
, pois o integer
também é um numeric
.
Além dos tipos básicos, existem também os tipos “complexos,” que são vector
, array
, matrix
, list
, data.frame
e factor
.
Data frame é, provavelmente, o tipo de dado complexo mais utilizado em R. É nele que você armazena conjuntos de dados estruturados em linhas e colunas. Um data frame possui colunas nomeadas, sendo que todas as colunas possuem a mesma quantidade de linhas. Imagine o dataframe
como uma tabela.
class(df)
## [1] "spec_tbl_df" "tbl_df" "tbl" "data.frame"
dim(df)
## [1] 144367 31
Percebeu o termo tbl
no output acima? Significa tibble()
, que, conforme o próprio pacote chamado tibble
descreve, corresponde a uma moderna implementação da estrutura data.frame
. A classe tibble
não possui algumas deficiências da classe data.frame
, por isso a usaremos sempre que possui. É muito simples transformar um data.frame
em tibble
.
# carregando um dataset pronto do R
data(iris)
# verificando a classe
class(iris)
## [1] "data.frame"
# transformando para tibble
<- as_tibble(iris)
iris_tbl # verificando a classe do novo objeto
class(iris_tbl)
## [1] "tbl_df" "tbl" "data.frame"
Imprima no seu console os dois objetos e note a diferença:
print(iris)
print(iris_tbl)
Outro tipo que já utilizamos bastante até agora, mas que não foi detalhado, é o vector
, ou vetor. Vetores são sequências unidimensionais de valores de um mesmo tipo:
#faça as seguintes atribuições
<- c('tipo1', 'tipo2', 'tipo3', 'tipo4')
vetor.chr <- c(1, 2, 5, 8, 1001)
vetor.num <- c(rep(2, 50)) #usando funcão para repetir números
vetor.num.repetidos <- c(seq(from=0, to=100, by=5)) #usando função para criar sequências
vetor.num.sequencia <- c(TRUE, TRUE, TRUE, FALSE, FALSE)
vetor.logical ##veja o conteúdo das variáveis
vetor.chr
## [1] "tipo1" "tipo2" "tipo3" "tipo4"
vetor.num
## [1] 1 2 5 8 1001
vetor.num.repetidos
## [1] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
vetor.num.sequencia
## [1] 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100
vetor.logical
## [1] TRUE TRUE TRUE FALSE FALSE
Para a criação de vetores, usamos a função de combinação de valores c()
(combine). Esta função vai combinar todos os parâmetros em um único vetor. Lembre-se: vetores são sequências que contêm apenas um tipo de dado.
Conhecendo o data.frame
e o vector
, você será capaz de entender como os dois se relacionam. Cada coluna de um data frame é um vetor. Um data frame pode ter colunas de diferentes tipos, mas cada coluna só pode ter registros de um único tipo.
Ficará mais claro a seguir. Veja como se cria um data.frame
:
#cria-se diferentes vetores
<- c('João', 'José', 'Maria', 'Joana')
nome <- c(45, 12, 28, 31)
idade <- c(TRUE, FALSE, TRUE, TRUE)
adulto <- c('DF', 'SP', 'RJ', 'MG')
uf #cada vetor é uma combinação de elementos de um MESMO tipo de dados
#sendo assim, cada vetor pode ser uma coluna de um data.frame
<- data.frame(nome, idade, adulto, uf)
clientes clientes
## nome idade adulto uf
## 1 João 45 TRUE DF
## 2 José 12 FALSE SP
## 3 Maria 28 TRUE RJ
## 4 Joana 31 TRUE MG
str(clientes)
## 'data.frame': 4 obs. of 4 variables:
## $ nome : chr "João" "José" "Maria" "Joana"
## $ idade : num 45 12 28 31
## $ adulto: logi TRUE FALSE TRUE TRUE
## $ uf : chr "DF" "SP" "RJ" "MG"
4.1.1 Conversões de tipos de variáveis
Quando é feito o carregamento de algum arquivo de dados no R, ele tenta “deduzir” os tipos de dados de cada coluna. Nem sempre essa dedução sai correta e, eventualmente, você precisará converter de um tipo para o outro. O R tem algumas funções para fazer essas conversões.
class("2015")
## [1] "character"
as.numeric("2015")
## [1] 2015
class(55)
## [1] "numeric"
as.character(55)
## [1] "55"
class(3.14)
## [1] "numeric"
as.integer(3.14)
## [1] 3
as.numeric(TRUE)
## [1] 1
as.numeric(FALSE)
## [1] 0
as.logical(1)
## [1] TRUE
as.logical(0)
## [1] FALSE
O R também tenta “forçar a barra,” às vezes, para te ajudar. Quando você faz uma operação entre dois tipos diferentes, ele tenta fazer algo chamado coerção de tipos, ou seja, ele tenta converter os dados para que a operação faça sentido. Caso o R não consiga fazer a coerção, ele vai mostrar uma mensagem de erro.
Experimente os comandos a seguir no console:
7 + TRUE
2015 > "2016"
"2014" < 2017
# em alguns casos a coerção irá falhar ou dar resultado indesejado
6 > "100"
"6" < 5
1 + "1"
Recomendamos fortemente que sempre se realize as conversões explicitamente com as funções apropriadas ao invés de confiar na coerção do R, a não ser que se tenha certeza do resultado.
4.1.2 Outros tipos de variáveis
Existem outros tipos de variáveis bastante utilizados. Citaremos alguns deles, pois nesse curso utilizaremos muito pouco os demais tipos.
Tipo | Descrição | Dimensões | Homogêneo | |
---|---|---|---|---|
vector | Coleção de elementos simples. Todos os elementos precisam ser do mesmo tipo básico de dado | 1 | Sim | |
array | Coleção que se parece com o vector, mas é multidimensional | n | Sim | |
matrix | Tipo especial de array com duas dimensões | 2 | Sim | |
list | Objeto complexo com elementos que podem ser de diferentes tipos | 1 | Não | |
data.frame | Tipo especial de lista, onde cada coluna é um vetor de apenas um tipo e todas as colunas têm o mesmo número de registros. É o tipo mais utilizado para se trabalhar com dados | 2 | Não | |
factor | Tipo especial de vector, que só contém valores predefinidos (levels) e categóricos (characters). Não é possível adicionar novas categorias sem criação de novos levels | 1 | Não |
4.1.3 Valores faltantes e o ‘NA’
Em casos onde não existe valor em uma coluna de uma linha, o R atribui NA
. É muito comum lidar com conjuntos de dados que tenham ocorrências de NA
em alguns campos. É importante saber o que se fazer em casos de NA
, e nem sempre a solução será a mesma: varia de acordo com as suas necessidades.
Em algumas bases de dados, quem gera o dado atribui valores genéricos como 999
ou até mesmo um “texto vazio,” ' '
. Neste caso, você provavelmente terá que substituir esses valores “omissos” por NA
. Imputar dados em casos de NA
é uma das várias estratégias para lidar-se com ocorrência de missing no conjunto dos dados.
Seguem algumas funções úteis para lidar-se com NA
:
- A função
summary()
pode ser usada para averiguar a ocorrência deNA
. - A função
is.na()
realiza um teste para saber se a variável/coluna possui um valorNA
. retorna TRUE se forNA
e FALSE se não for. - A função
complete.cases()
retorna TRUE para as linhas em que todas as colunas possuem valores válidos (preenchidos) e FALSE para as linhas em que, em alguma coluna, existe umNA
. Ou seja, esta função diz quais são as linhas (amostras) completas em todas as suas características (campos). - Algumas funções possuem o argumento
na.rm
, ou semelhantes, para desconsiderarNA
no cálculo. É o caso da funçãomean()
ousum()
.
Por exemplo:
data("airquality") # carrega uma base de dados pré-carregada no R
summary(airquality) # verificando ocorrência de NA
## Ozone Solar.R Wind Temp Month Day
## Min. : 1.00 Min. : 7.0 Min. : 1.700 Min. :56.00 Min. :5.000 Min. : 1.0
## 1st Qu.: 18.00 1st Qu.:115.8 1st Qu.: 7.400 1st Qu.:72.00 1st Qu.:6.000 1st Qu.: 8.0
## Median : 31.50 Median :205.0 Median : 9.700 Median :79.00 Median :7.000 Median :16.0
## Mean : 42.13 Mean :185.9 Mean : 9.958 Mean :77.88 Mean :6.993 Mean :15.8
## 3rd Qu.: 63.25 3rd Qu.:258.8 3rd Qu.:11.500 3rd Qu.:85.00 3rd Qu.:8.000 3rd Qu.:23.0
## Max. :168.00 Max. :334.0 Max. :20.700 Max. :97.00 Max. :9.000 Max. :31.0
## NA's :37 NA's :7
is.na(airquality$Ozone)
## [1] FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [21] FALSE FALSE FALSE FALSE TRUE TRUE TRUE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE TRUE FALSE TRUE FALSE
## [41] FALSE TRUE TRUE FALSE TRUE TRUE FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## [61] TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
## [81] FALSE FALSE TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [101] FALSE TRUE TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE
## [121] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [141] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
4.2 Estruturas de Controle de Fluxo
Para auxiliar no processo de manipulação de dados, você eventualmente precisará de algumas técnicas e estruturas de controle de fluxo. Estruturas para controle de fluxo nada mais são do que loops e condições. São estruturas fundamentais para qualquer linguagem de programação.
4.2.1 If e Else
A estrutura condicional é algo bastante intuitivo. A estrutura de if (se) e else (então) usa os operadores lógicos apresentados anteriormente. Se a condição do if()
for verdadeira, executa-se uma tarefa específica, se for falsa, executa-se uma tarefa diferente. A estrutura parece algo do tipo:
if( variavel >= 500 ) {
#executa uma tarefa se operação resultar TRUE
else {
} #executa outra tarefa se operação resultar FALSE
}
Da mesma forma, existe uma função que gera o mesmo resultado, o ifelse()
(e uma do pacote dplyr
, o if_else()
).
ifelse(variavel >= 500, 'executa essa tarefa se TRUE', 'executa outra se FALSE')
Existe uma diferença entre as duas formas de “if else”: a estrutura if() {} else {}
só opera variáveis, uma por uma, já a estrutura ifelse()
opera vetores, ou seja, consegue fazer a comparação para todos os elementos. Isso faz com que a forma if() {} else {}
seja mais utilizada para comparações fora dos dados, com variáveis avulsas. Já a estrutura ifelse()
é mais usada para comparações dentro dos dados, com colunas, vetores e linhas.
Qualquer uma dessas estruturas pode ser “aninhada,” ou seja, encadeada. Por exemplo:
<- 9823
a
if(a >= 10000) {
<- 'VALOR ALTO'
b else if(a < 10000 & a >= 1000) {
} <- 'VALOR MEDIO'
b else if(a < 1000) {
} <- 'VALOR BAIXO'
b
}
b
## [1] "VALOR MEDIO"
Ou ainda:
<- 839
a <- ifelse(a >= 10000, 'VALOR ALTO', ifelse(a < 10000 & a >= 1000, 'VALOR MEDIO', 'VALOR BAIXO'))
c c
## [1] "VALOR BAIXO"
4.2.2 Loops
Trata-se de um dos conceitos mais importantes de qualquer linguagem de programação, em R não é diferente. Loops (ou laços) repetem uma sequência de comando quantas vezes você desejar, ou até que uma condição aconteça, variando-se alguns aspectos entre uma repetição e outra.
Supondo que você tenha que ler 400 arquivos de dados que você obteve de um cliente. Você vai escrever 400 vezes a funcão de leitura? Nesse caso, basta fazer um loop para percorrer todos os arquivos da pasta e ler um por um com a função de leitura.
4.2.2.1 For
O for()
é usado para realizar uma série de ordens para uma determinada sequência ou índices (vetor). Sua sintaxe é bem simples:
for(i in c(1, 2, 3, 4, 5)) {
print(i^2)
}
## [1] 1
## [1] 4
## [1] 9
## [1] 16
## [1] 25
Para cada valor (chamamos esse valor de i
) dentro do vetor c(1, 2, 3, 4, 5)
, execute o comando print(i^2)
. Qualquer outro comando dentro das chaves { ... }
seria executado para cada valor do vetor.
Para entendermos melhor, vamos repensar o exemplo das séries usando o for()
.
<- list.files('dados/dados_loop') #lista todos os arquivos de uma pasta
lista.de.arquivos is.vector(lista.de.arquivos)
## [1] TRUE
for(i in lista.de.arquivos) {
print(paste('Leia o arquivo:', i))
#exemplo: read_delim(i, delim = "|")
}
## [1] "Leia o arquivo: arquivo1.txt"
## [1] "Leia o arquivo: arquivo10.txt"
## [1] "Leia o arquivo: arquivo11.txt"
## [1] "Leia o arquivo: arquivo12.txt"
## [1] "Leia o arquivo: arquivo13.txt"
## [1] "Leia o arquivo: arquivo2.txt"
## [1] "Leia o arquivo: arquivo3.txt"
## [1] "Leia o arquivo: arquivo4.txt"
## [1] "Leia o arquivo: arquivo5.txt"
## [1] "Leia o arquivo: arquivo6.txt"
## [1] "Leia o arquivo: arquivo7.txt"
## [1] "Leia o arquivo: arquivo8.txt"
## [1] "Leia o arquivo: arquivo9.txt"
Também é possível utilizar loop com if. No exemplo a seguir, queremos ver todos os números de 1 a 1000 que são divisíveis por 29 e por 3 ao mesmo tempo. Para isso, utilizaremos o operador %%
, que mostra o resto da divisão. Se o resto for zero, é divisível.
for(i in 1:1000){
if((i %% 29 == 0) & (i %% 3 == 0)){
print(i)
} }
## [1] 87
## [1] 174
## [1] 261
## [1] 348
## [1] 435
## [1] 522
## [1] 609
## [1] 696
## [1] 783
## [1] 870
## [1] 957
4.2.2.2 While
O while()
também é uma estrutura de controle de fluxo do tipo loop, mas, diferentemente do for()
, o while executa as tarefas repetidamente até que uma condição seja satisfeita, não percorrendo um vetor.
<- 1
i while(i <= 5){
print(i)
<- i + 1
i }
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5
O uso do while é um pouco menos intuitivo, mas não menos importante. O while é mais apropriado para eventos de automação ou simulação, onde tarefas serão executadas quando um “gatilho” for acionado. Um simples exemplo para ajudar na intuição de seu uso é:
<- list.files('dados/automatico/')
automatico length(automatico) == 0
Temos uma pasta vazia. O loop abaixo vai monitorar essa pasta. Enquanto essa pasta estiver vazia, ele estará em execução. Quando você colocar um arquivo dentro dessa pasta, vai mudar a condição length(automatico) == 0
de TRUE
para FALSE
e vai mudar a condição length(automatico) > 0
de FALSE
para TRUE
, disparando todas as tarefas programadas. Usamos a função Sys.sleep(5)
para que o código espere por mais cinco segundos antes de começar o loop novamente.
while (length(automatico) == 0) {
<- list.files('dados/automatico/')
automatico if(length(automatico) > 0) {
print('O arquivo chegou!')
print('Inicia a leitura dos dados')
print('Faz a manipulação')
print('Envia email informando conclusão dos cálculos')
else {
} print('aguardando arquivo...')
Sys.sleep(5)
} }
Faça o teste: execute o código acima, aguarde alguns segundos e perceba que nada aconteceu. Crie um arquivo qualquer dentro da pasta dados/automatico/
. Imediatamente o loop será encerrado e as tarefas executadas. Observe o output em tela.
4.2.3 Funções
Funções “encapsulam” uma sequência de comandos e instruções. É uma estrutura nomeada, que recebe parâmetros para iniciar sua execução e retorna um resultado ao final. Até o momento, você já usou diversas funções. Vejamos então como criar uma função:
<- function(parametro1, parametro2){
sua_funcao
# sequência de tarefas
return(valores_retornados)
}
# chamada da função
sua_funcao
Agora tente entender a seguinte função:
<- function(palavra) {
montanha_russa <- NULL
retorno for(i in 1:nchar(palavra)) {
if(i %% 2 == 0) {
<- paste0(retorno, tolower(substr(palavra, i, i)))
retorno else {
} <- paste0(retorno, toupper(substr(palavra, i, i)))
retorno
}
}return(retorno)
}
montanha_russa('teste de função: letras maiúsculas e minúsculas')
## [1] "TeStE De fUnÇãO: lEtRaS MaIúScUlAs e mInÚsCuLaS"
montanha_russa('CONSEGUIU ENTENDER?')
## [1] "CoNsEgUiU EnTeNdEr?"
montanha_russa('É Fácil Usar Funções!')
## [1] "É FáCiL UsAr fUnÇõEs!"
4.3 Manipulações com R base
Dominar a manipulação de data frames e vetores é muito importante. Em geral, toda manipulação pode ser feita com o R base, mas acreditamos que utilizando técnicas do tidyverse a atividade fica bem mais fácil. Portanto, utilizaremos o dplyr
, um dos principais pacotes do tidyverse. Porém, alguns conceitos do R base são clássicos e precisam ser dominados.
4.3.1 Trabalhando com colunas de um data.frame
Para selecionar ou trabalhar separadamente com apenas um campo (coluna) do seu data.frame, deve-se utilizar o $
. Repare nas funções abaixo e no uso do sifrão.
head(airquality$Ozone)
## [1] 41 36 12 18 NA 28
tail(airquality$Ozone)
## [1] 14 30 NA 14 18 20
class(airquality$Ozone) # Informa o tipo da coluna
## [1] "integer"
is.vector(airquality$Ozone) # Apenas para verificar que cada coluna de um data.frame é um vector
## [1] TRUE
unique(df$sgPartido) # Função que retorna apenas os valores únicos, sem repetição, de um vetor
## [1] NA "PSDB" "DEM" "PP" "PDT" "PODE" "PSB"
## [8] "PT" "REPUBLICANOS" "CIDADANIA" "PSOL" "MDB" "PSD" "PCdoB"
## [15] "PL" "PTB" "PROS" "PSC" "PSL" "SOLIDARIEDADE" "NOVO"
## [22] "AVANTE" "PATRIOTA" "PV" "REDE"
Lembre-se sempre: cada coluna de um data.frame é um vetor, portanto todos os registros (linhas) daquela coluna devem ser do mesmo tipo. Um data.frame pode ser considerado um conjunto de vetores nomeados, todos do mesmo tamanho, ou seja, todos com a mesma quantidade de registros.
Usando termos mais técnicos, um data frame é um conjunto de dados HETEROGÊNEOS, pois cada coluna pode ser de um tipo, e BIDIMENSIONAL, por possuir apenas linhas e colunas. Já o vetor é um conjunto de dados HOMOGÊNEO, pois só pode ter valores de um mesmo tipo, e UNIDIMENSIONAL.
Com esses conceitos em mente fica mais fácil entender o que mostraremos a seguir:
<- c(seq(from=0, to=100, by=15)) #vetor de 0 a 100, de 15 em 15.
vetor #lista todos os elementos vetor
## [1] 0 15 30 45 60 75 90
1] #mostra apenas o elemento na posição 1 vetor[
## [1] 0
2] #apenas o elemento na posição 2 vetor[
## [1] 15
7] #apenas o elemento na posição 7 vetor[
## [1] 90
8] #não existe nada na posição 8... vetor[
## [1] NA
A notação []
é usada para selecionar o elemento em uma ou mais posições do vetor.
c(2,7)] #selecionando mais de um elemento no vetor vetor[
## [1] 15 90
Uma notação parecida é usada para selecionar elementos no data.frame
. Porém, como já comentamos, data frames são BIDIMENSIONAIS. Então usaremos a notação [,]
com uma vírgula separando qual a linha (posição antes da vírgula) e a coluna (posição após a vírgula) que queremos selecionar.
10, ] #linha 10, todas as colunas df[
## # A tibble: 1 × 31
## txNomeParlamentar cpf ideCadastro nuCarteiraParlamentar nuLegislatura sgUF sgPartido codLegislatura numSubCota txtDescricao
## <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr> <dbl> <dbl> <chr>
## 1 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 12 ASSINATURA …
## # … with 21 more variables: numEspecificacaoSubCota <dbl>, txtDescricaoEspecificacao <chr>, txtFornecedor <chr>,
## # txtCNPJCPF <chr>, txtNumero <chr>, indTipoDocumento <dbl>, datEmissao <dttm>, vlrDocumento <chr>, vlrGlosa <chr>,
## # vlrLiquido <chr>, numMes <dbl>, numAno <dbl>, numParcela <dbl>, txtPassageiro <chr>, txtTrecho <chr>, numLote <dbl>,
## # numRessarcimento <dbl>, vlrRestituicao <lgl>, nuDeputadoId <dbl>, ideDocumento <dbl>, urlDocumento <chr>
72, 3] #linha 72, coluna 3 df[
## # A tibble: 1 × 1
## ideCadastro
## <dbl>
## 1 NA
c(100, 200), c(2,3,4)] # selecionando mais de uma linha e coluna em um data.frame df[
## # A tibble: 2 × 3
## cpf ideCadastro nuCarteiraParlamentar
## <dbl> <dbl> <dbl>
## 1 NA NA NA
## 2 NA NA NA
c(10:20), ] df[
## # A tibble: 11 × 31
## txNomeParlamentar cpf ideCadastro nuCarteiraParlamentar nuLegislatura sgUF sgPartido codLegislatura numSubCota txtDescricao
## <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr> <dbl> <dbl> <chr>
## 1 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 12 ASSINATURA …
## 2 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 12 ASSINATURA …
## 3 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 13 FORNECIMENT…
## 4 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 13 FORNECIMENT…
## 5 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 13 FORNECIMENT…
## 6 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 13 FORNECIMENT…
## 7 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 13 FORNECIMENT…
## 8 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 13 FORNECIMENT…
## 9 LIDERANÇA DO NOVO NA NA NA 2019 <NA> <NA> 56 1 MANUTENÇÃO …
## 10 LIDERANÇA DO NOVO NA NA NA 2019 <NA> <NA> 56 1 MANUTENÇÃO …
## 11 LIDERANÇA DO NOVO NA NA NA 2019 <NA> <NA> 56 1 MANUTENÇÃO …
## # … with 21 more variables: numEspecificacaoSubCota <dbl>, txtDescricaoEspecificacao <chr>, txtFornecedor <chr>,
## # txtCNPJCPF <chr>, txtNumero <chr>, indTipoDocumento <dbl>, datEmissao <dttm>, vlrDocumento <chr>, vlrGlosa <chr>,
## # vlrLiquido <chr>, numMes <dbl>, numAno <dbl>, numParcela <dbl>, txtPassageiro <chr>, txtTrecho <chr>, numLote <dbl>,
## # numRessarcimento <dbl>, vlrRestituicao <lgl>, nuDeputadoId <dbl>, ideDocumento <dbl>, urlDocumento <chr>
Repare na notação c(10:20), você pode usar :
para criar sequências. Experimente 1:1000
Também é possível selecionar o item desejado utilizando o próprio nome da coluna:
1:10, c('sgPartido', 'cpf')] df[
## # A tibble: 10 × 2
## sgPartido cpf
## <chr> <dbl>
## 1 <NA> NA
## 2 <NA> NA
## 3 <NA> NA
## 4 <NA> NA
## 5 <NA> NA
## 6 <NA> NA
## 7 <NA> NA
## 8 <NA> NA
## 9 <NA> NA
## 10 <NA> NA
Existem diversas outras formas de seleção e manipulação de dados, como, por exemplo, seleção condicional:
head(df[df$sgPartido == 'PT', ])
## # A tibble: 6 × 31
## txNomeParlamentar cpf ideCadastro nuCarteiraParlamentar nuLegislatura sgUF sgPartido codLegislatura numSubCota txtDescricao
## <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr> <dbl> <dbl> <chr>
## 1 <NA> NA NA NA NA <NA> <NA> NA NA <NA>
## 2 <NA> NA NA NA NA <NA> <NA> NA NA <NA>
## 3 <NA> NA NA NA NA <NA> <NA> NA NA <NA>
## 4 <NA> NA NA NA NA <NA> <NA> NA NA <NA>
## 5 <NA> NA NA NA NA <NA> <NA> NA NA <NA>
## 6 <NA> NA NA NA NA <NA> <NA> NA NA <NA>
## # … with 21 more variables: numEspecificacaoSubCota <dbl>, txtDescricaoEspecificacao <chr>, txtFornecedor <chr>,
## # txtCNPJCPF <chr>, txtNumero <chr>, indTipoDocumento <dbl>, datEmissao <dttm>, vlrDocumento <chr>, vlrGlosa <chr>,
## # vlrLiquido <chr>, numMes <dbl>, numAno <dbl>, numParcela <dbl>, txtPassageiro <chr>, txtTrecho <chr>, numLote <dbl>,
## # numRessarcimento <dbl>, vlrRestituicao <lgl>, nuDeputadoId <dbl>, ideDocumento <dbl>, urlDocumento <chr>
Em todas as comparações do R usamos operadores lógicos. São operações matemáticas em que o resultado é TRUE
ou FALSE
(tipo logic
). Para melhor entendimento, selecionamos alguns operadores lógicos e seus significados:
==
igual a: compara dois objetos e se forem iguais retorna TRUE, caso contrário, FALSE;!=
diferente: compara dois objetos e se forem diferentes retorna TRUE, caso contrário, FALSE;|
ou (or): compara dois objetos, se um dos dois for TRUE, retorna TRUE, se os dois forem FALSE, retorna FALSE;&
e (and): compara dois objetos, se os dois forem TRUE, retorna TRUE, se um dos dois ou os dois forem FALSE, retorna FALSE;>
,>=
,<
,<=
maior, maior ou igual, menor, menor ou igual: compara grandeza de dois números e retorna TRUE ou FALSE conforme a condição;
É possível fazer muita coisa com o R base, porém, vamos avançar com as manipulações, utilizando o pacote dplyr
, por ser mais simples e, por isso, de mais rápido aprendizado.
4.4 Pacote dplyr
O forte do pacote dplyr
é a sintaxe simples e concisa, o que facilita o aprendizado e torna o pacote um dos preferidos para as tarefas do dia a dia. Também conta como ponto forte sua otimização de performance para manipulação de dados. Ao carregar o pacote tidyverse
, você já carregará automaticamente o pacote dplyr
, mas você também pode carregá-lo individualmente:
install.packages("dplyr")
library(dplyr)
Referências:
Site do pacote dplyr
4.4.1 Verbetes do dplyr e o operador %>%
O dplyr
cobre praticamente todas as tarefas básicas da manipulação de dados: agregar, sumarizar, filtrar, ordenar, criar variáveis, joins, dentre outras.
As funções do dplyr
reproduzem as principais tarefas da manipulação, de forma bastante intuitiva. Veja só:
select()
filter()
arrange()
mutate()
group_by()
summarise()
Esses são os principais verbetes, mas existem outros disponíveis, como por exemplo slice()
, rename()
e transmute()
.
Além de nomes de funções intuitivos, o dplyr
também faz uso de um recurso disponível em boa parte dos pacotes do Hadley, o operador %>%
(originário do pacote magrittr
). Este operador encadeia as chamadas de funções de forma que você não vai precisar ficar chamando uma função dentro da outra ou ficar fazendo atribuições usando diversas linhas para concluir suas manipulações. Aliás, podemos dizer que esse operador %>%
, literalmente, cria um fluxo sequencial bastante claro e legível para todas as atividades de manipulação.
Os 6 principais verbetes listados acima possuem funções derivadas com os sufixos _at
, _if
e _all
, que podem ser muito úteis em arquivos com muitas colunas.
4.4.2 Select
O select()
é a função mais simples de ser entendida. É usada para selecionar variáveis (colunas, campos, features…) do seu data frame.
%>% select(urlDocumento, txtDescricao, vlrRestituicao) df
## # A tibble: 144,367 × 3
## urlDocumento txtDescricao vlrRestituicao
## <chr> <chr> <lgl>
## 1 http://camara.leg.br/cota-parlamentar/nota-fiscal-eletronica?ideDocumentoFiscal=7050172 CONSULTORIAS, PESQUISAS… NA
## 2 http://camara.leg.br/cota-parlamentar/nota-fiscal-eletronica?ideDocumentoFiscal=7058437 CONSULTORIAS, PESQUISAS… NA
## 3 http://camara.leg.br/cota-parlamentar/nota-fiscal-eletronica?ideDocumentoFiscal=7078508 CONSULTORIAS, PESQUISAS… NA
## 4 http://camara.leg.br/cota-parlamentar/nota-fiscal-eletronica?ideDocumentoFiscal=7123566 CONSULTORIAS, PESQUISAS… NA
## 5 http://camara.leg.br/cota-parlamentar/nota-fiscal-eletronica?ideDocumentoFiscal=7067718 DIVULGAÇÃO DA ATIVIDADE… NA
## 6 http://camara.leg.br/cota-parlamentar/nota-fiscal-eletronica?ideDocumentoFiscal=7088718 DIVULGAÇÃO DA ATIVIDADE… NA
## 7 http://camara.leg.br/cota-parlamentar/nota-fiscal-eletronica?ideDocumentoFiscal=7101137 DIVULGAÇÃO DA ATIVIDADE… NA
## 8 http://camara.leg.br/cota-parlamentar/nota-fiscal-eletronica?ideDocumentoFiscal=7140186 DIVULGAÇÃO DA ATIVIDADE… NA
## 9 <NA> ASSINATURA DE PUBLICAÇÕ… NA
## 10 http://camara.leg.br/cota-parlamentar/nota-fiscal-eletronica?ideDocumentoFiscal=7042111 ASSINATURA DE PUBLICAÇÕ… NA
## # … with 144,357 more rows
Você pode, também, fazer uma “seleção negativa,” ou seja, escolher as colunas que não quer:
%>% select(-txNomeParlamentar) df
## # A tibble: 144,367 × 30
## cpf ideCadastro nuCarteiraParlamentar nuLegislatura sgUF sgPartido codLegislatura numSubCota txtDescricao numEspecificaca…
## <dbl> <dbl> <dbl> <dbl> <chr> <chr> <dbl> <dbl> <chr> <dbl>
## 1 NA NA NA 2019 <NA> <NA> 56 4 CONSULTORIAS,… 0
## 2 NA NA NA 2019 <NA> <NA> 56 4 CONSULTORIAS,… 0
## 3 NA NA NA 2019 <NA> <NA> 56 4 CONSULTORIAS,… 0
## 4 NA NA NA 2019 <NA> <NA> 56 4 CONSULTORIAS,… 0
## 5 NA NA NA 2019 <NA> <NA> 56 5 DIVULGAÇÃO DA… 0
## 6 NA NA NA 2019 <NA> <NA> 56 5 DIVULGAÇÃO DA… 0
## 7 NA NA NA 2019 <NA> <NA> 56 5 DIVULGAÇÃO DA… 0
## 8 NA NA NA 2019 <NA> <NA> 56 5 DIVULGAÇÃO DA… 0
## 9 NA NA NA 2019 <NA> <NA> 56 12 ASSINATURA DE… 0
## 10 NA NA NA 2019 <NA> <NA> 56 12 ASSINATURA DE… 0
## # … with 144,357 more rows, and 20 more variables: txtDescricaoEspecificacao <chr>, txtFornecedor <chr>, txtCNPJCPF <chr>,
## # txtNumero <chr>, indTipoDocumento <dbl>, datEmissao <dttm>, vlrDocumento <chr>, vlrGlosa <chr>, vlrLiquido <chr>,
## # numMes <dbl>, numAno <dbl>, numParcela <dbl>, txtPassageiro <chr>, txtTrecho <chr>, numLote <dbl>, numRessarcimento <dbl>,
## # vlrRestituicao <lgl>, nuDeputadoId <dbl>, ideDocumento <dbl>, urlDocumento <chr>
%>% select(-c(txNomeParlamentar, cpf)) df
## # A tibble: 144,367 × 29
## ideCadastro nuCarteiraParlamentar nuLegislatura sgUF sgPartido codLegislatura numSubCota txtDescricao numEspecificacao…
## <dbl> <dbl> <dbl> <chr> <chr> <dbl> <dbl> <chr> <dbl>
## 1 NA NA 2019 <NA> <NA> 56 4 CONSULTORIAS, PESQ… 0
## 2 NA NA 2019 <NA> <NA> 56 4 CONSULTORIAS, PESQ… 0
## 3 NA NA 2019 <NA> <NA> 56 4 CONSULTORIAS, PESQ… 0
## 4 NA NA 2019 <NA> <NA> 56 4 CONSULTORIAS, PESQ… 0
## 5 NA NA 2019 <NA> <NA> 56 5 DIVULGAÇÃO DA ATIV… 0
## 6 NA NA 2019 <NA> <NA> 56 5 DIVULGAÇÃO DA ATIV… 0
## 7 NA NA 2019 <NA> <NA> 56 5 DIVULGAÇÃO DA ATIV… 0
## 8 NA NA 2019 <NA> <NA> 56 5 DIVULGAÇÃO DA ATIV… 0
## 9 NA NA 2019 <NA> <NA> 56 12 ASSINATURA DE PUBL… 0
## 10 NA NA 2019 <NA> <NA> 56 12 ASSINATURA DE PUBL… 0
## # … with 144,357 more rows, and 20 more variables: txtDescricaoEspecificacao <chr>, txtFornecedor <chr>, txtCNPJCPF <chr>,
## # txtNumero <chr>, indTipoDocumento <dbl>, datEmissao <dttm>, vlrDocumento <chr>, vlrGlosa <chr>, vlrLiquido <chr>,
## # numMes <dbl>, numAno <dbl>, numParcela <dbl>, txtPassageiro <chr>, txtTrecho <chr>, numLote <dbl>, numRessarcimento <dbl>,
## # vlrRestituicao <lgl>, nuDeputadoId <dbl>, ideDocumento <dbl>, urlDocumento <chr>
select_at()
: Selecionar um conjunto de variáveis, especificadas pelo nome ou pela posição numérica, podendo aplicar uma função ao nome delas:
# manter apenas as colunas que começam com S e transformar o nome para maiusculo
#df %>% select_at(vars(starts_with("vlr")))
# é equivalente a:
%>% select(starts_with("vlr")) df
## # A tibble: 144,367 × 4
## vlrDocumento vlrGlosa vlrLiquido vlrRestituicao
## <chr> <chr> <chr> <lgl>
## 1 1527.28 0 1527.28 NA
## 2 1527.28 0 1527.28 NA
## 3 1527.28 0 1527.28 NA
## 4 1527.28 0 1527.28 NA
## 5 1527.28 0 1527.28 NA
## 6 1527.28 0 1527.28 NA
## 7 1527.28 0 1527.28 NA
## 8 1527.28 0 1527.28 NA
## 9 613.61 0 613.61 NA
## 10 1527.28 0 1527.28 NA
## # … with 144,357 more rows
select_if()
: Selecionar o conjunto de variáveis do dataframe que atende a um teste lógico:
# selecionar apenas as colunas numericas do dataframe
%>% select_if(is.numeric) %>% head() df
## # A tibble: 6 × 15
## cpf ideCadastro nuCarteiraParlamen… nuLegislatura codLegislatura numSubCota numEspecificacaoSu… indTipoDocumento numMes numAno
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 NA NA NA 2019 56 4 0 4 4 2020
## 2 NA NA NA 2019 56 4 0 4 5 2020
## 3 NA NA NA 2019 56 4 0 4 7 2020
## 4 NA NA NA 2019 56 4 0 4 11 2020
## 5 NA NA NA 2019 56 5 0 4 6 2020
## 6 NA NA NA 2019 56 5 0 4 8 2020
## # … with 5 more variables: numParcela <dbl>, numLote <dbl>, numRessarcimento <dbl>, nuDeputadoId <dbl>, ideDocumento <dbl>
select_all()
: seleciona todas as colunas, opcionalmente aplicando uma função ao nome delas.
%>% select_all(tolower) df
## # A tibble: 144,367 × 31
## txnomeparlamentar cpf idecadastro nucarteiraparlamentar nulegislatura sguf sgpartido codlegislatura numsubcota txtdescricao
## <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr> <dbl> <dbl> <chr>
## 1 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 4 CONSULTORIA…
## 2 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 4 CONSULTORIA…
## 3 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 4 CONSULTORIA…
## 4 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 4 CONSULTORIA…
## 5 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 5 DIVULGAÇÃO …
## 6 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 5 DIVULGAÇÃO …
## 7 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 5 DIVULGAÇÃO …
## 8 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 5 DIVULGAÇÃO …
## 9 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 12 ASSINATURA …
## 10 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 12 ASSINATURA …
## # … with 144,357 more rows, and 21 more variables: numespecificacaosubcota <dbl>, txtdescricaoespecificacao <chr>,
## # txtfornecedor <chr>, txtcnpjcpf <chr>, txtnumero <chr>, indtipodocumento <dbl>, datemissao <dttm>, vlrdocumento <chr>,
## # vlrglosa <chr>, vlrliquido <chr>, nummes <dbl>, numano <dbl>, numparcela <dbl>, txtpassageiro <chr>, txttrecho <chr>,
## # numlote <dbl>, numressarcimento <dbl>, vlrrestituicao <lgl>, nudeputadoid <dbl>, idedocumento <dbl>, urldocumento <chr>
4.4.3 Mutate
Para criar novos campos ou transformar campos já existentes, podemos usar a mutate()
. Ela é útil para, por exemplo, converter classes de colunas:
# criar coluna com o nome do senador em minusculo
<- df %>%
df mutate(vlrDocumento = as.numeric(vlrDocumento),
vlrLiquido = as.numeric(vlrLiquido),
vlrRestituicao = as.numeric(vlrRestituicao))
Caso o argumento da esquerda em mutate()
seja um nome de coluna que já existe no dataframe, esta será sobrescrita:
%>%
df select(txNomeParlamentar, vlrLiquido) %>%
mutate(txNomeParlamentar = tolower(txNomeParlamentar)) %>%
head()
## # A tibble: 6 × 2
## txNomeParlamentar vlrLiquido
## <chr> <dbl>
## 1 liderança do democratas 1527.
## 2 liderança do democratas 1527.
## 3 liderança do democratas 1527.
## 4 liderança do democratas 1527.
## 5 liderança do democratas 1527.
## 6 liderança do democratas 1527.
Veja como é simples realizar a operação acima, de transformar uma coluna para minúsculo, para todas as colunas de texto do dataframe com o auxílio de mutate_if()
, na qual o primeiro argumento é um teste lógico e o segundo é a função a ser aplicada para todas as colunas onde o teste lógico seja TRUE
.
%>%
df # o primeiro argumento de mutate_if
mutate_if(is.character, tolower) %>%
head()
## # A tibble: 6 × 31
## txNomeParlamentar cpf ideCadastro nuCarteiraParlamentar nuLegislatura sgUF sgPartido codLegislatura numSubCota txtDescricao
## <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr> <dbl> <dbl> <chr>
## 1 liderança do democratas NA NA NA 2019 <NA> <NA> 56 4 consultoria…
## 2 liderança do democratas NA NA NA 2019 <NA> <NA> 56 4 consultoria…
## 3 liderança do democratas NA NA NA 2019 <NA> <NA> 56 4 consultoria…
## 4 liderança do democratas NA NA NA 2019 <NA> <NA> 56 4 consultoria…
## 5 liderança do democratas NA NA NA 2019 <NA> <NA> 56 5 divulgação …
## 6 liderança do democratas NA NA NA 2019 <NA> <NA> 56 5 divulgação …
## # … with 21 more variables: numEspecificacaoSubCota <dbl>, txtDescricaoEspecificacao <chr>, txtFornecedor <chr>,
## # txtCNPJCPF <chr>, txtNumero <chr>, indTipoDocumento <dbl>, datEmissao <dttm>, vlrDocumento <dbl>, vlrGlosa <chr>,
## # vlrLiquido <dbl>, numMes <dbl>, numAno <dbl>, numParcela <dbl>, txtPassageiro <chr>, txtTrecho <chr>, numLote <dbl>,
## # numRessarcimento <dbl>, vlrRestituicao <dbl>, nuDeputadoId <dbl>, ideDocumento <dbl>, urlDocumento <chr>
4.4.4 Filter
Além de escolher apenas alguns campos, você pode escolher apenas algumas linhas, utilizando alguma condição como filtragem. Para isso, basta utilizar a função filter
.
%>%
df select(cpf, txNomeParlamentar, txtDescricao, vlrDocumento) %>%
filter(vlrDocumento >= 100000)
## # A tibble: 6 × 4
## cpf txNomeParlamentar txtDescricao vlrDocumento
## <dbl> <chr> <chr> <dbl>
## 1 9006826200 Edmilson Rodrigues DIVULGAÇÃO DA ATIVIDADE PARLAMENTAR. 151260
## 2 43196926168 Professora Dorinha Seabra Rezende DIVULGAÇÃO DA ATIVIDADE PARLAMENTAR. 105600
## 3 60433086653 Emidinho Madeira DIVULGAÇÃO DA ATIVIDADE PARLAMENTAR. 104520
## 4 41864883634 Subtenente Gonzaga SERVIÇOS POSTAIS 100587
## 5 49156470991 Christiane de Souza Yared DIVULGAÇÃO DA ATIVIDADE PARLAMENTAR. 100000
## 6 47102500653 Rogério Correia DIVULGAÇÃO DA ATIVIDADE PARLAMENTAR. 144640
%>% filter(numMes == 9) %>% head() df
## # A tibble: 6 × 31
## txNomeParlamentar cpf ideCadastro nuCarteiraParlamentar nuLegislatura sgUF sgPartido codLegislatura numSubCota txtDescricao
## <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr> <dbl> <dbl> <chr>
## 1 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 5 DIVULGAÇÃO …
## 2 LIDERANÇA DO DEMOCRATAS NA NA NA 2019 <NA> <NA> 56 13 FORNECIMENT…
## 3 LIDERANÇA DO NOVO NA NA NA 2019 <NA> <NA> 56 1 MANUTENÇÃO …
## 4 LIDERANÇA DO NOVO NA NA NA 2019 <NA> <NA> 56 1 MANUTENÇÃO …
## 5 LIDERANÇA DO NOVO NA NA NA 2019 <NA> <NA> 56 1 MANUTENÇÃO …
## 6 LIDERANÇA DO NOVO NA NA NA 2019 <NA> <NA> 56 1 MANUTENÇÃO …
## # … with 21 more variables: numEspecificacaoSubCota <dbl>, txtDescricaoEspecificacao <chr>, txtFornecedor <chr>,
## # txtCNPJCPF <chr>, txtNumero <chr>, indTipoDocumento <dbl>, datEmissao <dttm>, vlrDocumento <dbl>, vlrGlosa <chr>,
## # vlrLiquido <dbl>, numMes <dbl>, numAno <dbl>, numParcela <dbl>, txtPassageiro <chr>, txtTrecho <chr>, numLote <dbl>,
## # numRessarcimento <dbl>, vlrRestituicao <dbl>, nuDeputadoId <dbl>, ideDocumento <dbl>, urlDocumento <chr>
4.4.5 Group By e Summarise
O group_by()
e o summarise()
são operações que trabalham na agregação dos dados, ou seja, um dado mais detalhado passa a ser um dado mais agregado e agrupado, em consequência disso, menos detalhado. O agrupamento de dados geralmente é trabalhado em conjunção com sumarizações, que usam funções matemáticas do tipo soma, média, desvio padrão etc.
Enquanto o group_by()
“separa” seus dados nos grupos que você selecionar, o summarise()
faz operações de agregação de linhas limitadas a esse grupo.
Vale observar que operações de agrupamento e sumarização geralmente DIMINUEM a quantidade de linhas dos seus dados, pois está reduzindo o nível de detalhe. Ou seja, de alguma forma, você está “perdendo” detalhe para “ganhar” agregação.
Como exemplo, utilizaremos os dados disponíveis no pacote nycflights13:
install.packages("nycflights13")
library(nycflights13)
data("flights")
str(flights)
## tibble [336,776 × 19] (S3: tbl_df/tbl/data.frame)
## $ year : int [1:336776] 2013 2013 2013 2013 2013 2013 2013 2013 2013 2013 ...
## $ month : int [1:336776] 1 1 1 1 1 1 1 1 1 1 ...
## $ day : int [1:336776] 1 1 1 1 1 1 1 1 1 1 ...
## $ dep_time : int [1:336776] 517 533 542 544 554 554 555 557 557 558 ...
## $ sched_dep_time: int [1:336776] 515 529 540 545 600 558 600 600 600 600 ...
## $ dep_delay : num [1:336776] 2 4 2 -1 -6 -4 -5 -3 -3 -2 ...
## $ arr_time : int [1:336776] 830 850 923 1004 812 740 913 709 838 753 ...
## $ sched_arr_time: int [1:336776] 819 830 850 1022 837 728 854 723 846 745 ...
## $ arr_delay : num [1:336776] 11 20 33 -18 -25 12 19 -14 -8 8 ...
## $ carrier : chr [1:336776] "UA" "UA" "AA" "B6" ...
## $ flight : int [1:336776] 1545 1714 1141 725 461 1696 507 5708 79 301 ...
## $ tailnum : chr [1:336776] "N14228" "N24211" "N619AA" "N804JB" ...
## $ origin : chr [1:336776] "EWR" "LGA" "JFK" "JFK" ...
## $ dest : chr [1:336776] "IAH" "IAH" "MIA" "BQN" ...
## $ air_time : num [1:336776] 227 227 160 183 116 150 158 53 140 138 ...
## $ distance : num [1:336776] 1400 1416 1089 1576 762 ...
## $ hour : num [1:336776] 5 5 5 5 6 5 6 6 6 6 ...
## $ minute : num [1:336776] 15 29 40 45 0 58 0 0 0 0 ...
## $ time_hour : POSIXct[1:336776], format: "2013-01-01 05:00:00" "2013-01-01 05:00:00" "2013-01-01 05:00:00" "2013-01-01 05:00:00" ...
Gostaríamos de obter a média de atraso da chegada para cada mês. Para isso, primeiro agrupamos no nível necessário e depois sumarizamos.
<- flights %>%
atraso_por_mes group_by(month) %>%
summarise(arr_delay_media = mean(arr_delay, na.rm=TRUE),
dep_delay_media = mean(dep_delay, na.rm=TRUE))
atraso_por_mes
## # A tibble: 12 × 3
## month arr_delay_media dep_delay_media
## <int> <dbl> <dbl>
## 1 1 6.13 10.0
## 2 2 5.61 10.8
## 3 3 5.81 13.2
## 4 4 11.2 13.9
## 5 5 3.52 13.0
## 6 6 16.5 20.8
## 7 7 16.7 21.7
## 8 8 6.04 12.6
## 9 9 -4.02 6.72
## 10 10 -0.167 6.24
## 11 11 0.461 5.44
## 12 12 14.9 16.6
A função n()
retorna a quantidade de observacões (linhas) por variável especificada em group_by()
:
# Quantidade de voos por hora do dia
%>%
flights group_by(carrier) %>%
summarise(n_voos = n()) %>%
head()
## # A tibble: 6 × 2
## carrier n_voos
## <chr> <int>
## 1 9E 18460
## 2 AA 32729
## 3 AS 714
## 4 B6 54635
## 5 DL 48110
## 6 EV 54173
A função n_distinct()
retorna a quantidade de casos únicos por grupo:
# quantas companhias aéreas diferentes operam por aeroporto por mês nos EUA?
%>%
flights group_by(origin, month) %>%
summarise(n_empresas = n_distinct(carrier)) %>%
head(6)
## `summarise()` has grouped output by 'origin'. You can override using the `.groups` argument.
## # A tibble: 6 × 3
## # Groups: origin [1]
## origin month n_empresas
## <chr> <int> <int>
## 1 EWR 1 10
## 2 EWR 2 10
## 3 EWR 3 10
## 4 EWR 4 11
## 5 EWR 5 11
## 6 EWR 6 12
4.4.6 Arrange
A função arrange()
serve para organizar os dados em sua ordenação. Costuma ser uma das últimas operações, normalmente usada para organizar os dados e facilitar visualizações ou criação de relatórios. Utilizando o exemplo anterior, gostaríamos de ordenar os meses pelas menores médias de decolagem (para ordens decrescentes basta usar o sinal de menos -
)
<- flights %>%
media group_by(month) %>%
summarise(arr_delay_media = mean(arr_delay, na.rm=TRUE),
dep_delay_media = mean(dep_delay, na.rm=TRUE)) %>%
arrange(dep_delay_media)
media
## # A tibble: 12 × 3
## month arr_delay_media dep_delay_media
## <int> <dbl> <dbl>
## 1 11 0.461 5.44
## 2 10 -0.167 6.24
## 3 9 -4.02 6.72
## 4 1 6.13 10.0
## 5 2 5.61 10.8
## 6 8 6.04 12.6
## 7 5 3.52 13.0
## 8 3 5.81 13.2
## 9 4 11.2 13.9
## 10 12 14.9 16.6
## 11 6 16.5 20.8
## 12 7 16.7 21.7
Referências:
Documentação da função arrange()
4.5 Exercícios
4.5.1 Parte 1
Quais foram os deputados com mais despesas na cota parlamentar (considerando a coluna vlrDocumento)?
Quais foram as 5 empresas mais contratadas (considerando a coluna textCNPJCPF)?
Qual foi o gasto médio dos deputados, por UF, com a cota parlamentar (considerando a coluna vlrDocumento)?
Quais categorias de gastos registraram mais despesas nas lideranças (considerando a coluna txtDescricao)?
Quantas linhas da coluna com o PDF da nota fiscal estão com NA (considerando a coluna urlDocumento)?
Qual foi o mês com menos gastos (considerando a coluna numMes)?
4.5.2 Parte 2
Baixe o dataset de anúncios do AirBNB no Rio de Janeiro a partir deste link:
http://data.insideairbnb.com/brazil/rj/rio-de-janeiro/2021-07-17/data/listings.csv.gz
- Leia o arquivo listings com a função read_csv() e salve no objeto
df_anuncios
- Inspecione os dados: funções
summary()
eglimpse()
- A partir do output de
glimpse()
, explique as diferentes classes de objetos no R.
- Observe o problema nas variáveis de preço
- Retorne a url (scrape_url) do anúncio mais caro do airbnb
- Retorne o nome do host (host_name) que tem a maior quantidade de anúncios
- Retorne a quantidade de hosts por ano em que entrou no airbnb
- Selecione as colunas name e space e filtre as linhas que contem a palavra praia em space. Dica: Vc pode usar a função
str_detect()
dentro defilter()
ou demutate()
- Imóveis que mencionam a palavra praia são em média mais caros?
- Use
mutate()
para modificar o dataframe criando uma coluna booleana chamadaesgotado
informando se o imovel esta indisponivel para os proximos 30 dias (coluna availability_30) - Quais os 5 bairros que possuem mais de 100 anúncios com a maior taxa de anúncios esgotados nos próximos 30 dias? Dica: crie duas colunas com summarise, uma usando n() e outra com mean(esgotado) e depois use filter(), arrange() e head()
- Retorne a quantidade de anúncios e reviews (number_of_reviews) por bairro, calcule uma taxa de quantidade de reviews por quantidade de anuncios. Os bairros que possuem mais anuncios são, proporcionalmente, os que tem mais reviews?
- Quais são os diferentes tipos de anúncio (quarto, apt, etc.) que existem? (Coluna room_type)
- A quantidade de quartos tem relação com o preço dos apartamentos inteiros?
- DESAFIO Suponha que você planeja uma viagem para o RJ com mais 1 pessoa de 5 diárias nos… proximos 30 dias. Você e seu grupo têm alguns critérios de escolha:
- Vocês querem ficar em Ipanema, Copacabana ou Leblon.
- Vocês preferem que o host esteja no mesmo bairro.
- Não desejam pagar um depósito de segurança;
- Querem um apartamento inteiro só para vocês que seja “instant bookable”
- A diária já inclua duas pessoas
Filtre os anúncios que atendem aos critérios acima e crie uma coluna chamada preco_total_viagem, com a formula sendo: taxa de limpeza + preço da diaria x quantidade de diarias. Compare os resultados com os do site. Dica: Comece com o código abaixo, selecionando as colunas importantes
%>%
df_anuncios select(listing_url, neighbourhood, host_neighbourhood,
availability_30, minimum_nights,
security_deposit, instant_bookable,
guests_included, price, room_type, number_of_reviews, cleaning_fee, review_scores_rating)