7 Manipulação de dados com o dplyr
7.1 O que é um Data Frame?
Provavelmente você já utilizou o Excel para construir ou analisar uma tabela com os seus dados de interesse. Geralmente, as tabelas já têm a mesma estrutura de um Data Frame, conceito que será muito útil em seus trabalhos e será apresentado aqui.
Em um Data Frame cada registro será inserido em uma linha, já as colunas representarão as suas variáveis.
Por exemplo, em uma pesquisa de opinião, as informações de uma linha serão os dados de uma pessoa específica que respondeu a pesquisa. Enquanto cada coluna da tabela corresponderá as respostas para uma pergunta específica.
Diferentemente de uma matriz tradicional, as colunas podem misturar vários tipos de variáveis.
No caso da pesquisa de opinião, pode-se ter uma coluna para Idade (variável numérica), outra para o Gênero (variável categórica) e outra pergunta aberta (variável de texto).
Regras básicas de um Data Frame:
- Cada coluna deve ter um nome
- Todas as colunas devem ser do mesmo tamanho. Não é permitido que uma coluna tenha 40 registros e outra 39.
- As colunas podem ser numéricas (numeric), categóricas (factor) ou texto (character)
- Sempre terão duas dimensões (linhas e colunas)
7.2 Manipulação de um Data Frame
Seja qual for a sua área dentro da Ciência de Dados, os conceitos a seguir serão muito úteis e irão facilitar muito a vida em suas análises.
Seja para econometria, bioestatística, demografia, machine learning ou qualquer outra.
O melhor pacote do R para manipular dados para manipular Data Frames se chama dplyr.
Porque usar o dplyr:
Facilidade de criação e leitura do código - Código limpo.
Manipulação básica ou avançada em poucas linhas
É muito mais veloz comparando com as funções correspondentes de outros pacotes.
É simples. Baseado em apenas 6 funções principais.
7.3 As funções do Dplyr
O Dplyr é bastante conhecido e usado pelos 6 verbos que representam suas principais funções:
- Summarise -> Calcula valores para uma coluna. Ex: soma total, mínimo, máximo, média, desvio padrão, etc.
- Mutate -> Cria uma nova variável que seja uma função entre variáveis que já existem
- Select -> Seleciona colunas que já existem pelo nome delas.
- Filter -> Seleciona registros (linhas) de acordo com uma condição estabelecida.
- Arrange -> Ordena as linhas do data frame.
- Rename -> Renomear o nome das variáveis.
Essas são as principais funções que você irá utilizar em uma manipulação de dados. Apesar de serem simples, são muito poderosas.
Além das funções acima, que são marca registrada da biblioteca dplyr
, irei apresentar aqui a função left_join
.
Essa função também é muito importante na manipulação de conjunto de dados e corresponde à função PROCV, muito utilizada no Excel.
7.4 As propriedades das funções do pacote Dplyr
Esses conceitos apresentados agora irão facilitar muito o seu entendimento para qualquer uma das funções usadas no pacote.
Características comuns às funções citadas do pacote:
- O primeiro argumento da função é sempre o seu conjunto de dados que será manipulado.
- Os argumentos seguintes vão definir o que será feito com o seu conjunto de dados
- O resultado também será um data frame.
- Ao inserir os nomes de colunas (variáveis) não é necessário (e nem permitido) usar "" ou o operador $.
Na prática será bem fácil identificar esse padrão. Então, vamos ver como funciona cada uma das funções.
7.5 A função Summarise e a função group_by
A função summarise
é útil para calcular estatísticas das colunas de um data frame.
Muitas vezes é utilizada com uma função auxiliar também muito importante: a função group_by
.
Apesar da função group_by
ser muito utilizada em conjunto com a função summarise
, ela também pode ser combinada com as outras funções da biblioteca dplyr
.
A combinação entre as funções summarise
e group_by
nos permitem reproduzir as tradicionais funções SOMASES e MEDIASES do Excel, com muita facilidade.
Olha só esse exemplo:
Vamos usar o mtcarts
- dataset nativo no R.
Para mais informações sobre as variáveis do dataset, execute o comando ?mtcarts
.
Suponha que você tenha um conjunto de dados com vários carros (cada carro será uma linha) e várias características dos carros (colunas).
Para calcular a média de uma dessas características, por exemplo a quantidade de cavalos dos carros, você usaria a função summarise
.
Mas imagine agora que você não precisa simplesmente calcular a quantidade de cavalos de todos os carros, você precisar calcular essa média de acordo com a quantidade de cilindros dos carros.
Ou seja, os carros serão separados em grupos de acordo com a sua quantidade de cilindros e você irá calcular a média da quantidade de cavalos para cada grupo.
Nesse caso, a função group_by
irá separar seus dados de acordo com uma variável (quantidade de cilindros) e assim você poderá usar a função summarise
para calcular a média da quantidade de cavalos.
library(dplyr)
mtcars_grupo <- group_by(mtcars,cyl) ##a variável cyl é a quantidade de cilindros do carro
summarise(mtcars_grupo,mean(hp)) ## a variável hp é a quantidade de cavalos do carro (horse power)
## # A tibble: 3 x 2
## cyl `mean(hp)`
## <dbl> <dbl>
## 1 4 82.6
## 2 6 122.
## 3 8 209.
Portanto, o código acima calculou a média da variável hp (quantidade de cavalos do carro) de acordo com a quantidade de cilindros do carro.
O código acima corresponde ao que seria feito pela função MEDIASES, do Excel. As duas funções calculam a média de grupos, segundo alguma condição.
Caso você deseje continuar trabalhando com o mesmo dataset (usando o mesmo objeto), é importante que você desfaça o agrupamento. Isso irá evitar futuros erros na execução do seu código.
O equivalente a função SOMASES, segue exatamente o mesmo raciocínio: calcular a soma de grupos para uma determinada variável. Veja o próximo exemplo.
Agora, suponha que você deseja somar os pesos dos carros disponíveis para cada quantidade de cilindros.
Ou seja, vamos somar os pesos de todos os carros com 4, 6 ou 8 cilindros, separados por grupo.
library(dplyr)
mtcars_grupo <- group_by(mtcars,cyl) ##a variável cyl é a quantidade de cilindros do carro
summarise(mtcars_grupo,sum(wt)) ## a variável wt é o peso do carro em libras (Weight)
## # A tibble: 3 x 2
## cyl `sum(wt)`
## <dbl> <dbl>
## 1 4 25.1
## 2 6 21.8
## 3 8 56.0
7.6 Mutate
A função mutate
serve para criar uma nova coluna que seja uma função entre as variáveis que já existem.
Então, usando o mesmo data frame mtcars
, temos a variável wt que representa o peso do carro (em libras) e a variável qsec que representa o tempo (em segundos) que o carro precisa para percorrer a distância de 0,25 milhas.
Portanto, como exemplo, vamos criar uma nova coluna para relativizar o tempo que o carro gasta para percorrer 0,25 milhas (qsec) pelo seu peso (wt). A fórmula para isso seria: qsec/wt.
O nome da nova coluna será tempo_peso.
Portanto:
7.7 Select
A função select
serve para selecionar colunas em um data frame.
Então, ainda usando o dataframe mtcars
, suponha que somente as variáveis mpg e gear serão úteis em nossa análise.
Para filtrar essas variáveis, precisamos executar o seguinte comando:
## mpg gear
## Mazda RX4 21.0 4
## Mazda RX4 Wag 21.0 4
## Datsun 710 22.8 4
## Hornet 4 Drive 21.4 3
## Hornet Sportabout 18.7 3
## Valiant 18.1 3
## Duster 360 14.3 3
## Merc 240D 24.4 4
## Merc 230 22.8 4
## Merc 280 19.2 4
## Merc 280C 17.8 4
## Merc 450SE 16.4 3
## Merc 450SL 17.3 3
## Merc 450SLC 15.2 3
## Cadillac Fleetwood 10.4 3
## Lincoln Continental 10.4 3
## Chrysler Imperial 14.7 3
## Fiat 128 32.4 4
## Honda Civic 30.4 4
## Toyota Corolla 33.9 4
## Toyota Corona 21.5 3
## Dodge Challenger 15.5 3
## AMC Javelin 15.2 3
## Camaro Z28 13.3 3
## Pontiac Firebird 19.2 3
## Fiat X1-9 27.3 4
## Porsche 914-2 26.0 5
## Lotus Europa 30.4 5
## Ford Pantera L 15.8 5
## Ferrari Dino 19.7 5
## Maserati Bora 15.0 5
## Volvo 142E 21.4 4
Então, o primeiro argumento é o dataset (mtcars
) e os argumentos restantes na função select
são as colunas que você deseja manter.
7.8 Filter
Enquanto a função select
seleciona as colunas do dataframe, a função filter é utilizada para selecionar as linhas do dataframe.
Então, quando precisamos selecionar registros de um data frame usando determinada condição, a função recomendada é a filter
.
Utilizando o mesmo data frame, suponha que precisamos filtrar todos os carros com 6 cilindros.
Neste caso, a variável em questão é a cyl, então a nossa condição é que o registro atenda a condição cyl==6.
Repare que o sinal de igual é duplo, pois é uma condição lógica.
Quando usamos cyl=6 estamos atribuindo o valor 6 para o objeto cyl. Mas não é o que desejamos aqui.
Desejamos filtrar os dados por uma condição lógica (verdadeira ou falsa). Para fazer testes lógicos no R, usamos == para retornar TRUE caso os valores sejam iguais e FALSE caso os valores sejam diferentes.
Quando for necessário inverter a lógica e buscar pelos valores diferentes (ao invés de buscar os iguais) o teste lógico será feito por "!="
(testa se os valores são diferentes).
Então, em nosso exemplo, o código seria o seguinte:
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
## Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
## Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
## Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
## Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
## Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
Também é possível combinar outros operadores lógicos quando vamos filtrar os dados, como E/OU.
Então, suponha que não baste que o carro tenha 6 cilindros, além disso você deseja que ele tenha menos que 3 toneladas. Neste caso, o peso do carro é representado pela variável wt.
Para filtrar os carros que tenham 6 cilindros (cyl==6) e tenham menos que 3 toneladas (wt<3), vamos executar o seguinte código:
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## Ferrari Dino 19.7 6 145 175 3.62 2.770 15.50 0 1 5 6
O operador lógico E é representado pelo símbolo &.
Já o operador lógico OU é representado pelo símbolo |.
Caso o objetivo fosse filtrar carros com 6 cilindros OU peso menor que 3 toneladas, o código seria o seguinte:
## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
## Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
## Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
## Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
## Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
## Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
## Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
## Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
## Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
## Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
## Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
## Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
## Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
Para a condição “cyl==6 | wt<3” ser verdadeira, basta que pelo menos uma das condições sejam atingidas. Ou seja, o carro tenha 6 cilindros ou menos de 3 toneladas. Caso as duas condições sejam atendidas simultaneamente o carro também estará na tabela filtrada.
7.9 Arrange
A função arrange
é responsável por ordenar as linhas do data frame seguindo uma nova ordem estabelecida.
Então, suponha que em nosso exemplo, queremos ordenar o data frame mtcars
do carro com menor número de marchas para o maior número de marchas (variável gear).
Porém, há vários carros que irão empatar para esse critério, já que a tabela tem 15 carros com 3 marchas, 12 carros com 4 marchas e 5 carros com 5 marchas.
##
## 3 4 5
## 15 12 5
Portanto, vou definir que os dados também sejam ordenados pelo peso (variável wt).
## mpg cyl disp hp drat wt qsec vs am gear carb
## Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
## Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
## AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
## Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
## Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
## Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
## Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
## Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
## Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
## Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
## Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
## Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
## Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
## Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
## Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
## Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
## Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
## Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
## Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
## Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
## Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
## Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
## Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
## Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
## Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
## Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
## Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
## Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
## Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
## Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
## Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
## Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
É possível usar a função arrange
para ordenar os dados usando muitas variáveis para ordenar os dados. Porém, a ordem que as colunas forem inseridas na função arrange
representam uma hierarquia de prioridade para ordenar os dados.
Isso significa que os dados sempre serão ordenados pela primeira variável e, em caso de empates, se considera a variável seguinte.
Portanto, a função só irá ordenar pela segunda coluna caso haja empates na primeira, por exemplo.
7.10 Rename
Alterar os nomes de uma variável de um data frame é algo conceitualmente simples. Mas, na prática pode ser bem trabalhoso de fazer sem a função rename
.
Quais são os nomes das colunas da tabela mtcats
?
## [1] "mpg" "cyl" "disp" "hp" "drat" "wt" "qsec" "vs" "am" "gear"
## [11] "carb"
Agora suponha que você deseje alterar o nome da coluna cyl para cilindros e hp para cavalos.
## mpg cilindros disp cavalos drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
## Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
Esse é o padrão. Após informar o data frame onde se aplicará as alterações, coloca-se o novo nome da coluna antes do sinal de igual e logo após o nome antigo da coluna.
7.11 Como juntar informações de data frames diferentes
Se você costumava usar o Excel, a função que vou falar agora é bem parecida com o PROCV.
Existem algumas formas de fazer essa junção de tabelas no R, aqui vou te mostrar a solução usando a biblioteca dplyr
.
Por exemplo, suponha que você esteja trabalhando com o data frame iris. Esse conjunto de dados contém informações sobre os tamanhos de partes de uma flor e também de qual é a espécie da flor.
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 5.1 3.5 1.4 0.2 setosa
## 2 4.9 3.0 1.4 0.2 setosa
## 3 4.7 3.2 1.3 0.2 setosa
## 4 4.6 3.1 1.5 0.2 setosa
## 5 5.0 3.6 1.4 0.2 setosa
## 6 5.4 3.9 1.7 0.4 setosa
Agora, imagine que você tem uma outra tabela que te informa o preço cobrado para cada espécie das flores:
## Species Preco
## 1 setosa 5
## 2 versicolor 10
## 3 virginica 15
Como fazer para juntar todas as informações em uma única tabela?
Note que os dois data frames possuem uma variável em comum: Species.
Essa variável é extremamente importante para juntar as duas tabelas, pois cada registro na tabela iris buscará o preço na tabela preco_iris de acordo com o valor da variável Species.
Por exemplo, essa é a primeira linha da tabela iris.
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 5.1 3.5 1.4 0.2 setosa
Ou seja, o primeiro registro da tabela é da espécie setosa.
Então, pela tabela preco_iris, sabemos que deve ser atribuído o Preço igual a 5 para esse registro, pois:
## Species Preco
## 1 setosa 5
## 2 versicolor 10
## 3 virginica 15
Esse cálculo é feito para todos os registros de forma bem simples. A função que irá executar essa junção entre as duas tabelas é a: left_join()
.
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species Preco
## 1 5.1 3.5 1.4 0.2 setosa 5
## 2 4.9 3.0 1.4 0.2 setosa 5
## 3 4.7 3.2 1.3 0.2 setosa 5
## 4 4.6 3.1 1.5 0.2 setosa 5
## 5 5.0 3.6 1.4 0.2 setosa 5
## 6 5.4 3.9 1.7 0.4 setosa 5
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species Preco
## 145 6.7 3.3 5.7 2.5 virginica 15
## 146 6.7 3.0 5.2 2.3 virginica 15
## 147 6.3 2.5 5.0 1.9 virginica 15
## 148 6.5 3.0 5.2 2.0 virginica 15
## 149 6.2 3.4 5.4 2.3 virginica 15
## 150 5.9 3.0 5.1 1.8 virginica 15
Note que primeiramente informamos a tabela iris. Quando você utilizar a função left_join
, o primeiro parâmetro da função deve ser a tabela que você deseja usar como base.
A função irá procurar na segunda tabela os valores correspondentes para a sua variável comum e adicionar na primeira tabela.
É importante que você também informe qual a variável que irá ligar as informações das duas tabelas. Isso é informado pelo parâmetro by, em nosso caso by="Species"
.
Caso você não informe, a função irá procurar automaticamente por alguma variável em comum nos dois data frames.
Também é possível e, muitas vezes será necessário, utilizar mais de uma variável para vincular as duas tabelas. Nesse caso, a função ficaria da seguinte forma: left_join(tabela1,tabela2,by = c("variavel_comum_1","variavel_comum_2"))
7.12 O operador %>% (em inglês se pronuncia pipe)
Em português pode ser “paipe”! :)
O operador %>%
facilita muito a nossa vida, tornando o código mais limpo e fácil de ser compreendido.
O operador funciona da seguinte forma:
Isso significa que o objeto do lado esquerdo do operador (dataset) será inserido na função ao lado direito do operador no primeiro argumento da função.
O operador %>%
pode ser usado conjuntamente com inúmeras funções, incluindo todas que aprendemos nesse capítulo.
Exemplos práticos:
Algumas linhas atrás, ordenamos o dataset mtcars
em ordem crescente pelas colunas gear e wt, usando o código:
Utilizando o operador %>%, o código ficaria da seguinte maneira:
Então, o dataset mtcars
é inserido no primeiro argumento da função arrange
.
A diferença é pequena para casos simples como esse, porém em casos mais complexos a utilização do operador %>% (pipe) fará uma diferença enorme na organização do seu código.