Aula 2 - Manipulação de Dados

Author

Marina Scalon

Script utilizado na aula 2 para demostrar as funções do pacote dpyr e tidyr do tidyverse

Instalando os pacotes

Nessa aula vamos utilizar o mesmo conjunto de dados da aula 1 para demostrar as funções dos pacotes tidyr e dplyr do tidyverse. O primeiro passo então é carregar o pacote. Confiram a versão e atualizem para versão 2.0.0 usando a função tidyverse_update()!

library(tidyverse)
Warning: package 'tidyverse' was built under R version 4.0.5
-- Attaching packages --------------------------------------- tidyverse 1.3.1 --
v ggplot2 3.3.5     v purrr   0.3.4
v tibble  3.1.3     v dplyr   1.0.7
v tidyr   1.1.3     v stringr 1.4.0
v readr   2.0.1     v forcats 0.5.1
Warning: package 'ggplot2' was built under R version 4.0.5
Warning: package 'tibble' was built under R version 4.0.5
Warning: package 'tidyr' was built under R version 4.0.5
Warning: package 'readr' was built under R version 4.0.5
Warning: package 'dplyr' was built under R version 4.0.5
Warning: package 'forcats' was built under R version 4.0.5
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
# tidyverse_update()

Carregando o conjunto de dados

Agora vamos determinar o diretório de trabalho e carregar os dados, conforme aprendemos na aula anterior.

Você deve colocar o diretório de acordo com o seu caminho no computador, e de acordo com a localização dos seus dados.

# setwd("C:/Marina/Pos-doutorado/PNPD_UFPR/Vis Man Dados/Aula 2")
# dados <- read.csv("Dados.csv")
dados <- readr::read_csv('https://raw.githubusercontent.com/scalonmc/VisMan/master/VisManDados/Aula1/dados.csv')
Rows: 129 Columns: 13
-- Column specification --------------------------------------------------------
Delimiter: ","
chr  (3): Tratamento, especie, Grupo
dbl (10): Amostra, individuo, N, P, Mg, K, Ca, Al_ppm, area, peso

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
str(dados)
spec_tbl_df [129 x 13] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ Amostra   : num [1:129] 1 2 3 4 5 6 7 8 9 10 ...
 $ Tratamento: chr [1:129] "Floresta" "Floresta" "Floresta" "Floresta" ...
 $ especie   : chr [1:129] "AT" "AT" "AT" "BC" ...
 $ Grupo     : chr [1:129] "D" "D" "D" "B" ...
 $ individuo : num [1:129] 1 2 3 1 2 3 1 2 3 1 ...
 $ N         : num [1:129] 2.36 2.07 2.03 1.32 1.23 ...
 $ P         : num [1:129] 0.1143 0.1143 0.1214 0.0643 0.0714 ...
 $ Mg        : num [1:129] 0.15 0.18 0.133 0.159 0.113 ...
 $ K         : num [1:129] 1.197 1.444 0.366 0.679 0.957 ...
 $ Ca        : num [1:129] 0.319 0.413 0.371 0.576 0.458 ...
 $ Al_ppm    : num [1:129] 122.8 251.8 206.5 96.8 103.3 ...
 $ area      : num [1:129] 288 262 184 149 263 ...
 $ peso      : num [1:129] 3.63 2.49 2.16 1.86 4.39 ...
 - attr(*, "spec")=
  .. cols(
  ..   Amostra = col_double(),
  ..   Tratamento = col_character(),
  ..   especie = col_character(),
  ..   Grupo = col_character(),
  ..   individuo = col_double(),
  ..   N = col_double(),
  ..   P = col_double(),
  ..   Mg = col_double(),
  ..   K = col_double(),
  ..   Ca = col_double(),
  ..   Al_ppm = col_double(),
  ..   area = col_double(),
  ..   peso = col_double()
  .. )
 - attr(*, "problems")=<externalptr> 

Utilizando as funções do dplyr

Select

A função select() é importante para selecionar ou excluir variáveis (colunas do dataset)

Abaixo, vamos fazer passo a passo:

  1. Selecionar apenas as variáveis categóricas
  2. Excluir variávies não úteis
  3. Condicional, no caso se a variável for numérica usando is.numeric
  4. Selecionar variávels com alguma característica comum utilizando starts_with() ou ends_with()
  5. Alterar ordem para visualização dos dados
categoricas <- select(dados, Tratamento, especie, Grupo) #1
str(categoricas)
tibble [129 x 3] (S3: tbl_df/tbl/data.frame)
 $ Tratamento: chr [1:129] "Floresta" "Floresta" "Floresta" "Floresta" ...
 $ especie   : chr [1:129] "AT" "AT" "AT" "BC" ...
 $ Grupo     : chr [1:129] "D" "D" "D" "B" ...
clean <- select(dados, -Amostra, -individuo) #2
str(clean)
tibble [129 x 11] (S3: tbl_df/tbl/data.frame)
 $ Tratamento: chr [1:129] "Floresta" "Floresta" "Floresta" "Floresta" ...
 $ especie   : chr [1:129] "AT" "AT" "AT" "BC" ...
 $ Grupo     : chr [1:129] "D" "D" "D" "B" ...
 $ N         : num [1:129] 2.36 2.07 2.03 1.32 1.23 ...
 $ P         : num [1:129] 0.1143 0.1143 0.1214 0.0643 0.0714 ...
 $ Mg        : num [1:129] 0.15 0.18 0.133 0.159 0.113 ...
 $ K         : num [1:129] 1.197 1.444 0.366 0.679 0.957 ...
 $ Ca        : num [1:129] 0.319 0.413 0.371 0.576 0.458 ...
 $ Al_ppm    : num [1:129] 122.8 251.8 206.5 96.8 103.3 ...
 $ area      : num [1:129] 288 262 184 149 263 ...
 $ peso      : num [1:129] 3.63 2.49 2.16 1.86 4.39 ...
