8  Manipulando

Perceba que estamos construindo uma sequência lógica de aprendizado. No Capítulo 4, nos familiarizamos um pouco melhor com comandos no R e o ambiente do RStudio. Nos Capítulo 5 e Capítulo 6, aprendemos os conceitos de objeto e função, respectivamente, utilizando a experiência adquirida no capítulo anterior para criá-los e armazená-los sem a desconfiança inicial de quem nunca teve contato com a linguagem. Por fim, no Capítulo 7 desenvolvemos a capacidade de importar dados de fontes externas ao R – sejam eles do mundo real ou apenas construídos pelo seu professor. Em resumo, você pode pensar que chegamos neste momento com um certo conhecimento e prática na linguagem, aptos então a aprender como modificar um objeto contendo dados.

“Como assim, modificar um objeto?” Significa adicionar, excluir ou alterar dados. De forma resumida, podemos

  1. substituir ou transformar (somando, multiplicando, etc.) determinado dado específico sem alterar o número de linhas e colunas da estrutura;

  2. adicionar ou remover determinado dado específico, alterando o número de linhas ou colunas da estrutura;

Neste capítulo, daremos ênfase a modificação de vetores e data.frames, abrangendo os pontos mencionados acima1.

8.1 Vetor

Lembre-se que um vetor é uma sequência de valores de mesmo tipo, podendo ser interpretado como uma coluna (vetor-coluna) ou como uma linha (vetor-linha). Portanto, se o combinarmos com mais uma coluna/linha, deixará de ser um vetor. Logo, nos concentraremos na substituição, transformação, adição e remoção de um dado específico. Vamos começar com um simples vetor c(4, 5, 6, 444), atirbuindo-o ao objeto de nome x.

x <- c(4, 5, 6, 444)
x
[1]   4   5   6 444

8.1.1 Substituindo e transformando

Se quisessemos apenas substituir o seu segundo elemento, como faríamos? Basta atribuir o novo valor que desejamos, através do operador <-, à segunda posição do vetor x! Lembre-se, do Capítulo 5, que para nos referimos ao enésimo elemento de um vetor, devemos escrever seu nome, seguido de colchetes, com a posição \(n\) desejada na parte interior.

x[2] <- 444
x
[1]   4 444   6 444

Podemos também substituir os valores de múltiplas posições, atribuindo um único valor. No exemplo abaixo, o valor 8 será atribuído às posições 1 e 32.

x[c(1, 3)] <- 8
x
[1]   8 444   8 444

Ou então substituir os valores de múltiplas posições, atribuindo múltiplos valores, de forma paralela. No exemplo abaixo, os valores ‘6’ e ‘12’ serão atribuídos às posições 1 e 3, respectivamente.

x[c(1, 3)] <- c(6, 12)
x
[1]   6 444  12 444

Ao invés de nos referirmos à posição do dado que queremos alterar, talvez seja mais útil utilizar seu valor propriamente dito, não é? Por exemplo, substituir todos os ‘444’ presentes por ‘9’. Esse procedimento pode ser feito indicando, dentro dos colchetes após o nome do vetor, que queremos nos relacionar com todos os seus elementos de valor igual a ‘444’.

x[x == 444] <- 9
x
[1]  6  9 12  9

E se quiséssemos substituir valores específicos que são diferentes? Aqui, teremos que nos valer do uso do operador %in%. No exemplo abaixo, iremos substituir todos os ‘4’ e ‘9’ por ‘0’.

x[x %in% c(4, 9)] <- 0
x
[1]  6  0 12  0

Além disso, podemos, por exemplo, ter o desejo de alterar o quarto elemento do vetor x através da soma, subtração, multiplicação ou divisão. Nesse caso, devemos realizar a operação sobre o valor atual da quarta posição do vetor e atribuir o resultado, através do operador <-, à essa mesma posição! Vamos multiplicá-lo por 2.

x[4] <- x[4] * 2
x
[1]  6  0 12  0

A lógica de atribuição é idêntica ao do primeiro exemplo, quando substituímos o elemento da segunda posição! Por fim, note que você pode combinar todos esses comandos. No exemplo abaixo, substiutímos os valores ‘6’ e 24’ pelo valor da terceira posição, dividido por 2, somado mais 9 e 32, respectivamente.

x[x %in% c(6, 12)] <- c((x[3] / 2) + 9, 32)
x
[1] 15  0 32  0

8.1.2 Adicionando e removendo

E se quiséssemos adicionar um quinto elemento a esse vetor? Basta atribuir o valor desejado à esta posição, como se estivesse substituindo ou alterando um elemento existente! O R irá automaticamente criar esse espaço.

x[5] <- 7
x
[1] 15  0 32  0  7

