Capítulo 2 (Básico da) Manipulação de data frames

Ainda que seja possivel criar um data frame entrando diretamente com os dados via linha de comando, é mais comum importamos tabelas a partir de arquivos .csv, .txt ou outros formatos. Ao importar estes tipos de arquivo, o R os lê como data.frames.

Inicialmente vamos introduzir métodos de preparação de uma nova seção em R e importação/exportação de tabelas.

2.1 Iniciando uma seção de trabalho

Seção no R, se refere ao ambiente em que ficam armazenados os objetos (vetores, matrizes, data frames, etc.) criados durante o processo de manipulação e análise de dados. Ao fechar uma seção do R (ex. ao sair do R Stúdio), esta pode ser salva guardando os objetos criados. O arquivo de uma seção é salvo com extensão .RData.

Ao abrir um novo script (com extensão .r) em um editor de texto é necessário definir o diretório em que iremos trabalhar. Este diretório de trabalho será o local de onde iremos importar dados, e para onde iremos salvar as figuras e tabelas criadas ao longo do trabalho. No R-Studio, um novo script pode ser aberto via menu Arquivo --> Novo script. Ao iniciar o R-Studio abre-se uma nova seção. O diretório desta seção pode ser verificado pelo comando:

getwd()

Crie uma pasta \(\texttt{IntroR}\) e direcione a seção de trabalho para esta pasta utilizando a função setwd("C:/seu_caminho/IntroR") e verifique se houve mudança com a função getwd()

setwd("C:/seu_caminho/IntroR")
getwd()
## [1] "C:/seu_caminho/IntroR"

A partir deste momento o R irá ler e salvar aquivos sempre neste diretório.

2.2 Importando arquivos .csv

Importe o conjunto dados dbenv.csv. Abra o arquivo em algum editor de texto e veja as características deste arquivo. Você verá por exemplo que ele é composto por 11 variáveis (colunas) mensuradas em 30 pontos (linhas). Este conjunto de dados pode ser obtido Aqui em formato .csv. Após fazer o download, você pode importar o conjunto de dados por:

dbenv <- read.csv(file = "C:/seu_caminho/IntroR/dbenv.csv", 
                 header = TRUE, dec = '.', sep = ',')

A função read.csv possui diferentes argumentos. A argumento header define se a primeira linha consiste do cabeçalho (TRUE) ou não (FALSE). O argumento dec define se o separador decimal consiste de vírgula ou ponto e o argumento sep informa sobre qual é o caracter separador de colunas utilizado no arquivo. No arquivo em questão as colunas são separadas por vírgulas. Outros tipos de separadores comuns são ponto-e-vírgula ou tabulações.

Veja os nomes das 11 variáveis (cabeçalho), a dimensão da tabela (número de linhas e colunas) e sua estrutura (um data.frame formado por 11 vetores numéricos).

dbenv
##     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
## 7   268 841 4.205  400 81  88   7  15   0 111  22
## 8   491 792 3.258  130 81  94  20  41  12  70  81
## 9   705 752 2.565  480 80  90  30  82  12  72  52
## 10  990 617 4.605 1000 77  82   6  75   1 100  43
## 11 1234 483 3.738 1990 81  96  30 160   0 115  27
## 12 1324 477 2.833 2000 79  86   4  50   0 122  30
## 13 1436 450 3.091 2110 81  98   6  52   0 124  24
## 14 1522 434 2.565 2120 83  98  27 123   0 123  38
## 15 1645 415 1.792 2300 86  86  40 100   0 117  21
## 16 1859 375 3.045 1610 80  88  20 200   5 103  27
## 17 1985 348 1.792 2430 80  92  20 250  20 102  46
## 18 2110 332 2.197 2500 80  90  50 220  20 103  28
## 19 2246 310 1.792 2590 81  84  60 220  15 106  33
## 20 2477 286 2.197 2680 80  86  30 300  30 103  28
## 21 2812 262 2.398 2720 79  85  20 220  10  90  41
## 22 2940 254 2.708 2790 81  88  20 162   7  91  48
## 23 3043 246 2.565 2880 81  97 260 350 115  63 164
## 24 3147 241 1.386 2976 80  99 140 250  60  52 123
## 25 3278 231 1.792 3870 79 100 422 620 180  41 167
## 26 3579 214 1.792 3910 79  94 143 300  30  62  89
## 27 3732 206 2.565 3960 81  90  58 300  26  72  63
## 28 3947 195 1.386 4320 83 100  74 400  30  81  45
## 29 4220 183 1.946 6770 78 110  45 162  10  90  42
## 30 4530 172 1.099 6900 82 109  65 160  10  82  44
colnames(dbenv)
##  [1] "dfs" "alt" "slo" "flo" "pH"  "har" "pho" "nit" "amm" "oxy" "bdo"
dim(dbenv)
## [1] 30 11