numericas <- select_if(dados, is.numeric) #3

ppm <- select(clean, ends_with("ppm")) #4
str(ppm)
tibble [129 x 1] (S3: tbl_df/tbl/data.frame)
 $ Al_ppm: num [1:129] 122.8 251.8 206.5 96.8 103.3 ...
ordered <- select(dados, N, P, everything())
head(ordered)
# A tibble: 6 x 13
      N      P Amostra Tratamento especie Grupo individuo    Mg     K    Ca
  <dbl>  <dbl>   <dbl> <chr>      <chr>   <chr>     <dbl> <dbl> <dbl> <dbl>
1  2.36 0.114        1 Floresta   AT      D             1 0.150 1.20  0.319
2  2.07 0.114        2 Floresta   AT      D             2 0.180 1.44  0.413
3  2.03 0.121        3 Floresta   AT      D             3 0.133 0.366 0.371
4  1.32 0.0643       4 Floresta   BC      B             1 0.159 0.679 0.576
5  1.23 0.0714       5 Floresta   BC      B             2 0.113 0.957 0.458
6  1.37 0.0786       6 Floresta   BC      B             3 0.116 0.75  0.347
# ... with 3 more variables: Al_ppm <dbl>, area <dbl>, peso <dbl>

Rbase

Para fazer a mesma coisa no Rbase
São comandos bem simples que eu acho importante demostrar
O diferencial é precisar verificar o número correspondente da coluna do dataframe
categoricas2 <- dados[2:4] #1
str(categoricas2)
tibble [129 x 3] (S3: tbl_df/tbl/data.frame)
 $ Tratamento: chr [1:129] "Floresta" "Floresta" "Floresta" "Floresta" ...
 $ especie   : chr [1:129] "AT" "AT" "AT" "BC" ...
 $ Grupo     : chr [1:129] "D" "D" "D" "B" ...
clean2 <- dados[-c(1,5)] #2
str(clean)
tibble [129 x 11] (S3: tbl_df/tbl/data.frame)
 $ Tratamento: chr [1:129] "Floresta" "Floresta" "Floresta" "Floresta" ...
 $ especie   : chr [1:129] "AT" "AT" "AT" "BC" ...
 $ Grupo     : chr [1:129] "D" "D" "D" "B" ...
 $ N         : num [1:129] 2.36 2.07 2.03 1.32 1.23 ...
 $ P         : num [1:129] 0.1143 0.1143 0.1214 0.0643 0.0714 ...
 $ Mg        : num [1:129] 0.15 0.18 0.133 0.159 0.113 ...
 $ K         : num [1:129] 1.197 1.444 0.366 0.679 0.957 ...
 $ Ca        : num [1:129] 0.319 0.413 0.371 0.576 0.458 ...
 $ Al_ppm    : num [1:129] 122.8 251.8 206.5 96.8 103.3 ...
 $ area      : num [1:129] 288 262 184 149 263 ...
 $ peso      : num [1:129] 3.63 2.49 2.16 1.86 4.39 ...
nutri <- dados[6:13] #3
str(nutri)
tibble [129 x 8] (S3: tbl_df/tbl/data.frame)
 $ N     : num [1:129] 2.36 2.07 2.03 1.32 1.23 ...
 $ P     : num [1:129] 0.1143 0.1143 0.1214 0.0643 0.0714 ...
 $ Mg    : num [1:129] 0.15 0.18 0.133 0.159 0.113 ...
 $ K     : num [1:129] 1.197 1.444 0.366 0.679 0.957 ...
 $ Ca    : num [1:129] 0.319 0.413 0.371 0.576 0.458 ...
 $ Al_ppm: num [1:129] 122.8 251.8 206.5 96.8 103.3 ...
 $ area  : num [1:129] 288 262 184 149 263 ...
 $ peso  : num [1:129] 3.63 2.49 2.16 1.86 4.39 ...

Slice

A função slice() é importante para selecionar ou excluir observações (linhas do dataset)

Abaixo, vamos fazer passo a passo:

  1. Retirar linhas correspondentes a vegetação “Savana”
  2. Selecionar apenas as linhas correspondentes a vegetação “Savana”
sem.savana <- slice(clean, -46:-90)
str(sem.savana)
tibble [84 x 11] (S3: tbl_df/tbl/data.frame)
 $ Tratamento: chr [1:84] "Floresta" "Floresta" "Floresta" "Floresta" ...
 $ especie   : chr [1:84] "AT" "AT" "AT" "BC" ...
 $ Grupo     : chr [1:84] "D" "D" "D" "B" ...
 $ N         : num [1:84] 2.36 2.07 2.03 1.32 1.23 ...
 $ P         : num [1:84] 0.1143 0.1143 0.1214 0.0643 0.0714 ...
 $ Mg        : num [1:84] 0.15 0.18 0.133 0.159 0.113 ...
 $ K         : num [1:84] 1.197 1.444 0.366 0.679 0.957 ...
 $ Ca        : num [1:84] 0.319 0.413 0.371 0.576 0.458 ...
 $ Al_ppm    : num [1:84] 122.8 251.8 206.5 96.8 103.3 ...
 $ area      : num [1:84] 288 262 184 149 263 ...
 $ peso      : num [1:84] 3.63 2.49 2.16 1.86 4.39 ...
