(Básico da) Manipulação de data frames

R
Programação
Manipulação de dados
Data frames
Princípios de manipulação de data frames no R: importação, seleção de linhas e colunas e criação de variáveis.

Embora seja possivel criar um data frame entrando com os dados diretamente via linha de comando, é mais eficiente importá-los a partir de arquivos texto (.csv, .txt).

1 Importando arquivos .csv

Um arquivo do tipo .csv pode ser lido com a função read.csv. Faça o download do conjunto de dados dbenv.csv disponível no repositório datasets e salve-o em sua pasta de trabalho (ex. "C:/seu_caminho/Introducao_R"). Ao abrir o arquivo em algum editor de texto verá que ele é composto por \(30\) linhas por \(11\) colunas.

Após fazer o download, você pode importar o conjunto de dados utilizando o comando:

dbenv <- read.csv(file = "C:/seu_caminho/Introducao_R/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.

Confira 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
NotaAcessando .csv em uma url

Como este arquivo está em um repositório na nuvem, poderia ser lido acessando diretamente sua url, sem a necessidade de fazer o download:

dbenv <- read.csv(file = "https://raw.githubusercontent.com/FCopf/datasets/refs/heads/main/dbenv.csv", 
                 header = TRUE, dec = '.', 
                 sep = ',')
NotaIniciando uma seção de trabalho

Uma 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 RStudio), 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 é importante definir o diretório de trabalho, que será o local onde ficarão dados e onde serão salvos os resultados do trabalho (ex. figuras, tabelas, etc.). No RStudio, 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()

Para criar uma pasta (ex. Introducao_R) e direcionar a seção de trabalho para esta pasta utiliza-se a função setwd():

setwd("C:/seu_caminho/Introducao_R")

A função getwd() pode ser utilizada para verificar se a alteração de diretório foi realizada

getwd()
C:/seu_caminho/Introducao_R

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

2 Manipulação de data frames

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

No data frame os nomes das colunas e linhas podem ser acessados por:

colnames(dbenv)
 [1] "dfs" "alt" "slo" "flo" "pH"  "har" "pho" "nit" "amm" "oxy" "bdo"
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 estão sendo lidos como caracteres.

Colunas específicas podem ser acessadas 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

Ou por suas posições:

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
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

Sub-conjunto do data frame podem ser selecionados combinando esses procedimentos.

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

2.2 Adicionando novas colunas

Este conjunto de dados mostra medidas físicas e químicas obtidas em um riacho amostrado desde a cabeceira até a 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

A nova coluna denominada trecho foi inserida no data frame, como pode ser visto:

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

O mesmo pode ser realizado com a função transform(). Vamos utilizá-la para criar uma nova variável categórica a partir do oxigênio dissolvido, considerando 3 níveis de satuação: Pobre (\(0\) a \(5\)), Médio (\(5\) a \(8\)) e Saturado (acima de \(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.3 Família apply e aggregate

Em muitas situações temos interesse aplicar uma determinada função a cada linha ou a cada coluna de um data frame ou ainda para grupos distintos de linhas.

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

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

O resultado é calculado para toda a coluna.

Função tapply

Podemos estar interessados no entanto, em extrair as médias separadamente para os trechos alto, médio e baixo do rio. 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
Nota

Existem outras 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

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 múltiplas 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 combinados com níveis de \(pH\).

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

3 Exportando um data frame

Finalmente, podemos exportar o data frame media.trecho obtido acima para um arquivo Mediaportecho.csv.

write.table(media.trecho, file = "C:/seu_caminho/Introducao_R/Mediaportecho.csv", 
            sep = ",", dec = '.', row.names = FALSE, 
            col.names = TRUE)