Observação: arquivos .txt podem ser lidos com a função read.table. Veremos a frente funções para leitura de outros formatos.

2.3 Seleção de linhas e colunas em data frames

No data frame que importamos as colunas têm nomes que podem ser acessados por:

colnames(dbenv)
##  [1] "dfs" "alt" "slo" "flo" "pH"  "har" "pho" "nit" "amm" "oxy" "bdo"

O nome das linhas podem ser acessados por:

rownames(dbenv)
##  [1] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9"  "10" "11" "12" "13" "14" "15"
## [16] "16" "17" "18" "19" "20" "21" "22" "23" "24" "25" "26" "27" "28" "29" "30"

Os números “entre aspas” significam que o R está lendo os nomes das linhas não como números, mas como caracteres.

Podemos utilizar colunas específicas deste por meio de seus nomes:

colunas <- c("dfs", "flo", "oxy")
dbenv[,colunas]
##     dfs  flo oxy
## 1     3   84 122
## 2    22  100 103
## 3   102  180 105
## 4   185  253 110
## 5   215  264  80
## 6   324  286 102
## 7   268  400 111
## 8   491  130  70
## 9   705  480  72
## 10  990 1000 100
## 11 1234 1990 115
## 12 1324 2000 122
## 13 1436 2110 124
## 14 1522 2120 123
## 15 1645 2300 117
## 16 1859 1610 103
## 17 1985 2430 102
## 18 2110 2500 103
## 19 2246 2590 106
## 20 2477 2680 103
## 21 2812 2720  90
## 22 2940 2790  91
## 23 3043 2880  63
## 24 3147 2976  52
## 25 3278 3870  41
## 26 3579 3910  62
## 27 3732 3960  72
## 28 3947 4320  81
## 29 4220 6770  90
## 30 4530 6900  82

Também podemos acessá-las pela sua posição:

colunas_num <- c(1, 3, 4)
dbenv[,colunas_num]
##     dfs   slo  flo
## 1     3 6.176   84
## 2    22 3.434  100
## 3   102 3.638  180
## 4   185 3.497  253
## 5   215 3.178  264
## 6   324 3.497  286
## 7   268 4.205  400
## 8   491 3.258  130
## 9   705 2.565  480
## 10  990 4.605 1000
## 11 1234 3.738 1990
## 12 1324 2.833 2000
## 13 1436 3.091 2110
## 14 1522 2.565 2120
## 15 1645 1.792 2300
## 16 1859 3.045 1610
## 17 1985 1.792 2430
## 18 2110 2.197 2500
## 19 2246 1.792 2590
## 20 2477 2.197 2680
## 21 2812 2.398 2720
## 22 2940 2.708 2790
## 23 3043 2.565 2880
## 24 3147 1.386 2976
## 25 3278 1.792 3870
## 26 3579 1.792 3910
## 27 3732 2.565 3960
## 28 3947 1.386 4320
## 29 4220 1.946 6770
## 30 4530 1.099 6900

O mesmo é válido para as linhas.