so.savana <- slice(clean, 46:90)
str(so.savana)
tibble [45 x 11] (S3: tbl_df/tbl/data.frame)
 $ Tratamento: chr [1:45] "Savana" "Savana" "Savana" "Savana" ...
 $ especie   : chr [1:45] "AT" "AT" "AT" "BC" ...
 $ Grupo     : chr [1:45] "D" "D" "D" "B" ...
 $ N         : num [1:45] 2.07 2.36 2.4 1.41 1.55 ...
 $ P         : num [1:45] 0.1071 0.1714 0.1071 0.0786 0.0714 ...
 $ Mg        : num [1:45] 0.22 0.205 0.214 0.171 0.222 ...
 $ K         : num [1:45] 1.303 1.28 1.126 0.814 0.879 ...
 $ Ca        : num [1:45] 0.813 0.825 0.57 0.603 0.968 ...
 $ Al_ppm    : num [1:45] 155 213 155 239 258 ...
 $ area      : num [1:45] 352 378 375 208 574 ...
 $ peso      : num [1:45] 3.4 3.87 5.07 2.68 6.17 ...

Rbase

Para fazer a mesma coisa no Rbase
Sem usar a função **subset()** e usando a função **subset()**
so.savana2 <- clean[46:90,]
so.savana3 <- subset(clean, Tratamento == "Savana")

sem.savana2 <- clean[-(46:90),]
sem.savana3 <- subset(clean, Tratamento != "Savana")

Slice

A função filter() funciona para seleção condicional de variáveis Ela é equivalente a função subset() do Rbase

deciduous <-  filter(clean, Grupo == "D")
deciduous2 <- subset(clean, Grupo == "D")

Também é possível combinar as condições de filtro!

Nesse caso estamos selecionando as espécies decíduas (D) apenas de Floresta com nitrogênio foliar maior que 2%

deciduous.floresta.highN <- filter(clean, Grupo == "D" & 
                                     Tratamento =="Floresta" &
                                     N >=2)
str(deciduous.floresta.highN)
tibble [6 x 11] (S3: tbl_df/tbl/data.frame)
 $ Tratamento: chr [1:6] "Floresta" "Floresta" "Floresta" "Floresta" ...
 $ especie   : chr [1:6] "AT" "AT" "AT" "GN" ...
 $ Grupo     : chr [1:6] "D" "D" "D" "D" ...
 $ N         : num [1:6] 2.36 2.07 2.03 4.62 3.77 ...
 $ P         : num [1:6] 0.114 0.114 0.121 0.143 0.157 ...
 $ Mg        : num [1:6] 0.15 0.18 0.133 0.247 0.176 ...
 $ K         : num [1:6] 1.197 1.444 0.366 1.263 1.388 ...
 $ Ca        : num [1:6] 0.319 0.413 0.371 0.645 0.266 ...
 $ Al_ppm    : num [1:6] 123 252 206 181 148 ...
 $ area      : num [1:6] 288 262 184 274 385 ...
 $ peso      : num [1:6] 3.63 2.49 2.16 3.92 3.62 ...

Verificar operadores lógicos do R

Operador %in%

Para selecionar vários níveis dentro de uma variável

sp <- filter(clean, especie %in% c("CB", "KC", "QP"))
str(sp)
tibble [27 x 11] (S3: tbl_df/tbl/data.frame)
 $ Tratamento: chr [1:27] "Floresta" "Floresta" "Floresta" "Floresta" ...
 $ especie   : chr [1:27] "CB" "CB" "CB" "KC" ...
 $ Grupo     : chr [1:27] "B" "B" "B" "D" ...
 $ N         : num [1:27] 1.18 1.27 1.55 1.23 1.41 ...
 $ P         : num [1:27] 0.0929 0.0786 0.0714 0.0786 0.1 ...
 $ Mg        : num [1:27] 0.088 0.0788 0.0822 0.1123 0.1307 ...
 $ K         : num [1:27] 0.318 0.233 0.336 0.567 0.459 0.479 0.376 0.934 0.405 0.657 ...
 $ Ca        : num [1:27] 0.315 0.12 0.112 0.311 0.336 ...
 $ Al_ppm    : num [1:27] 45.3 51.8 38.8 155 180.8 ...
 $ area      : num [1:27] 490 312 288 287 145 ...
 $ peso      : num [1:27] 5.6 4.77 5.38 4.78 1.42 ...

Rename

A função rename() é importante para mudar os nomes das variáveis. O nome atual vem antes do nome original. Vamos mudar os nomes para inglês.

Dica!

