Aula 04 · Introdução à Linguagem R
PPG em Ecologia e Conservação · UFMS
Wickham, H. (2011). The split-apply-combine strategy for data analysis. Journal of Statistical Software 40(1): 1–29. doi:10.18637/jss.v040.i01
group_by() faz o split, summarise() faz o apply e o combine — e você nunca vê os grupos separados.
O equivalente no R base seria um for sobre as espécies, um mean() dentro, um objeto crescendo a cada volta e um rbind() no fim. Quatro lugares para errar em vez de um.
É por isso que o artigo de 2011 tem 29 páginas para uma ideia que cabe em duas linhas: a ideia é simples, escrever isso certo à mão é que não era.
Esquema baseado em Wickham, Çetinkaya-Rundel & Grolemund, R for Data Science (2ª ed.). A aula de hoje é a seta Arrumar; a de amanhã, o laço Explorar.
O tidyverse é um guarda-chuva: carrega dplyr, tidyr, ggplot2, readr, purrr e mais alguns de uma vez. Hoje usamos os dois primeiros.
Bovo, R.P.; Simon, M.N.; Provete, D.B.; Lyra, M.; Navas, C.A.; Andrade, D.V. (2023). Beyond Janzen’s Hypothesis: How Amphibians That Climb Tropical Mountains Respond to Climate Variation. Integrative Organismal Biology 5(1): obad009. doi:10.1093/iob/obad009
225 indivíduos, 5 espécies de anuros, 6 altitudes, 2 serras da Mata Atlântica. Limites térmicos, perda de água, massa e clima de cada sítio.
Dados reais e publicados. É o mesmo arquivo da aula 01 à aula 08.
[1] 225 26
[1] "ID" "Species"
[3] "Sex" "EWL_Ugcm2s1"
[5] "WU_Ugcm2s1" "perc_hidration_after_EWL"
[7] "Bodymass_g" "CTmin"
[9] "CTmax" "Tbr"
[11] "WT" "Mountain_Range"
Repare nos nomes: EWL_Ugcm2s1, Bodymass_g, Altitude_m. A unidade está no nome da coluna — ótimo para quem abre o arquivo solto, cansativo para quem vai digitar aquilo cinquenta vezes hoje.
dplyr
rename() muda o nome de uma colunaselect() escolhe colunasfilter() escolhe linhas por um critério — o filtro do Excelmutate() cria colunas novas a partir das que existemsummarise() reduz muitas linhas a um valor-resumoarrange() ordena as linhasselect mexe em coluna, filter mexe em linha. Trocar os dois é o erro mais comum da primeira semana.
rename() — tirar a unidade do nome[1] "ID" "especie"
[3] "sexo" "ewl"
[5] "WU_Ugcm2s1" "perc_hidration_after_EWL"
[7] "massa" "ctmin"
A unidade não sumiu — mudou de lugar. Ela agora vive no comentário do script e no arquivo de metadados. Encurtar nome sem fazer isso é perder informação.
select() — ficar só com o que interessa id especie sexo serra altitude massa ewl
1 RPB 41 Rhinella icterica Male Serra do Mar 820 218.88 1.9732
2 RPB 42 Rhinella icterica Male Serra do Mar 820 233.12 2.0827
3 RPB 69 Rhinella icterica <NA> Serra do Mar 820 63.65 2.7657
4 RPB 114 Rhinella icterica Male Serra do Mar 820 85.05 1.5170
ctmin ctmax bio5
1 3.4 39.5 25.3
2 4.2 39.3 25.3
3 3.2 40.6 25.3
4 1.8 39.0 25.3
Repare: select() também renomeia (bio5 = BIO_5). Um verbo a menos.
filter() — escolher linhas[1] 46
[1] 106
[1] 107
Cento e sete sem sexo registrado, de 225. Não é erro de digitação: nem sempre dá para sexar o animal. Mas é uma variável que vocês não vão conseguir usar como preditora.
Vírgula dentro do filter() significa e. Para “ou”, use |.
mutate() — criar coluna Min. 1st Qu. Median Mean 3rd Qu. Max. NAs
0.60 8.50 10.80 10.69 13.70 15.30 35
O arquivo já trazia essas duas prontas. Recalculamos assim mesmo — não por desconfiança, mas porque agora a definição está escrita no código, e não só num arquivo de metadados que o leitor pode nunca abrir.
%>% id especie sexo serra altitude massa ewl
1 RPB 285 Dendropsophus minutus <NA> Serra do Mar 1500 0.5588 1.6490
2 RPB 286 Dendropsophus minutus Male Serra do Mar 1500 0.6915 1.7245
3 RPB 287 Dendropsophus minutus Male Serra do Mar 1500 0.5292 1.7974
ctmin ctmax bio5 amplitude tol_aquec
1 6.4 28.7 23.8 22.3 4.900001
2 5.1 29.7 23.8 24.6 5.900001
3 3.3 29.7 23.8 26.4 5.900001
Leia o %>% como “e então”. O R moderno também aceita |>, nativo, que faz o mesmo nos casos simples.
group_by() + summarise()O split-apply-combine do Wickham, em duas linhas:
# A tibble: 5 × 4
especie n ctmax_med ctmax_dp
<chr> <int> <dbl> <dbl>
1 Boana faber 46 38.4 0.78
2 Dendropsophus minutus 59 33.2 1.7
3 Leptodactylus latrans 31 38.8 0.62
4 Physalaemus cuvieri 39 35.1 1.61
5 Rhinella icterica 50 38.8 0.68
10 minutos — encadeie os verbos
Escreva um pipeline, do anuros até a resposta, para cada pergunta:
ctmax medido?Regra: um %>% por linha. Quando der erro, apague a última linha e rode de novo — assim você descobre em qual verbo quebrou, em vez de adivinhar.
.groups# A tibble: 4 × 3
especie serra n
<chr> <chr> <int>
1 Boana faber Serra da Mantiqueira 14
2 Boana faber Serra do Mar 32
3 Dendropsophus minutus Serra da Mantiqueira 10
4 Dendropsophus minutus Serra do Mar 49
Sem .groups = "drop", o resultado sai ainda agrupado por especie, e a próxima operação age dentro de cada espécie sem avisar. É a fonte silenciosa de resultado errado mais comum do dplyr.
serra altitude n
1 Serra da Mantiqueira 550 18
2 Serra da Mantiqueira 1600 55
3 Serra do Mar 35 39
4 Serra do Mar 820 36
5 Serra do Mar 1022 54
6 Serra do Mar 1500 23
Leiam com atenção: cada altitude aparece em uma serra só.
Isso não é defeito do arquivo — é como a coleta foi feita. E vai decidir quais modelos são possíveis na aula 06. Guardem.
tidyr
Wickham, H. (2014). Tidy Data. Journal of Statistical Software 59(10): 1–23. doi:10.18637/jss.v059.i10
pivot_longer() — de largo para longoNosso arquivo tem ctmin e ctmax em duas colunas. Para o ggplot, muitas vezes queremos uma coluna “limite” e uma coluna “valor”:
# A tibble: 4 × 5
id especie altitude limite temperatura
<chr> <chr> <int> <chr> <dbl>
1 RPB 41 Rhinella icterica 820 ctmin 3.4
2 RPB 41 Rhinella icterica 820 ctmax 39.5
3 RPB 42 Rhinella icterica 820 ctmin 4.2
4 RPB 42 Rhinella icterica 820 ctmax 39.3
De 225 linhas para 450: cada indivíduo agora ocupa duas.
pivot_wider() — o caminho de volta# A tibble: 3 × 5
id especie altitude ctmin ctmax
<chr> <chr> <int> <list> <list>
1 RPB 41 Rhinella icterica 820 <dbl [1]> <dbl [1]>
2 RPB 42 Rhinella icterica 820 <dbl [1]> <dbl [1]>
3 RPB 69 Rhinella icterica 820 <dbl [1]> <dbl [1]>
“Largo” e “longo” não são certo e errado — são formatos convenientes para propósitos diferentes. Largo para ler na tela; longo para o ggplot e para a maioria dos modelos.
tidyrseparate() / unite() — dividir e juntar colunas (útil quando alguém gravou "Boana faber" e "macho" na mesma célula)drop_na() — remove as linhas com ausentesreplace_na() / fill() — substituem ou propagamCuidado com drop_na() sem argumento: ele apaga a linha se qualquer coluna tiver NA. Aqui isso jogaria fora os 107 indivíduos sem sexo, mesmo numa análise que nem usa sexo. Diga em qual coluna: drop_na(ctmax).
[1] 225
[1] 91
[1] 190
O primeiro drop_na() custou mais da metade da amostra para nada. Silêncio total: nenhum aviso, nenhum erro. Só um n menor lá na frente.
dados/, como veio da fonte.dados/processados/, que entra no .gitignore — porque o script que o gera está versionado, e isso basta para reconstruí-lo.Esse arquivo é o que as aulas 05, 06 e 07 vão ler. Rodem o aula-04.R antes delas.
Sempre na versão mais recente, direto da fonte:
Posit Software, PBC · CC BY-SA
Com o dado da semana — abram o aula-04.R:
dplyr, não contando na tabela.ewl por serra e sexo. O que fazer com a linha dos NA?amplitude tem 35 ausentes, os mesmos de ctmax. Mostre com código que são os mesmos indivíduos.No livro Análises Ecológicas no R, capítulo 5: leiam o tópico 5.6 e façam do 5.7.6 ao 5.8.17.