linhas <- c("3", "7", "9")
dbenv[linhas,]
##   dfs alt   slo flo pH har pho nit amm oxy bdo
## 3 102 914 3.638 180 83  52   5  22   5 105  35
## 7 268 841 4.205 400 81  88   7  15   0 111  22
## 9 705 752 2.565 480 80  90  30  82  12  72  52

Também podemos acessá-las pela sua posição:

linhas_num <- c(3, 7, 9)
dbenv[linhas_num,]
##   dfs alt   slo flo pH har pho nit amm oxy bdo
## 3 102 914 3.638 180 83  52   5  22   5 105  35
## 7 268 841 4.205 400 81  88   7  15   0 111  22
## 9 705 752 2.565 480 80  90  30  82  12  72  52

Finalmente, podemos combinar estes procedimentos para selecionar sub-conjunto de linhas e colunas.

dbenv[linhas,colunas]
##   dfs flo oxy
## 3 102 180 105
## 7 268 400 111
## 9 705 480  72

2.4 Adicionando novas colunas a um data frame

Este conjunto de dados mostra medidas físicas e químicas obtidas em um riacho seguindo do trecho alto de cabeceira seguindo para os trechos baixos próximos à foz. O ponto mais alto (934 m de altitude) está a 3 km da cabeceira enquanto o ponto mais baixo está a 172 m de altitude e a 4530 km da cabeceira. Vamos criar uma nova variável categorizando os trechos do rio em “Alto,” “Medio” e “Baixo” assumindo a seguinte relação:

  • 0 a 300 m: Baixo;
  • 300 a 600 m: Médio;
  • Acima de 600 m: Alto.
elv_cat <- cut(dbenv$alt, breaks = c(0, 300, 600, 1000), 
              labels = c("Baixo", "Medio", "Alto"))

A inserção do novo objeto elv_cat no data frame pode ser feito simplesmente por:

dbenv$trecho <- elv_cat

Assim, inserimos assim, uma nova coluna denominada trecho contendo uma variável categórica com três níveis.

head(dbenv)
##   dfs alt   slo flo pH har pho nit amm oxy bdo trecho
## 1   3 934 6.176  84 79  45   1  20   0 122  27   Alto
## 2  22 932 3.434 100 80  40   2  20  10 103  19   Alto
## 3 102 914 3.638 180 83  52   5  22   5 105  35   Alto
## 4 185 854 3.497 253 80  72  10  21   0 110  13   Alto
## 5 215 849 3.178 264 81  84  38  52  20  80  62   Alto
## 6 324 846 3.497 286 79  60  20  15   0 102  53   Alto

Poderíamos ter realizado exatamente o mesmo utilizando a função transform(). Vamos utilizá-la a seguir como exemplo, criando uma nova variável categórica a partir do oxigênio dissolvido, considerando 3 níveis: pobre (0 a 5), médio (5 a 8), saturado (> 8).

dbenv <- transform(dbenv,  
 saturacao = cut(dbenv$oxy, breaks = c(0, 40, 109, 124), 
           labels = c("Pobre", "Medio", "Saturado")))

Veja agora o data frame