Por outro lado, para remover determinado valor via sua posição, escreva-a dentro dos colchetes precedida pelo sinal de - e atribua o resultado a objeto de mesmo nome.

x <- x[-5]
x
[1] 15  0 32  0

Você também pode remover elementos de um vetor que correspondam a determinados valores. Novamente, faremos uso do operador %in%. Dessa vez, também usaremos o operador de negação !.

x <- x[!(x %in% c(15, 32))]
x
[1] 0 0

8.2 Matriz

Vamos utilizar como base a matriz contendo os números de 1 a 9, disposta em 3 linhas e 3 colunas.

matrix <- matrix(c(1:9), ncol = 3)
matrix
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

8.2.1 Substituindo e transformando

Observe que agora temos uma estrutura de dados bidimensional. Isso significa que você acessar determinando valor através de sua posição, indicando a linha e a coluna em que está. Para substituir tal valor, podemos aplicar a mesma lógica que utilizamos com vetores. No exemplo abaixo, substituímos o número da posição {linha 2, coluna 2} por 1000.

matrix[2, 2] <- 1000
matrix
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2 1000    8
[3,]    3    6    9

Você também pode indicar múltiplas posições para fixar o novo valor. Nesse caso, é necessário inserir dois vetores dentro dos colchetes, represetando as linhas e colunas, respectivamente. O novo valor será atribuído a todas as combinações possíveis de posições geradas pelos vetores. Observe o exemplo abaixo. Nele, estamos substituindo os valores das posições {linha 1, coluna 2}, {linha 1, coluna 3}, {linha 2, coluna 2} e {linha 2, coluna 3} pelo número 500.

matrix[c(1,2), c(2,3)] <- 500
matrix
     [,1] [,2] [,3]
[1,]    1  500  500
[2,]    2  500  500
[3,]    3    6    9

No entanto, esse não é o único jeito de se referir a posição de um elemento de uma matriz. Você pode acessá-lo pensando na matriz como um vetor coluna! Em outras palavras, contabilize cada valor em sequência, partindo da esquerda, de cima para baixo. Nessa indexação imaginária, podemos novamente acessar as posições {linha 1, coluna 3} e {linha 2, coluna 3} através dos índices 7 e 8, respectivamente.

matrix[c(7, 8)] <- c(70, 80)
matrix
     [,1] [,2] [,3]
[1,]    1  500   70
[2,]    2  500   80
[3,]    3    6    9

Para nos referirmos à valores propriamente ditos, o procedimento é o mesmo de um vetor.

matrix[matrix == 3] <- 90
matrix
     [,1] [,2] [,3]
[1,]    1  500   70
[2,]    2  500   80
[3,]   90    6    9
matrix[matrix %in% c(1, 80)] <- 0
matrix
     [,1] [,2] [,3]
[1,]    0  500   70
[2,]    2  500    0
[3,]   90    6    9

Assim como o procedimento de alterar algum elemento específico.

matrix[2, 2] <- matrix[2, 2] * 2
matrix
     [,1] [,2] [,3]
[1,]    0  500   70
[2,]    2 1000    0
[3,]   90    6    9

8.2.2 Adicionando e removendo

E se quiséssemos adicionar um décimo elemento a essa matriz, na posição {linha 1, coluna 4}, seria possível? A resposta é não.

matrix[1, 4] <- 50
Error in `[<-`(`*tmp*`, 1, 4, value = 50): índice fora de limites

E se tratassemos a matriz como um vetor, como fizemos no início da subseção anterior, funcionaria? Nesse caso, até conseguiriamos atribuir o novo valor, porém a matriz seria realmente convertida em vetor!

matrix[10] <- 50
matrix
 [1]    0    2   90  500 1000    6   70    0    9   50

Na prática, para adicionar valores à uma matriz, devemos adicionar uma nova linha ou coluna, utilizando as funções rbind e cbind, respectivamente! É necessário respeitar sua forma retangular. “Mas e se não tivermos valores suficientes para preencher um linha ou coluna nova?” Você pode utilizar NA! No exemplo abaixo, adicionamos uma nova coluna a nossa matriz base.

matrix <- cbind(matrix, c(10, NA, NA))
matrix
     [,1] [,2] [,3] [,4]
[1,]    1    4    7   10
[2,]    2    5    8   NA
[3,]    3    6    9   NA

Por outro lado, para remover determinada linha ou coluna, escreva seu índice dentro dos colchetes precedido pelo sinal de -, separado por vírgula – lembrando que linhas são escritas antes e colunas depois da vírgula. No final, atribua o resultado a objeto de mesmo nome. Abaixo, removendo a coluna 1 da matriz.

matrix <- matrix[,-1]
matrix
     [,1] [,2] [,3]