Quando o nome for espaçado ou tiver caracter especial, deve estar entre o símbolo `

ls(clean)
 [1] "Al_ppm"     "area"       "Ca"         "especie"    "Grupo"     
 [6] "K"          "Mg"         "N"          "P"          "peso"      
[11] "Tratamento"
new <- rename(clean, Vegetation = Tratamento, Species = especie, `Phenological group` = Grupo,
                Al = Al_ppm, 
                `leaf area` = area, `leaf mass` = peso)

ls(new)
 [1] "Al"                 "Ca"                 "K"                 
 [4] "leaf area"          "leaf mass"          "Mg"                
 [7] "N"                  "P"                  "Phenological group"
[10] "Species"            "Vegetation"        

Arrange

A função arrange() permite colocarmos os dados em determinada ordem. Isso é importante principalmente para verificar tendências ou outliers Aqui vamos colocar os dados na ordem do maior valor de Al par ao menor para verificarmos as plantas acumuladoras de alumínio. Vamos usar a função head() para olhar como os dados foram ordenados do maior valor de Al.

acumuladoras <- arrange (new, desc(Al))

head(acumuladoras)
# A tibble: 6 x 11
  Vegetation Species `Phenological group`     N      P     Mg     K    Ca     Al
  <chr>      <chr>   <chr>                <dbl>  <dbl>  <dbl> <dbl> <dbl>  <dbl>
1 Savana     QP      D                    1.40  0.0786 0.0736 0.728 0.398 15012.
2 Savana     QP      D                    1.48  0.0857 0.0812 0.632 0.236 12878.
3 Savana     QP      D                    1.06  0.0714 0.0728 0.893 0.210 12522.
4 Floresta   QP      D                    1.84  0.0714 0.0776 0.376 0.412 12345 
5 Floresta   QP      D                    1.32  0.0786 0.0844 0.405 0.515 11365 
6 Savana     VE      S                    0.754 0.0571 0.0347 0.326 0.196 10975 
# ... with 2 more variables: leaf area <dbl>, leaf mass <dbl>

Mais interessante talvez seja ver esse padrão por algum grupo. Para isso arrange() pode ser muito útil.

acumuladoras <- arrange(new, `Phenological group`, desc(Al))
head(acumuladoras)
# A tibble: 6 x 11
  Vegetation Species `Phenological group`     N      P     Mg     K    Ca    Al
  <chr>      <chr>   <chr>                <dbl>  <dbl>  <dbl> <dbl> <dbl> <dbl>
1 Savana     BC      B                     1.56 0.0714 0.222  0.879 0.968  258.
2 Savana     SA      B                     2.08 0.0714 0.0941 0.561 0.221  258.
3 Savana     SA      B                     1.91 0.0643 0.0734 0.313 0.113  252.
4 Savana     BC      B                     1.41 0.0786 0.171  0.814 0.603  239.
5 Savana     SA      B                     1.99 0.0571 0.0704 0.369 0.15   239.
6 Campo      CB      B                     1.56 0.0786 0.160  0.507 0.503  226 
# ... with 2 more variables: leaf area <dbl>, leaf mass <dbl>

Mutate

A função mutate() é muito utilizada para diversos objetivos de manipulação. Com ela, podemos:

  1. Transformar classes de objetos
  2. Mudar os nomes de variáveis ou de fatores
  3. Criar novas variáveis

A função transform() também cria novas variávies de forma equivalente, mas observe a diferença nos nomes das variáveis

str(new)
tibble [129 x 11] (S3: tbl_df/tbl/data.frame)
 $ Vegetation        : chr [1:129] "Floresta" "Floresta" "Floresta" "Floresta" ...
 $ Species           : chr [1:129] "AT" "AT" "AT" "BC" ...
 $ Phenological group: chr [1:129] "D" "D" "D" "B" ...
 $ N                 : num [1:129] 2.36 2.07 2.03 1.32 1.23 ...
 $ P                 : num [1:129] 0.1143 0.1143 0.1214 0.0643 0.0714 ...
 $ Mg                : num [1:129] 0.15 0.18 0.133 0.159 0.113 ...
 $ K                 : num [1:129] 1.197 1.444 0.366 0.679 0.957 ...
 $ Ca                : num [1:129] 0.319 0.413 0.371 0.576 0.458 ...
 $ Al                : num [1:129] 122.8 251.8 206.5 96.8 103.3 ...
 $ leaf area         : num [1:129] 288 262 184 149 263 ...
 $ leaf mass         : num [1:129] 3.63 2.49 2.16 1.86 4.39 ...
dados.factor <- mutate_if(new, is.character, as.factor) #1
str(dados.factor)
tibble [129 x 11] (S3: tbl_df/tbl/data.frame)
 $ Vegetation        : Factor w/ 3 levels "Campo","Floresta",..: 2 2 2 2 2 2 2 2 2 2 ...
 $ Species           : Factor w/ 15 levels "AT","BC","BS",..: 1 1 1 2 2 2 3 3 3 4 ...
 $ Phenological group: Factor w/ 3 levels "B","D","S": 2 2 2 1 1 1 1 1 1 1 ...
 $ N                 : num [1:129] 2.36 2.07 2.03 1.32 1.23 ...
 $ P                 : num [1:129] 0.1143 0.1143 0.1214 0.0643 0.0714 ...
 $ Mg                : num [1:129] 0.15 0.18 0.133 0.159 0.113 ...
 $ K                 : num [1:129] 1.197 1.444 0.366 0.679 0.957 ...
 $ Ca                : num [1:129] 0.319 0.413 0.371 0.576 0.458 ...
 $ Al                : num [1:129] 122.8 251.8 206.5 96.8 103.3 ...
 $ leaf area         : num [1:129] 288 262 184 149 263 ...
 $ leaf mass         : num [1:129] 3.63 2.49 2.16 1.86 4.39 ...
new.rename <- mutate(dados.factor, `Phenological group` = recode(`Phenological group`, D = "Deciduous",  #2
                                      B = "Semideciduous", S = "Evergreen"),
                Vegetation = recode(Vegetation, Savana = "Savanna", Floresta = "Forest", Campo = "Grassland"))
str(new.rename)
tibble [129 x 11] (S3: tbl_df/tbl/data.frame)
 $ Vegetation        : Factor w/ 3 levels "Grassland","Forest",..: 2 2 2 2 2 2 2 2 2 2 ...
 $ Species           : Factor w/ 15 levels "AT","BC","BS",..: 1 1 1 2 2 2 3 3 3 4 ...
 $ Phenological group: Factor w/ 3 levels "Semideciduous",..: 2 2 2 1 1 1 1 1 1 1 ...
 $ N                 : num [1:129] 2.36 2.07 2.03 1.32 1.23 ...
 $ P                 : num [1:129] 0.1143 0.1143 0.1214 0.0643 0.0714 ...
 $ Mg                : num [1:129] 0.15 0.18 0.133 0.159 0.113 ...
 $ K                 : num [1:129] 1.197 1.444 0.366 0.679 0.957 ...
 $ Ca                : num [1:129] 0.319 0.413 0.371 0.576 0.458 ...
 $ Al                : num [1:129] 122.8 251.8 206.5 96.8 103.3 ...
 $ leaf area         : num [1:129] 288 262 184 149 263 ...
 $ leaf mass         : num [1:129] 3.63 2.49 2.16 1.86 4.39 ...
final <- mutate(new.rename, SLA = (`leaf area`/`leaf mass`), `N:P` = N/P) #3

final.2 <- transform(new.rename, SLA=(`leaf area`/`leaf mass`), `N:P` = N/P)

A função transmute() equivale a mutate para criação de novas variáveis, porém só mantém a coluna da variável criada (não adiciona novas colunas)

final.3 <- transmute(new.rename, SLA = (`leaf area`/`leaf mass`))

PIPE

O símbolo %>% conhecido como pipe é usado para unir as funções, podendo ser mentalmente substituído por “depois” (“then”).

Dessa forma, não precisa se referir aos dados que estão sendo utilizados no início de cada função pois o pipe já assume que o produto de uma etapa é o impute da seguinte.

Assim, organizar o seu código aplicando todos os comandos que fizemos acima, mas usando pipe reduz o número de linhas e deixa tudo mais limpo.

Veja as etapas para chegar no dataset final:

final.pipe <- dados %>%
  mutate_if(is.character, as.factor) %>%  #mudar classe dos objetos
  select(-Amostra, -individuo) %>%  # eliminar colunas inuteis
  rename(Vegetation = Tratamento, Species = especie, `Phenological group` = Grupo,
                Al = Al_ppm, 
                `leaf area` = area, `leaf mass` = peso) %>% #renomear variáveis
  mutate(`Phenological group` = recode(`Phenological group`, D = "Deciduous", 
                                      B = "Semideciduous", S = "Evergreen"),
                Vegetation = recode(Vegetation, Savana = "Savanna", 
                                    Floresta = "Forest", Campo = "Grassland")) %>%  # renomear os fatores
 mutate(SLA=(`leaf area`/`leaf mass`), `N:P` = N/P) #criar novas variáveis

summary(final.pipe)
     Vegetation    Species       Phenological group       N        
 Grassland:39   AT     : 9   Semideciduous:44       Min.   :0.612  
 Forest   :45   BC     : 9   Deciduous    :45       1st Qu.:1.225  
 Savanna  :45   CB     : 9   Evergreen    :40       Median :1.413  
                DM     : 9                          Mean   :1.704  
                GN     : 9                          3rd Qu.:2.026  
                KC     : 9                          Max.   :4.994  
                (Other):75                                         
       P                 Mg               K                Ca        
 Min.   :0.03570   Min.   :0.0053   Min.   :0.1910   Min.   :0.0725  
 1st Qu.:0.06430   1st Qu.:0.0745   1st Qu.:0.3760   1st Qu.:0.1738  
 Median :0.07140   Median :0.1026   Median :0.5090   Median :0.2727  
 Mean   :0.08012   Mean   :0.1124   Mean   :0.6624   Mean   :0.3319  
 3rd Qu.:0.08570   3rd Qu.:0.1471   3rd Qu.:0.8140   3rd Qu.:0.4584  
 Max.   :0.22860   Max.   :0.2745   Max.   :2.4910   Max.   :0.9681  
                                                                     
       Al            leaf area        leaf mass           SLA        
 Min.   :   19.3   Min.   : 34.34   Min.   :0.2584   Min.   : 31.59  
 1st Qu.:  116.3   1st Qu.:137.17   1st Qu.:1.8373   1st Qu.: 60.18  
 Median :  180.8   Median :192.61   Median :2.4810   Median : 77.10  
 Mean   : 1763.2   Mean   :204.89   Mean   :2.9656   Mean   : 78.71  
 3rd Qu.:  419.5   3rd Qu.:257.68   3rd Qu.:3.8455   3rd Qu.: 94.92  
 Max.   :15012.5   Max.   :573.53   Max.   :9.4754   Max.   :150.00  
                   NA's   :3        NA's   :3        NA's   :3       
      N:P        
 Min.   : 8.653  
 1st Qu.:16.781  
 Median :19.780  
 Mean   :21.896  
 3rd Qu.:24.412  
 Max.   :63.537  
                 

Depois que você deixar os seus dados do jeito que você quer, salve novo arquivo de dados manipulados! Da próxima vez que você for usar conjunto da dados você já pode carregar o arquivo modificado e prontinho, sem passar pela etapa de manipulação novamente. Nunca substitua os dados originais! Use a função write.csv() e escreva sempre a extensão (.csv) no arquivo que será salvo.

write.csv(final.pipe, "Dados_manipulados.csv")

Summarise

A função summarise() (ou summarize()) cria um novo dataframe colapsando valores em um sumário. MUITO ÚTIL pra fazer tabelas de médias, desvio padrão, etc. Usualmente utilizamos a função group_by() antes para especificar os grupos. Também pode ser combinada por summarise_all para aplicar a função em todas as variáveis.

medias<- final.pipe %>% summarise(N = mean(N),
                                   P = mean(P))
medias
# A tibble: 1 x 2
      N      P
  <dbl>  <dbl>
1  1.70 0.0801
# Agrupando e aplicando em todas as colunas

medias2 <- final.pipe %>% group_by(Species, Vegetation, `Phenological group`) %>% 
                summarise_all(mean) #médias por colunas
head(medias2)
# A tibble: 6 x 13
# Groups:   Species, Vegetation [6]
  Species Vegetation `Phenological group`     N      P    Mg     K    Ca    Al
  <fct>   <fct>      <fct>                <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl>
1 AT      Grassland  Deciduous             1.79 0.102  0.165 1.72  0.623 239. 
2 AT      Forest     Deciduous             2.15 0.117  0.154 1.00  0.368 194. 
3 AT      Savanna    Deciduous             2.28 0.129  0.213 1.24  0.736 174. 
4 BC      Grassland  Semideciduous         1.05 0.0476 0.108 0.656 0.404 131. 
5 BC      Forest     Semideciduous         1.30 0.0714 0.130 0.795 0.460  86.0
6 BC      Savanna    Semideciduous         1.41 0.0690 0.176 0.843 0.708 232. 
# ... with 4 more variables: leaf area <dbl>, leaf mass <dbl>, SLA <dbl>,
#   N:P <dbl>

Múltiplas funções

tabela_mean <- final.pipe %>% select(-Species, -`Phenological group`)%>% group_by(Vegetation) %>% 
  summarise_all(mean, na.rm=T)

tabela1 <- final.pipe %>% select(-Species, -`Phenological group`) %>% group_by(Vegetation) %>% summarise_all(.funs = list(mean, sd))

tabela2 <- final.pipe %>% select(-Species, -`Phenological group`) %>% group_by(Vegetation) %>% summarise_all(.funs = list(mean = mean, sd = sd))

tabela3 <- final.pipe %>% select(-Species, -`Phenological group`) %>% group_by(Vegetation) %>% summarise_all(.funs = list(~mean(., na.rm=T), ~sd(., na.rm=T)))

tabela_all2 <- final.pipe %>% group_by(Vegetation) %>% 
  summarise(across(where(is.numeric), list(mean, sd),na.rm=T)) 

Utilizando o stringr para alterar nomes

Stringr é outro pacote do tidyverse que lida com strings - nomes!. Útil para manipular planilhas com variáveis characteres. Caso vc se interesse em se aprofundar nesse pacote, tem um vídeo muito útil feito pelo pessoal da UEM aqui

tabela_all3 <- tabela_all2 %>% rename_with(str_replace, pattern = "1", replacement = "media") %>% rename_with(str_replace, pattern = "2", replacement = "sd")

tabela_all3
# A tibble: 3 x 21
  Vegetation N_media  N_sd P_media   P_sd Mg_media  Mg_sd K_media  K_sd Ca_media
  <fct>        <dbl> <dbl>   <dbl>  <dbl>    <dbl>  <dbl>   <dbl> <dbl>    <dbl>
1 Grassland     1.58 0.626  0.0747 0.0238    0.115 0.0413   0.706 0.417    0.343
2 Forest        1.66 0.738  0.0811 0.0260    0.110 0.0442   0.591 0.363    0.326
3 Savanna       1.86 1.13   0.0838 0.0419    0.112 0.0627   0.696 0.422    0.328
# ... with 11 more variables: Ca_sd <dbl>, Al_media <dbl>, Al_sd <dbl>,
#   leaf area_media <dbl>, leaf area_sd <dbl>, leaf mass_media <dbl>,
#   leaf mass_sd <dbl>, SLA_media <dbl>, SLA_sd <dbl>, N:P_media <dbl>,
#   N:P_sd <dbl>

Utilizando o tibble para ajustar a tabela

Tibble é um pacote do tidyverse que transforma os dados em um novo tipo de data frame - um tibble. Muito útil para quem trabalha com datasets muito grandes porque é um dataframe simplificado.

tabela_all4 <- final.pipe %>% group_by(Vegetation) %>% 
  summarise(across(where(is.numeric), tibble::lst(mean, sd), na.rm=T, .names = "{fn}_{col}"))

tabela_all4
# A tibble: 3 x 21
  Vegetation mean_N  sd_N mean_P   sd_P mean_Mg  sd_Mg mean_K  sd_K mean_Ca
  <fct>       <dbl> <dbl>  <dbl>  <dbl>   <dbl>  <dbl>  <dbl> <dbl>   <dbl>
1 Grassland    1.58 0.626 0.0747 0.0238   0.115 0.0413  0.706 0.417   0.343
2 Forest       1.66 0.738 0.0811 0.0260   0.110 0.0442  0.591 0.363   0.326
3 Savanna      1.86 1.13  0.0838 0.0419   0.112 0.0627  0.696 0.422   0.328
# ... with 11 more variables: sd_Ca <dbl>, mean_Al <dbl>, sd_Al <dbl>,
#   mean_leaf area <dbl>, sd_leaf area <dbl>, mean_leaf mass <dbl>,
#   sd_leaf mass <dbl>, mean_SLA <dbl>, sd_SLA <dbl>, mean_N:P <dbl>,
#   sd_N:P <dbl>
write.csv(tabela_all4, "summary.csv")

Opção do Rbase

Família APPLY

> Aplica uma função para listas de valores
  Opção alternativa e MAIS eficiente que loops 

Apply para matrizes, lapply para listas, sapply para vetores. Aggregate para gerar tabelas de sumários por grupos.

apply(final.pipe[4:9], 2, mean) #apply(X, MARGIN, FUN), sendo a margin = 1 para rows e 2 para colunas
           N            P           Mg            K           Ca           Al 
1.704481e+00 8.012093e-02 1.124016e-01 6.624186e-01 3.318806e-01 1.763154e+03 
a<-as.list(final.pipe)
lapply(a[4:9], mean) 
$N
[1] 1.704481

$P
[1] 0.08012093

$Mg
[1] 0.1124016

$K
[1] 0.6624186

$Ca
[1] 0.3318806

$Al
[1] 1763.154
sum.table<-function(x){
  c(mean = mean(x, na.rm=T),sd = sd(x, na.rm=T))
}

lapply(a[4:9], sum.table)
$N
     mean        sd 
1.7044806 0.8685233 

$P
      mean         sd 
0.08012093 0.03193007 

$Mg
      mean         sd 
0.11240155 0.05033641 

$K
     mean        sd 
0.6624186 0.4012569 

$Ca
     mean        sd 
0.3318806 0.1980531 

$Al
    mean       sd 
1763.154 3430.080 
apply(final.pipe[4:9], 2, sum.table)
             N          P         Mg         K        Ca       Al
mean 1.7044806 0.08012093 0.11240155 0.6624186 0.3318806 1763.154
sd   0.8685233 0.03193007 0.05033641 0.4012569 0.1980531 3430.080
sapply(a[4:9], sum.table)
             N          P         Mg         K        Ca       Al
mean 1.7044806 0.08012093 0.11240155 0.6624186 0.3318806 1763.154
sd   0.8685233 0.03193007 0.05033641 0.4012569 0.1980531 3430.080
tapply(final.pipe$N, final.pipe$Vegetation, sum.table) #divide em grupos: tapply(X, INDEX, FUN = NULL)
$Grassland
     mean        sd 
1.5776410 0.6262919 

$Forest
     mean        sd 
1.6572667 0.7384168 

$Savanna
    mean       sd 
1.861622 1.126328 
tabela_all5 <- aggregate(final.pipe[4:13], list(final.pipe$Vegetation), sum.table)
str(tabela_all5)
'data.frame':   3 obs. of  11 variables:
 $ Group.1  : Factor w/ 3 levels "Grassland","Forest",..: 1 2 3
 $ N        : num [1:3, 1:2] 1.578 1.657 1.862 0.626 0.738 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : NULL
  .. ..$ : chr [1:2] "mean" "sd"
 $ P        : num [1:3, 1:2] 0.0747 0.0811 0.0838 0.0238 0.026 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : NULL
  .. ..$ : chr [1:2] "mean" "sd"
 $ Mg       : num [1:3, 1:2] 0.1153 0.1098 0.1125 0.0413 0.0442 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : NULL
  .. ..$ : chr [1:2] "mean" "sd"
 $ K        : num [1:3, 1:2] 0.706 0.591 0.696 0.417 0.363 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : NULL
  .. ..$ : chr [1:2] "mean" "sd"
 $ Ca       : num [1:3, 1:2] 0.343 0.326 0.328 0.18 0.167 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : NULL
  .. ..$ : chr [1:2] "mean" "sd"
 $ Al       : num [1:3, 1:2] 1157 1922 2130 2243 3594 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : NULL
  .. ..$ : chr [1:2] "mean" "sd"
 $ leaf area: num [1:3, 1:2] 218.1 216.8 179.9 74.5 75.6 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : NULL
  .. ..$ : chr [1:2] "mean" "sd"
 $ leaf mass: num [1:3, 1:2] 3.57 3.01 2.36 1.89 1.33 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : NULL
  .. ..$ : chr [1:2] "mean" "sd"
 $ SLA      : num [1:3, 1:2] 67.6 78.4 89.3 18.6 24.1 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : NULL
  .. ..$ : chr [1:2] "mean" "sd"
 $ N:P      : num [1:3, 1:2] 21.52 20.59 23.53 6.09 5.35 ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : NULL
  .. ..$ : chr [1:2] "mean" "sd"
str(tabela_all4)
tibble [3 x 21] (S3: tbl_df/tbl/data.frame)
 $ Vegetation    : Factor w/ 3 levels "Grassland","Forest",..: 1 2 3
 $ mean_N        : num [1:3] 1.58 1.66 1.86
 $ sd_N          : num [1:3] 0.626 0.738 1.126
 $ mean_P        : num [1:3] 0.0747 0.0811 0.0838
 $ sd_P          : num [1:3] 0.0238 0.026 0.0419
 $ mean_Mg       : num [1:3] 0.115 0.11 0.112
 $ sd_Mg         : num [1:3] 0.0413 0.0442 0.0627
 $ mean_K        : num [1:3] 0.706 0.591 0.696
 $ sd_K          : num [1:3] 0.417 0.363 0.422
 $ mean_Ca       : num [1:3] 0.343 0.326 0.328
 $ sd_Ca         : num [1:3] 0.18 0.167 0.241
 $ mean_Al       : num [1:3] 1157 1922 2130
 $ sd_Al         : num [1:3] 2243 3594 4059
 $ mean_leaf area: num [1:3] 218 217 180
 $ sd_leaf area  : num [1:3] 74.5 75.6 121.5
 $ mean_leaf mass: num [1:3] 3.57 3.01 2.36
 $ sd_leaf mass  : num [1:3] 1.89 1.33 1.93
 $ mean_SLA      : num [1:3] 67.6 78.4 89.3
 $ sd_SLA        : num [1:3] 18.6 24.1 27.3
 $ mean_N:P      : num [1:3] 21.5 20.6 23.5
 $ sd_N:P        : num [1:3] 6.09 5.35 12.51

Utilizando as funções do tidyr

O tidyr tem apenas 4 funções principais! Vamos entender elas AGORA!

Pivot_longer (antiga funcão gather())

A funçao pivot_longer() empilha os dados. Ela é útil para arranjar os dados de forma que algum conjunto de variáveis torne-se um fator. Alguns tipos de gráficos (como gráficos de barras e boxplots) utilizam essa estrutura. Também pode ser importante para fazer gráficos separados em facetas, sendo que cada faceta seria relacionada a um fator.

Logicamente, TUDO depende da sua pergunta e do que você quer demostrar!!!

Vamos usar pivot_longer() para juntar os nutrientes em uma única coluna.

nutri <- medias2 %>% select(-`leaf area`, -`leaf mass`, -SLA, -Al, -`N:P`) %>% pivot_longer(4:8, names_to = "Nutriente", values_to ="media") 
head(nutri)
# A tibble: 6 x 5
# Groups:   Species, Vegetation [2]
  Species Vegetation `Phenological group` Nutriente media
  <fct>   <fct>      <fct>                <chr>     <dbl>
1 AT      Grassland  Deciduous            N         1.79 
2 AT      Grassland  Deciduous            P         0.102
3 AT      Grassland  Deciduous            Mg        0.165
4 AT      Grassland  Deciduous            K         1.72 
5 AT      Grassland  Deciduous            Ca        0.623
6 AT      Forest     Deciduous            N         2.15 
boxplot(media~Nutriente, data=nutri)

Pivot_wider (antiga função spread())

A função pivot_wider faz exatamente o oposto da função pivot_longer. Ela espalha os dados, tornando fatores novas variáveis.

Vamos usar o pivot_wider para criar variáveis com os diferentes grupos fenológicos

grupos <- nutri %>% 
  pivot_wider(names_from=Vegetation, values_from = media)

head(grupos)
# A tibble: 6 x 6
# Groups:   Species [2]
  Species `Phenological group` Nutriente Grassland Forest Savanna
  <fct>   <fct>                <chr>         <dbl>  <dbl>   <dbl>
1 AT      Deciduous            N             1.79   2.15    2.28 
2 AT      Deciduous            P             0.102  0.117   0.129
3 AT      Deciduous            Mg            0.165  0.154   0.213
4 AT      Deciduous            K             1.72   1.00    1.24 
5 AT      Deciduous            Ca            0.623  0.368   0.736
6 BC      Semideciduous        N             1.05   1.30    1.41 

Unite

A função unite junta, como o próprio nome diz, duas ou mais colunas em uma só. Vamos juntar os fatores para criar uma variável de interação com grupo e tratamento, especificando um separador, no caso _ .

inter <- medias2 %>% unite("Interaction", `Phenological group`, Vegetation, sep= "_")
head(inter)
# A tibble: 6 x 12
# Groups:   Species [2]
  Species Interaction                 N      P    Mg     K    Ca    Al `leaf area`
  <fct>   <chr>                   <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl>       <dbl>
1 AT      Deciduous_Grassland      1.79 0.102  0.165 1.72  0.623 239.         238.
2 AT      Deciduous_Forest         2.15 0.117  0.154 1.00  0.368 194.         245.
3 AT      Deciduous_Savanna        2.28 0.129  0.213 1.24  0.736 174.         368.
4 BC      Semideciduous_Grassland  1.05 0.0476 0.108 0.656 0.404 131.         244.
5 BC      Semideciduous_Forest     1.30 0.0714 0.130 0.795 0.460  86.0        197.
6 BC      Semideciduous_Savanna    1.41 0.0690 0.176 0.843 0.708 232.         324.
# ... with 3 more variables: leaf mass <dbl>, SLA <dbl>, N:P <dbl>

Separate

A função separate faz o oposto da função unite, separando as colunas em 1 ou mais colunas. Vamos demostrar de algumas formas:

  1. Separando as variáveis que acabamos de juntar no exemplo anterior

  2. Separando as iniciais da variável espécie entre a inicial do gênero e a inicial do epípeto específico,

inter %>% separate(Interaction, into = c("Grupo", "Tipo"), sep = "_")
# A tibble: 44 x 13
# Groups:   Species [15]
   Species Grupo         Tipo          N      P    Mg     K    Ca    Al `leaf area`
   <fct>   <chr>         <chr>     <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl>       <dbl>
 1 AT      Deciduous     Grassland  1.79 0.102  0.165 1.72  0.623 239.        238. 
 2 AT      Deciduous     Forest     2.15 0.117  0.154 1.00  0.368 194.        245. 
 3 AT      Deciduous     Savanna    2.28 0.129  0.213 1.24  0.736 174.        368. 
 4 BC      Semideciduous Grassland  1.05 0.0476 0.108 0.656 0.404 131.        244. 
 5 BC      Semideciduous Forest     1.30 0.0714 0.130 0.795 0.460  86.0       197. 
 6 BC      Semideciduous Savanna    1.41 0.0690 0.176 0.843 0.708 232.        324. 
 7 BS      Semideciduous Grassland  1.25 0.0643 0.161 0.610 0.480 103.        125. 
 8 BS      Semideciduous Forest     1.30 0.0833 0.141 0.464 0.543  96.9       140. 
 9 BS      Semideciduous Savanna    1.28 0.0691 0.143 0.620 0.668 164.         50.1
10 CB      Semideciduous Grassland  1.46 0.0786 0.157 0.479 0.455 187.        394. 
# ... with 34 more rows, and 3 more variables: leaf mass <dbl>, SLA <dbl>,
#   N:P <dbl>
inter %>% separate(Species, into = c("Genero", "Epípeto"), sep = 1)
# A tibble: 44 x 13
   Genero Epípeto Interaction       N      P    Mg     K    Ca    Al `leaf area`
   <chr>  <chr>   <chr>         <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl>       <dbl>
 1 A      T       Deciduous_Gr~  1.79 0.102  0.165 1.72  0.623 239.        238. 
 2 A      T       Deciduous_Fo~  2.15 0.117  0.154 1.00  0.368 194.        245. 
 3 A      T       Deciduous_Sa~  2.28 0.129  0.213 1.24  0.736 174.        368. 
 4 B      C       Semideciduou~  1.05 0.0476 0.108 0.656 0.404 131.        244. 
 5 B      C       Semideciduou~  1.30 0.0714 0.130 0.795 0.460  86.0       197. 
 6 B      C       Semideciduou~  1.41 0.0690 0.176 0.843 0.708 232.        324. 
 7 B      S       Semideciduou~  1.25 0.0643 0.161 0.610 0.480 103.        125. 
 8 B      S       Semideciduou~  1.30 0.0833 0.141 0.464 0.543  96.9       140. 
 9 B      S       Semideciduou~  1.28 0.0691 0.143 0.620 0.668 164.         50.1
10 C      B       Semideciduou~  1.46 0.0786 0.157 0.479 0.455 187.        394. 
# ... with 34 more rows, and 3 more variables: leaf mass <dbl>, SLA <dbl>,
#   N:P <dbl>

Leitura complementar

FIM