dbenv
##     dfs alt   slo  flo pH har pho nit amm oxy bdo trecho saturacao
## 1     3 934 6.176   84 79  45   1  20   0 122  27   Alto  Saturado
## 2    22 932 3.434  100 80  40   2  20  10 103  19   Alto     Medio
## 3   102 914 3.638  180 83  52   5  22   5 105  35   Alto     Medio
## 4   185 854 3.497  253 80  72  10  21   0 110  13   Alto  Saturado
## 5   215 849 3.178  264 81  84  38  52  20  80  62   Alto     Medio
## 6   324 846 3.497  286 79  60  20  15   0 102  53   Alto     Medio
## 7   268 841 4.205  400 81  88   7  15   0 111  22   Alto  Saturado
## 8   491 792 3.258  130 81  94  20  41  12  70  81   Alto     Medio
## 9   705 752 2.565  480 80  90  30  82  12  72  52   Alto     Medio
## 10  990 617 4.605 1000 77  82   6  75   1 100  43   Alto     Medio
## 11 1234 483 3.738 1990 81  96  30 160   0 115  27  Medio  Saturado
## 12 1324 477 2.833 2000 79  86   4  50   0 122  30  Medio  Saturado
## 13 1436 450 3.091 2110 81  98   6  52   0 124  24  Medio  Saturado
## 14 1522 434 2.565 2120 83  98  27 123   0 123  38  Medio  Saturado
## 15 1645 415 1.792 2300 86  86  40 100   0 117  21  Medio  Saturado
## 16 1859 375 3.045 1610 80  88  20 200   5 103  27  Medio     Medio
## 17 1985 348 1.792 2430 80  92  20 250  20 102  46  Medio     Medio
## 18 2110 332 2.197 2500 80  90  50 220  20 103  28  Medio     Medio
## 19 2246 310 1.792 2590 81  84  60 220  15 106  33  Medio     Medio
## 20 2477 286 2.197 2680 80  86  30 300  30 103  28  Baixo     Medio
## 21 2812 262 2.398 2720 79  85  20 220  10  90  41  Baixo     Medio
## 22 2940 254 2.708 2790 81  88  20 162   7  91  48  Baixo     Medio
## 23 3043 246 2.565 2880 81  97 260 350 115  63 164  Baixo     Medio
## 24 3147 241 1.386 2976 80  99 140 250  60  52 123  Baixo     Medio
## 25 3278 231 1.792 3870 79 100 422 620 180  41 167  Baixo     Medio
## 26 3579 214 1.792 3910 79  94 143 300  30  62  89  Baixo     Medio
## 27 3732 206 2.565 3960 81  90  58 300  26  72  63  Baixo     Medio
## 28 3947 195 1.386 4320 83 100  74 400  30  81  45  Baixo     Medio
## 29 4220 183 1.946 6770 78 110  45 162  10  90  42  Baixo     Medio
## 30 4530 172 1.099 6900 82 109  65 160  10  82  44  Baixo     Medio

2.5 Aplicando uma função às linhas ou colunas de um data frame

2.5.1 Família de funções apply

Em muitas situações temos interesse aplicar um determinado cálculo a cada linha ou coluna de um data frame ou para grupos distintos.

Observação: o mesmo raciocínio servese aplica a objetos do tipo matrix.

Observe por exemplo se extraímos a média aritmética da coluna pH (\(\times\) 10).

mean(dbenv$pH)  # média aritmética
## [1] 80.5

Função tapply

Podemos estar interessados em extrair as médias para cada categoria de elevação. A função tapply() é útil nestas situações.

tapply(dbenv$pH, dbenv$trecho, mean)
##    Baixo    Medio     Alto 
## 80.27273 81.22222 80.10000

A função acima, pode ser lida do modo:

  • Selecione a coluna pH;
  • Agrupe os elementos em função dos níveis em trecho (Baixo, Medio, Alto);
  • Calcule a média aritmética para cada sub-grupo.

Note que o resultado foi um vetor em que cada elemento corresponde à média de um sub-grupo. Funções que retornam mais de um valor resultam em um objeto no formato de lista. A função range() por exemplo, retorna dois valores (mínimo e máximo). Ao utilizá-la junto à função tapply() termos como resultado uma lista composta por um vetor para cada subgrupo.

tapply(dbenv$pH, dbenv$trecho, range)
## $Baixo
## [1] 78 83
## 
## $Medio
## [1] 79 86
## 
## $Alto
## [1] 77 83

Função apply

Podemos aplicar uma determinada função a todas as linhas ou colunas de um data frame (ou matriz).

apply(dbenv[,1:5], MARGIN = 2, mean)
##         dfs         alt         slo         flo          pH 
## 1879.033333  481.500000    2.757733 2220.100000   80.500000