[1,]    4    7   10
[2,]    5    8   NA
[3,]    6    9   NA

Agora, removendo a linha 2.

matrix <- matrix[-2,]
matrix
     [,1] [,2] [,3]
[1,]    4    7   10
[2,]    6    9   NA

8.3 Dataframe

Nessa seção, iremos manipular data.frames. Vamos recapitular a Tabela 7.1, que importamos no Capítulo 7.

estudantes <- read_csv("dados/estudantes.csv")
Rows: 5 Columns: 6
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Nome, comida.favorita, PlanoDeRefeição
dbl (3): matrícula, IDADE, peso

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
estudantes
# A tibble: 5 × 6
  matrícula Nome     comida.favorita PlanoDeRefeição IDADE  peso
      <dbl> <chr>    <chr>           <chr>           <dbl> <dbl>
1         1 Jorge    Acarajé         Regime             18    76
2         2 Laís     Macarrão        Livre              23    65
3         3 Matheus  Carne           Regime             22    70
4         4 Laura    Frango          Livre              21    68
5         5 Nathália Peixe           Regime             21    66

8.3.1 Sem pacotes externos

Muito do que vimos com relação à matrizes se aplica aos dataframes. Com exceção do exercício imaginário do dataframe como um vetor-coluna, as tarefas de substituição e alteração podem ser realizadas da mesma forma.

estudantes[2, 2] <- "Maurício"
estudantes
# A tibble: 5 × 6
  matrícula Nome     comida.favorita PlanoDeRefeição IDADE  peso
      <dbl> <chr>    <chr>           <chr>           <dbl> <dbl>
1         1 Jorge    Acarajé         Regime             18    76
2         2 Maurício Macarrão        Livre              23    65
3         3 Matheus  Carne           Regime             22    70
4         4 Laura    Frango          Livre              21    68
5         5 Nathália Peixe           Regime             21    66
estudantes[c(5,2), c(5,6)] <- list(c(25, 23), c(70,68))
estudantes
# A tibble: 5 × 6
  matrícula Nome     comida.favorita PlanoDeRefeição IDADE  peso
      <dbl> <chr>    <chr>           <chr>           <dbl> <dbl>
1         1 Jorge    Acarajé         Regime             18    76
2         2 Maurício Macarrão        Livre              23    68
3         3 Matheus  Carne           Regime             22    70
4         4 Laura    Frango          Livre              21    68
5         5 Nathália Peixe           Regime             25    70
estudantes[estudantes == "Carne"] <- "Carne Vermelha"
estudantes
# A tibble: 5 × 6
  matrícula Nome     comida.favorita PlanoDeRefeição IDADE  peso
      <dbl> <chr>    <chr>           <chr>           <dbl> <dbl>
1         1 Jorge    Acarajé         Regime             18    76
2         2 Maurício Macarrão        Livre              23    68
3         3 Matheus  Carne Vermelha  Regime             22    70
4         4 Laura    Frango          Livre              21    68
5         5 Nathália Peixe           Regime             25    70
estudantes$PlanoDeRefeição[estudantes$Nome %in% c("Jorge", "Maurício")] <- "Regime Forte" 
estudantes
# A tibble: 5 × 6
  matrícula Nome     comida.favorita PlanoDeRefeição IDADE  peso
      <dbl> <chr>    <chr>           <chr>           <dbl> <dbl>
1         1 Jorge    Acarajé         Regime Forte       18    76
2         2 Maurício Macarrão        Regime Forte       23    68
3         3 Matheus  Carne Vermelha  Regime             22    70
4         4 Laura    Frango          Livre              21    68
5         5 Nathália Peixe           Regime             25    70
estudantes[1, 5] <- estudantes[1, 5] * 2
estudantes
# A tibble: 5 × 6
  matrícula Nome     comida.favorita PlanoDeRefeição IDADE  peso
      <dbl> <chr>    <chr>           <chr>           <dbl> <dbl>
1         1 Jorge    Acarajé         Regime Forte       36    76
2         2 Maurício Macarrão        Regime Forte       23    68
3         3 Matheus  Carne Vermelha  Regime             22    70
4         4 Laura    Frango          Livre              21    68
5         5 Nathália Peixe           Regime             25    70

