Capítulo 7 Manipulação e formatação de dados
Após importar uma basde de dados para o R, os principais pacotes para manipulação e formatação de data frames são o dplyr
e o tidyr
. As funções destes pacotes oferecem uma etapa inicial na análise, modelagem e comunicação de dados. Lembramos aqui que uma base de dados é organizada em um formato de tabela em que as linhas são as observações e as colunas são as variáveis que descrevem estas observações. Estas variáveis podem ser quantitativas (contínuas ou discretas) ou qualitativas (ordenadas ou não).
7.1 Transformação de dados: os pacotes dplyr
e tidyr
Aqui veremos funções principais para manipular as observações nas linhas (Manipulate Cases), manipular descritores nas colunas (Manipulate Variables) e combinar tabelas (Combine Tables). Na Cheatsheets do dplyr
você verá também a variedade de funções relacionadas ao cáculo sobre vetores (Vector Functions), funções resumo (Summary Functions, e Summarise Cases) e manipulação de nomes das linhas.
7.1.1 Ordenando as linhas: funções arrange()
e desc()
Estas funções permitem que você ordene a base de dados seguindo os valores de alguma de suas colunas. Vamos utilizar como exemplo a base de dados iris
comumente utilizadas em uma variedade de tutorias sobre ciência de dados. Carrege e verifique a base de dados composta por 150 linhas e 5 colunas.
data("iris")
head(iris, 10)
Vamos ordenar a tabela pela coluna Sepal.Length
.
%>%
iris arrange(Sepal.Length)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 4.3 3.0 1.1 0.1 setosa
## 2 4.4 2.9 1.4 0.2 setosa
## 3 4.4 3.0 1.3 0.2 setosa
## 4 4.4 3.2 1.3 0.2 setosa
## 5 4.5 2.3 1.3 0.3 setosa
## 6 4.6 3.1 1.5 0.2 setosa
## 7 4.6 3.4 1.4 0.3 setosa
## 8 4.6 3.6 1.0 0.2 setosa
## 9 4.6 3.2 1.4 0.2 setosa
## 10 4.7 3.2 1.3 0.2 setosa
As linhas aparecem agora de acordo com os valores (em ordem crescente) de Sepal.Length
, iniciando em 4.3.
Em seguida faça o mesmo em ordem decresente.
%>%
iris arrange(desc(Sepal.Length))
Podemos combinar duas colunas, ordenando a tabela em função da coluna Species
(em ordem alfabética decrescente) e em função de Sepal.Length
(em ordem crescente).
%>%
iris arrange(desc(Species), Sepal.Length)
Nos exemplos acimas, somente visualizamos a tabela em diferentes ordens. Se quisermos criar um novo objeto com a tabela em alguma destas sequências fazemos:
<- iris %>%
iris_ordenado arrange(Sepal.Length)
iris_ordenado
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 4.3 3.0 1.1 0.1 setosa
## 2 4.4 2.9 1.4 0.2 setosa
## 3 4.4 3.0 1.3 0.2 setosa
## 4 4.4 3.2 1.3 0.2 setosa
## 5 4.5 2.3 1.3 0.3 setosa
## 6 4.6 3.1 1.5 0.2 setosa
7.1.2 Filtrando linhas: função filter()
Esta função permite extrair somente as linhas de uma tabela que satisfaçam uma condição lógica. Vamos extrair as linhas referentes à espécie virginica
.
%>%
iris filter(Species == "virginica")
Ou às espécies diferentes de virginica
.
%>%
iris filter(Species != "virginica")
Agora, vamos filtrar as linhas em que o comprimento das pétalas seja menor que 1.3.
%>%
iris filter(Petal.Length < 1.3)
E para o comprimento das pétalas seja menor que 1.3 E o comprimento das sépalas maior ou igual a 5.
%>%
iris filter(Petal.Length < 1.3 & Sepal.Length >= 5)
7.1.3 Selecionando colunas: função select()
A função select permite extrair ou reorganizar um subconjunto colunas de um data frame. Rode os exemplos a seguir:
%>%
iris select(Petal.Length)
%>%
iris select(Petal.Length, Species)
%>%
iris select(Petal.Length:Species)
%>%
iris select(Species:Petal.Length)
%>%
iris select(!c(Petal.Length, Species))
%>%
iris select(starts_with("Sepal"))
Finalmente, combine as funções filter()
e select()
para extrair um subconjunto do data frame:
%>%
iris select(starts_with("Sepal")) %>%
filter(Sepal.Length <= 4.5)
7.1.4 Agrupando tabelas: funções do grupo join
Se você tem alguma experiência em linguagem SQL para banco de dados, irá compreender facilmente o uso do grupo de funções join. Veremos aqui as funções left_join()
, right_join()
, inner_join()
e anti_join()
.
Considere as duas tabelas abaixo que podem ser acessadas em Regiao.csv e Habitat.csv
## # A tibble: 10 x 4
## Riacho Bacia Município Área
## <chr> <chr> <chr> <dbl>
## 1 R1 Boicucanga São Sebastião 30.3
## 2 R4 Boicucanga São Sebastião 30.3
## 3 R8 Boicucanga São Sebastião 30.3
## 4 R2 Cubatão Cubatão 189
## 5 R5 Cubatão Cubatão 189
## 6 R10 Cubatão Cubatão 189
## 7 R13 Cubatão Cubatão 189
## 8 R6 Quilombo Santos 86
## 9 R9 Quilombo Santos 86
## 10 R7 Quilombo Santos 86
## # A tibble: 8 x 4
## Riacho Altitude Largura Profundidade
## <chr> <dbl> <dbl> <dbl>
## 1 R1 74 7.8 20.2
## 2 R4 14 10.9 17.7
## 3 R8 245 8.3 19.5
## 4 R11 241 2.2 20.3
## 5 R2 29 1.6 11.8
## 6 R6 86 15.2 35.3
## 7 R9 77 4.1 18.9
## 8 R7 63 14.2 42.1
<- read_csv("C:/seu_caminho/IntroR/Regiao.csv")
regiao regiao
<- read_csv("C:/seu_caminho/IntroR/Habitat.csv")
habitat habitat
A tabela regiao
, contém informações sobre alguns o bacia hidrográfica, á área da bacia e o múnicípio de alguns riachos da região litorânea do estado de São Paulo. A tabela trecho
, contém informações sobre a largura e profundidades destes riachos. Alguns riachos são coumuns às duas tabelas, enquanto outros ocorrem somente em uma ou em outra tabela. Sabendo que a coluna Riacho
(R1, R2, R3,….R13) se referem ao mesmo ponto de amostragem, podemos utilizá-la para combinar as informações das duas tabelas.
7.1.4.1 Função left_join()
Retorna todas as linhas da tabela à esquerda as as colunas das duas tabelas. Linhas sem correspondência na tabela da direita terão valores de NA
. Se houver várias correspondências, todas as combinações serão retornadas.
%>% left_join(y = habitat) regiao
## # A tibble: 10 x 7
## Riacho Bacia Município Área Altitude Largura Profundidade
## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 R1 Boicucanga São Sebastião 30.3 74 7.8 20.2
## 2 R4 Boicucanga São Sebastião 30.3 14 10.9 17.7
## 3 R8 Boicucanga São Sebastião 30.3 245 8.3 19.5
## 4 R2 Cubatão Cubatão 189 29 1.6 11.8
## 5 R5 Cubatão Cubatão 189 NA NA NA
## 6 R10 Cubatão Cubatão 189 NA NA NA
## 7 R13 Cubatão Cubatão 189 NA NA NA
## 8 R6 Quilombo Santos 86 86 15.2 35.3
## 9 R9 Quilombo Santos 86 77 4.1 18.9
## 10 R7 Quilombo Santos 86 63 14.2 42.1
Veja que todas as linhas da tabela regiao
estão presentes. Foram adicionadas a elas as informações de Altitude
, Largura
e Profundidade
, somente para os riachos que também estavam presentes na tabela habitat
.
7.1.4.2 Função right_join()
Retorna todas as linhas da tabela à direita as as colunas das duas tabelas. Linhas sem correspondência na tabela da esquerda terão valores de NA
. Se houver várias correspondências, todas as combinações serão retornadas.
%>% right_join(y = habitat) regiao
## # A tibble: 8 x 7
## Riacho Bacia Município Área Altitude Largura Profundidade
## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 R1 Boicucanga São Sebastião 30.3 74 7.8 20.2
## 2 R4 Boicucanga São Sebastião 30.3 14 10.9 17.7
## 3 R8 Boicucanga São Sebastião 30.3 245 8.3 19.5
## 4 R2 Cubatão Cubatão 189 29 1.6 11.8
## 5 R6 Quilombo Santos 86 86 15.2 35.3
## 6 R9 Quilombo Santos 86 77 4.1 18.9
## 7 R7 Quilombo Santos 86 63 14.2 42.1
## 8 R11 <NA> <NA> NA 241 2.2 20.3
Note que a coluna de R11
contém NA
nas colunas Bacia
e Município
, pois este riacho não está presente na tabela regiao
.
7.1.4.3 Função inner_join()
Resgata apenas as linhas coincidantes a ambas as tabelas.
%>% inner_join(y = habitat) regiao
7.1.4.4 Função anti_join()
Retorna todas as linhas da tabela à esquerda em que existem correspondências com a de direita. Retorna todas as colunas de ambas. Se houver várias correspondências, todas as combinações serão retornadas. Testes os comandos abaixo.
%>% anti_join(y = habitat) regiao
%>% anti_join(y = regiao) habitat
7.1.4.5 Função full_join()
Retorna todas as linhas e colunas das duas tabelas. Nas células em que não houver valores correspondentes, retorna NA
na posição faltante.
%>% full_join(y = habitat) regiao
%>% semi_join(y = regiao) habitat
7.1.5 Criando e modificando colunas: função mutate()
Voltemos à base de dados Doubs river.
library(ade4)
data(doubs)
<- doubs$env
ambiente head(ambiente)
## dfs alt slo flo pH har pho nit amm oxy bdo
## 1 3 934 6.176 84 79 45 1 20 0 122 27
## 2 22 932 3.434 100 80 40 2 20 10 103 19
## 3 102 914 3.638 180 83 52 5 22 5 105 35
## 4 185 854 3.497 253 80 72 10 21 0 110 13
## 5 215 849 3.178 264 81 84 38 52 20 80 62
## 6 324 846 3.497 286 79 60 20 15 0 102 53
Veja que a coluna pH está dada em ph \(\times\) 10. Vamos retornar à escala unitária.
%>%
ambiente mutate(pH = pH/10)
## dfs alt slo flo pH har pho nit amm oxy bdo
## 1 3 934 6.176 84 7.9 45 1 20 0 122 27
## 2 22 932 3.434 100 8.0 40 2 20 10 103 19
## 3 102 914 3.638 180 8.3 52 5 22 5 105 35
## 4 185 854 3.497 253 8.0 72 10 21 0 110 13
## 5 215 849 3.178 264 8.1 84 38 52 20 80 62
## 6 324 846 3.497 286 7.9 60 20 15 0 102 53
## 7 268 841 4.205 400 8.1 88 7 15 0 111 22
## 8 491 792 3.258 130 8.1 94 20 41 12 70 81
## 9 705 752 2.565 480 8.0 90 30 82 12 72 52
## 10 990 617 4.605 1000 7.7 82 6 75 1 100 43
## 11 1234 483 3.738 1990 8.1 96 30 160 0 115 27
## 12 1324 477 2.833 2000 7.9 86 4 50 0 122 30
## 13 1436 450 3.091 2110 8.1 98 6 52 0 124 24
## 14 1522 434 2.565 2120 8.3 98 27 123 0 123 38
## 15 1645 415 1.792 2300 8.6 86 40 100 0 117 21
## 16 1859 375 3.045 1610 8.0 88 20 200 5 103 27
## 17 1985 348 1.792 2430 8.0 92 20 250 20 102 46
## 18 2110 332 2.197 2500 8.0 90 50 220 20 103 28
## 19 2246 310 1.792 2590 8.1 84 60 220 15 106 33
## 20 2477 286 2.197 2680 8.0 86 30 300 30 103 28
## 21 2812 262 2.398 2720 7.9 85 20 220 10 90 41
## 22 2940 254 2.708 2790 8.1 88 20 162 7 91 48
## 23 3043 246 2.565 2880 8.1 97 260 350 115 63 164
## 24 3147 241 1.386 2976 8.0 99 140 250 60 52 123
## 25 3278 231 1.792 3870 7.9 100 422 620 180 41 167
## 26 3579 214 1.792 3910 7.9 94 143 300 30 62 89
## 27 3732 206 2.565 3960 8.1 90 58 300 26 72 63
## 28 3947 195 1.386 4320 8.3 100 74 400 30 81 45
## 29 4220 183 1.946 6770 7.8 110 45 162 10 90 42
## 30 4530 172 1.099 6900 8.2 109 65 160 10 82 44
Vamos agora criar uma variavel categórica pH_cat
com os níveis Elevado
se maior ou igual a 8 e Neutro
caso contrátio.
%>%
ambiente mutate(pH = pH/10) %>%
mutate(pH_cat = ifelse(pH < 8, yes = "Neutro", no = "Elevado"))
A nova variável está no final da tabela. Vamos colocá-la logo após a coluna pH
%>%
ambiente mutate(pH = pH/10) %>%
mutate(pH_cat = ifelse(pH < 8, yes = "Neutro", no = "Elevado"), .after = pH)
7.1.6 Unindo colunas: função unite()
Todas as funções vistas acima neste capítulo são do pacote dplyr
. A função unite() é do pacote
tidyr``` e permite unir duas colunas. Para isto, vamos retornar à tabela Iris e selecionar algumas linhas para exemplificar a união de colunas.
<- iris %>% filter(Sepal.Length > 5.5 & Sepal.Length < 6.1)
iris2 iris2
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 5.8 4.0 1.2 0.2 setosa
## 2 5.7 4.4 1.5 0.4 setosa
## 3 5.7 3.8 1.7 0.3 setosa
## 4 5.7 2.8 4.5 1.3 versicolor
## 5 5.9 3.0 4.2 1.5 versicolor
## 6 6.0 2.2 4.0 1.0 versicolor
## 7 5.6 2.9 3.6 1.3 versicolor
## 8 5.6 3.0 4.5 1.5 versicolor
## 9 5.8 2.7 4.1 1.0 versicolor
## 10 5.6 2.5 3.9 1.1 versicolor
## 11 5.9 3.2 4.8 1.8 versicolor
## 12 6.0 2.9 4.5 1.5 versicolor
## 13 5.7 2.6 3.5 1.0 versicolor
## 14 5.8 2.7 3.9 1.2 versicolor
## 15 6.0 2.7 5.1 1.6 versicolor
## 16 6.0 3.4 4.5 1.6 versicolor
## 17 5.6 3.0 4.1 1.3 versicolor
## 18 5.8 2.6 4.0 1.2 versicolor
## 19 5.6 2.7 4.2 1.3 versicolor
## 20 5.7 3.0 4.2 1.2 versicolor
## 21 5.7 2.9 4.2 1.3 versicolor
## 22 5.7 2.8 4.1 1.3 versicolor
## 23 5.8 2.7 5.1 1.9 virginica
## 24 5.7 2.5 5.0 2.0 virginica
## 25 5.8 2.8 5.1 2.4 virginica
## 26 6.0 2.2 5.0 1.5 virginica
## 27 5.6 2.8 4.9 2.0 virginica
## 28 6.0 3.0 4.8 1.8 virginica
## 29 5.8 2.7 5.1 1.9 virginica
## 30 5.9 3.0 5.1 1.8 virginica
Vamos criar uma nova coluna Genus
e uní-la às coluna Species
.
%>%
iris2 mutate(Genus = rep("Iris", times = nrow(iris2)), .before = Species)
## Sepal.Length Sepal.Width Petal.Length Petal.Width Genus Species
## 1 5.8 4.0 1.2 0.2 Iris setosa
## 2 5.7 4.4 1.5 0.4 Iris setosa
## 3 5.7 3.8 1.7 0.3 Iris setosa
## 4 5.7 2.8 4.5 1.3 Iris versicolor
## 5 5.9 3.0 4.2 1.5 Iris versicolor
## 6 6.0 2.2 4.0 1.0 Iris versicolor
## 7 5.6 2.9 3.6 1.3 Iris versicolor
## 8 5.6 3.0 4.5 1.5 Iris versicolor
## 9 5.8 2.7 4.1 1.0 Iris versicolor
## 10 5.6 2.5 3.9 1.1 Iris versicolor
## 11 5.9 3.2 4.8 1.8 Iris versicolor
## 12 6.0 2.9 4.5 1.5 Iris versicolor
## 13 5.7 2.6 3.5 1.0 Iris versicolor
## 14 5.8 2.7 3.9 1.2 Iris versicolor
## 15 6.0 2.7 5.1 1.6 Iris versicolor
## 16 6.0 3.4 4.5 1.6 Iris versicolor
## 17 5.6 3.0 4.1 1.3 Iris versicolor
## 18 5.8 2.6 4.0 1.2 Iris versicolor
## 19 5.6 2.7 4.2 1.3 Iris versicolor
## 20 5.7 3.0 4.2 1.2 Iris versicolor
## 21 5.7 2.9 4.2 1.3 Iris versicolor
## 22 5.7 2.8 4.1 1.3 Iris versicolor
## 23 5.8 2.7 5.1 1.9 Iris virginica
## 24 5.7 2.5 5.0 2.0 Iris virginica
## 25 5.8 2.8 5.1 2.4 Iris virginica
## 26 6.0 2.2 5.0 1.5 Iris virginica
## 27 5.6 2.8 4.9 2.0 Iris virginica
## 28 6.0 3.0 4.8 1.8 Iris virginica
## 29 5.8 2.7 5.1 1.9 Iris virginica
## 30 5.9 3.0 5.1 1.8 Iris virginica
<- iris2 %>%
iris3 mutate(Genus = rep("Iris", times = nrow(iris2)), .before = Species) %>%
unite(col = scientic_name, Genus, Species, sep = " ")
iris3
## Sepal.Length Sepal.Width Petal.Length Petal.Width scientic_name
## 1 5.8 4.0 1.2 0.2 Iris setosa
## 2 5.7 4.4 1.5 0.4 Iris setosa
## 3 5.7 3.8 1.7 0.3 Iris setosa
## 4 5.7 2.8 4.5 1.3 Iris versicolor
## 5 5.9 3.0 4.2 1.5 Iris versicolor
## 6 6.0 2.2 4.0 1.0 Iris versicolor
## 7 5.6 2.9 3.6 1.3 Iris versicolor
## 8 5.6 3.0 4.5 1.5 Iris versicolor
## 9 5.8 2.7 4.1 1.0 Iris versicolor
## 10 5.6 2.5 3.9 1.1 Iris versicolor
## 11 5.9 3.2 4.8 1.8 Iris versicolor
## 12 6.0 2.9 4.5 1.5 Iris versicolor
## 13 5.7 2.6 3.5 1.0 Iris versicolor
## 14 5.8 2.7 3.9 1.2 Iris versicolor
## 15 6.0 2.7 5.1 1.6 Iris versicolor
## 16 6.0 3.4 4.5 1.6 Iris versicolor
## 17 5.6 3.0 4.1 1.3 Iris versicolor
## 18 5.8 2.6 4.0 1.2 Iris versicolor
## 19 5.6 2.7 4.2 1.3 Iris versicolor
## 20 5.7 3.0 4.2 1.2 Iris versicolor
## 21 5.7 2.9 4.2 1.3 Iris versicolor
## 22 5.7 2.8 4.1 1.3 Iris versicolor
## 23 5.8 2.7 5.1 1.9 Iris virginica
## 24 5.7 2.5 5.0 2.0 Iris virginica
## 25 5.8 2.8 5.1 2.4 Iris virginica
## 26 6.0 2.2 5.0 1.5 Iris virginica
## 27 5.6 2.8 4.9 2.0 Iris virginica
## 28 6.0 3.0 4.8 1.8 Iris virginica
## 29 5.8 2.7 5.1 1.9 Iris virginica
## 30 5.9 3.0 5.1 1.8 Iris virginica
Observação: a função unite()
*exclui as colunas que foram unificadas da tabela.
7.1.7 Reformatando tabelas: funções spread()
e gather()
Importe a tabela HubbardBrook.csv
com dados anuais de vazão e precipitação em dois riachos de áreas desmatadas e referência. Os dados foram retirados de tiee.esa.org e podem ser obtidos em HubbardBrook.csv.
## # A tibble: 62 x 4
## Year Treatment Flow Precipitation
## <dbl> <chr> <dbl> <dbl>
## 1 1958 Deforested 645. 1168.
## 2 1959 Deforested 1012. 1483.
## 3 1960 Deforested 825. 1321.
## 4 1961 Deforested 470. 980.
## 5 1962 Deforested 777. 1232.
## 6 1963 Deforested 774. 1139.
## 7 1964 Deforested 712. 1175.
## 8 1965 Deforested 599. 1115.
## 9 1966 Deforested 1189. 1222.
## 10 1967 Deforested 1132. 1315.
## # ... with 52 more rows
<- read_csv("C:/seu_caminho/IntroR/HubbardBrook.csv")
stream stream
A função spread()
reorganiza dados do formato longo para o formato largo. Vamos vazer isto abaixo somente para a variável Flow
e excluindo Precipitation
.
<- stream %>%
stream_largo select(-Precipitation) %>%
spread(key = Treatment, value = Flow)
stream_largo
## # A tibble: 31 x 3
## Year Deforested Reference
## <dbl> <dbl> <dbl>
## 1 1958 645. 567.
## 2 1959 1012. 918.
## 3 1960 825. 752.
## 4 1961 470. 436.
## 5 1962 777. 699.
## 6 1963 774. 663.
## 7 1964 712. 630.
## 8 1965 599. 547.
## 9 1966 1189. 727.
## 10 1967 1132. 781.
## # ... with 21 more rows
Enquanto a função gather()
faz o caminho reverso.
<- stream_largo %>%
stream_longo gather(key = Desmatamento, value = Flow, -Year)
stream_longo
## # A tibble: 62 x 3
## Year Desmatamento Flow
## <dbl> <chr> <dbl>
## 1 1958 Deforested 645.
## 2 1959 Deforested 1012.
## 3 1960 Deforested 825.
## 4 1961 Deforested 470.
## 5 1962 Deforested 777.
## 6 1963 Deforested 774.
## 7 1964 Deforested 712.
## 8 1965 Deforested 599.
## 9 1966 Deforested 1189.
## 10 1967 Deforested 1132.
## # ... with 52 more rows