O argumento MARGIN = 2 diz que desejamos aplicar a função ás colunas da matriz. Com MARGIN = 1 aplicamos a função às linhas da matriz.

Função lapply

Se o objeto é do formato lista, o comando lapply() aplica uma função a cada elemento da lista. Considere a lista:

nossalista <- list(Ilha = c("Ilhabela", "Anchieta", "Cardoso"), 
                  Areaskm2 = c(347.5, 8.3, 131), 
                  Bioma = rep("Mata Atlantica",3),
                  Lat = c(23, 25, 23),
                  Long = c(45, 47, 45))

Veja os resultados dos comandos abaixo:

lapply(nossalista, sort)
## $Ilha
## [1] "Anchieta" "Cardoso"  "Ilhabela"
## 
## $Areaskm2
## [1]   8.3 131.0 347.5
## 
## $Bioma
## [1] "Mata Atlantica" "Mata Atlantica" "Mata Atlantica"
## 
## $Lat
## [1] 23 23 25
## 
## $Long
## [1] 45 45 47
lapply(nossalista, sort)
## $Ilha
## [1] "Anchieta" "Cardoso"  "Ilhabela"
## 
## $Areaskm2
## [1]   8.3 131.0 347.5
## 
## $Bioma
## [1] "Mata Atlantica" "Mata Atlantica" "Mata Atlantica"
## 
## $Lat
## [1] 23 23 25
## 
## $Long
## [1] 45 45 47

Obs.: Existem oitras funções neste grupo, Veja o help() destas funções pois são extremamente úteis na manipulação de data frames e listas.

?tapply
?apply
?lapply
?mapply
?replicate

2.5.2 Função aggregate

A função tapply() aplica uma função a subgrupos de uma única coluna. A função aggregate() faz o mesmo, porém para multiplas colunas agrupadas de acordo com uma ou mais categorias. O comando abaixo calcula os valores médios das variáveis para os trechos alto, médio e baixo combinmados com níveis acima e abaixo de pH = 80.

media.trecho <- aggregate(dbenv[, 1:11], 
                         by = list(TRECHO = dbenv$trecho,
                                   ALCALINO = dbenv$pH >= 80),
                         FUN = mean)
media.trecho
##   TRECHO ALCALINO      dfs      alt      slo       flo       pH      har
## 1  Baixo    FALSE 3472.250 222.5000 1.982000 4317.5000 78.75000 97.25000
## 2  Medio    FALSE 1324.000 477.0000 2.833000 2000.0000 79.00000 86.00000
## 3   Alto    FALSE  439.000 799.0000 4.759333  456.6667 78.33333 62.33333
## 4  Baixo     TRUE 3402.286 228.5714 1.986571 3786.5714 81.14286 95.57143
## 5  Medio     TRUE 1754.625 393.3750 2.501500 2206.2500 81.50000 91.50000
## 6   Alto     TRUE  284.000 847.7143 3.396429  258.1429 80.85714 74.28571
##         pho       nit        amm       oxy      bdo
## 1 157.50000 325.50000 57.5000000  70.75000 84.75000
## 2   4.00000  50.00000  0.0000000 122.00000 30.00000
## 3   9.00000  36.66667  0.3333333 108.00000 41.00000
## 4  92.42857 274.57143 39.7142857  77.71429 73.57143
## 5  31.62500 165.62500  7.5000000 111.62500 30.50000
## 6  16.00000  36.14286  8.4285714  93.00000 40.57143

2.6 Exportando um data frame

Finalmente, podemos exportar um resultado para arquivos texto. Vamos exportar o data frame media.trecho obtido acima para um arquivo .csv.

write.table(media.trecho, file = "Mediaportecho.csv", 
            sep = ",", dec = '.', row.names = FALSE, 
            col.names = TRUE)
  • Veja o help() sobre a função write.table para mais informações.
  • O arquivo será salvo em seu diretório de trabalho, aquele que você definiu no início desta seção com o comando setwd().