Para adicionar um novo valor, basta refenciar sua posição. Perceba que, caso não haja observações suficientes, o R automaticamente completará o restante com ´NA`.

estudantes[1, 7] <- 50
estudantes
# A tibble: 5 × 7
  matrícula Nome     comida.favorita PlanoDeRefeição IDADE  peso  ...7
      <dbl> <chr>    <chr>           <chr>           <dbl> <dbl> <dbl>
1         1 Jorge    Acarajé         Regime Forte       36    76    50
2         2 Maurício Macarrão        Regime Forte       23    68    NA
3         3 Matheus  Carne Vermelha  Regime             22    70    NA
4         4 Laura    Frango          Livre              21    68    NA
5         5 Nathália Peixe           Regime             25    70    NA

Para remover uma coluna, escreva seu índice entre os colchetes precedido do sinal de -. Para remover uma linha, realize o mesmo procedimento, apenas adicionando uma vírgula ao final.

estudantes <- estudantes[-7]
estudantes <- estudantes[-2,]

estudantes
# A tibble: 4 × 6
  matrícula Nome     comida.favorita PlanoDeRefeição IDADE  peso
      <dbl> <chr>    <chr>           <chr>           <dbl> <dbl>
1         1 Jorge    Acarajé         Regime Forte       36    76
2         3 Matheus  Carne Vermelha  Regime             22    70
3         4 Laura    Frango          Livre              21    68
4         5 Nathália Peixe           Regime             25    70

8.3.2 dplyr

A depender do nível de complexidade da tarefa que desejamos executar, as funções básicas não serão adequadas (seja por não existir uma função que faça aquele procedimento ou pela dificuldade de implementação/legibilidade do código). Nessa subseção, aprenderemos três funções do pacote dplyr que serão tornarão o processo de mainupalação mais rápido, fácil e legível.

Pipe!

Na maioria dos casos, iremos utilizar funções do pacote dplyr em sequência, isto é, utilizando as transformações anteriores como input para funções seguintes. Por esse motivo, se torna comum o uso do operador Pipe %>%. Não se assuste.

Vamos retornar com o dataframe estudantes inicial. Não iremos salvar os resultados para facilitar a demonstração – mas lembre-se, caso você queira que seu dataframe permenaça com as modificações, é necessário atribuí-lo à novo objeto (ou a um objeto com mesmo nome do antigo, substiutindo-o na memória).

Rows: 5 Columns: 6
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Nome, comida.favorita, PlanoDeRefeição
dbl (3): matrícula, IDADE, peso

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

select

Imagine que você queira selecionar apenas as colunas “Nome”, “IDADE” e “Peso”. Para executar essa tarefa, podemos utilizar a função select.

estudantes %>% 
    select(Nome, IDADE, peso)
# A tibble: 5 × 3
  Nome     IDADE  peso
  <chr>    <dbl> <dbl>
1 Jorge       18    76
2 Laís        23    65
3 Matheus     22    70
4 Laura       21    68
5 Nathália    21    66

mutate

Agora, imagine que você deseja alterar a coluna ‘peso’, somando mais 2 para cada observação. Você pode utilizar a função mutate.

estudantes %>% 
  mutate(peso = peso + 2)
# A tibble: 5 × 6
  matrícula Nome     comida.favorita PlanoDeRefeição IDADE  peso
      <dbl> <chr>    <chr>           <chr>           <dbl> <dbl>
1         1 Jorge    Acarajé         Regime             18    78
2         2 Laís     Macarrão        Livre              23    67
3         3 Matheus  Carne           Regime             22    72
4         4 Laura    Frango          Livre              21    70
5         5 Nathália Peixe           Regime             21    68

filter

Por fim, vamos supor que você queira filtrar somente as pessoas maiores de 20 anos. Para essa tarefa, podemos utilizar a função filter.

estudantes %>% 
  filter(IDADE > 20)
# A tibble: 4 × 6
  matrícula Nome     comida.favorita PlanoDeRefeição IDADE  peso
      <dbl> <chr>    <chr>           <chr>           <dbl> <dbl>
1         2 Laís     Macarrão        Livre              23    65
2         3 Matheus  Carne           Regime             22    70
3         4 Laura    Frango          Livre              21    68
4         5 Nathália Peixe           Regime             21    66
Utilizando as funções de forma conjunta!

Se resolvermos utilizar todas essas funções ao mesmo tempo, teremos:

estudantes %>% 
  select(Nome, IDADE, peso) %>%
  mutate(peso = peso + 2) %>% 
  filter(IDADE > 20)
# A tibble: 4 × 3
  Nome     IDADE  peso
  <chr>    <dbl> <dbl>
1 Laís        23    67
2 Matheus     22    72
3 Laura       21    70
4 Nathália    21    68

  1. Não iremos, no entanto, abordar a geração de diferentes representações de uma mesma tabela de dados. Todas as tabelas que você receber estarão organizadas de forma apropriada para a execução da tarefa. De qualquer modo, caso tenha interesse em entender melhor este processo e como fazê-lo, veja o Capítulo 5 do livro R for Data Science.↩︎

  2. Note que c(1, 3), no interior dos colchetes, também é um vetor. Esse vetor não é armazenado na memória e, nesse contexto, serve para indicar as posições que desejamos substituir.↩︎