---
title: "Manipulação de dados"
subtitle: "Aula 2"
author: "Bruno Montezano"
institute: "Grupo Alliance<br>Programa de Pós-Graduação em Psiquiatria e Ciências do Comportamento<br>Universidade Federal do Rio Grande do Sul"
date: last-modified
date-format: long
lang: pt-br
execute:
  echo: true
format:
  revealjs:
    incremental: true
    smaller: true
    theme: [default, ../assets/custom.scss]
    logo: "../assets/logo_ufrgs.png"
---

## Conteúdo de hoje

- Importação de dados
- Valores ausentes
- Fatores
- Manipulação de dados
  - Selecionar colunas
  - Criar e modificar colunas
  - Filtragem de linhas
  - Ordenação de linhas
- Sumarização de dados
  - Agrupar e resumir dados
  
## `tidyverse`

![](../assets/logo_tidyverse.png){fig-align="center" width=45%}

## O que é o `tidyverse`?

O `tidyverse` é uma coleção de pacotes de R desenvolvidos para ciência de dados.

. . .

No curso, vamos usar alguns pacotes do `tidyverse`, como:

- `readr`, `readxl` e `haven`: importação de dados
- `dplyr`: manipulação de dados
- `ggplot2`: visualização de dados

. . .

Para instalar o conjunto de pacotes:

```{r instalar-tidyverse}
#| eval: false
install.packages("tidyverse")
```

## Importando e exportando dados com `readr`

![](../assets/logo_readr.png){fig-align="center" width=45%}

## Caminhos

Um passo essencial na importação de dados é saber onde está o arquivo a ser importado.

. . .

Toda função vai exigir um **caminho**, ou seja, uma **string** que representa
o endereço do arquivo no computador.

. . .

Há duas formas de passar o caminho ao R: através de um **caminho absoluto**
ou **caminho relativo**.

. . .

Antes, vamos entender o que é o **diretório de trabalho**.

## Diretório de trabalho

O diretório de trabalho (*working directory*) é a pasta na qual o R vai
buscar os arquivos ao lê-los ou salvá-los.

. . .

Podemos descobrir que pasta é essa através da função `getwd()`:

```{r getwd}
getwd()
```

A função retorna uma string com o caminho do seu diretório de trabalho.

. . .

O diretório de trabalho pode ser modificado através da função `setwd()`:

```{r setwd}
#| eval: false
setwd("/home/bruno/Documents/Projects/Thesis")
```

## Caminhos absolutos

Caminhos absolutos são aqueles que iniciam na pasta raíz do seu computador.

. . .

Este é o caminho absoluto onde os slides desta aula foram produzidos:

```
"/home/bruno/dox/projects/r-workshop/slides/2_manipulacao"
```

. . .

Em computadores com Windows pode ter uma cara parecida com esta:

```
"C:/Users/Bruno/Documents/Projects/Thesis"
```

. . .

Na maioria dos casos, caminhos absolutos são **má prática**, pois deixam
o código irreprodutível. Se você trocar de computador ou passar o script para
outra pessoa rodar, o código não vai funcionar, pois o caminho absoluto para o
arquivo muito provavelmente será diferente.

## Caminhos relativos

Caminhos relativos são aqueles que iniciam no diretório de trabalho da sua
sessão.

. . .

O diretório de trabalho da sessão usada para produzir os slides é a pasta
`r-workshop`. Olhem o caminho absoluto no slide anterior. Logo, o caminho
relativo para a pasta onde os slides foram produzidos seria apenas
`slides/2_manipulacao`.

. . .

Trabalhar com **projetos no RStudio** ajuda bastante o uso de caminhos
relativos, pois nos incentiva a colocar todos os arquivos da análise dentro da
pasta do projeto. Projetos podem ser criados em *Arquivo > Novo Projeto...*

. . .

Assim, se você usar apenas caminhos relativos e compartilhar a pasta do projeto
com alguém, todos os caminhos existentes nos códigos continuarão a funcionar em
qualquer computador!

## Arquivos de texto delimitados

Uma das formas mais comuns de armazenar dados é em um arquivo de texto delimitado,
como por exemplo: valores separados por vírgula (**.csv**) ou valores separados
por tabulação (**.tsv**).

:::: {.columns}

::: {.column width="50%"}
Aqui estão dados em **.csv**:

```
"id","diagnostico","sexo","idade"
001,"thb","masculino",34
002,"tdm","feminino",25
003,"tdm","masculino",19
004,"thb","feminino",31
005,"tdm","feminino",24
006,"thb","masculino",21
```
:::

::: {.column width="50%"}
E aqui estão dados em **.tsv**:

```
"id"	"diagnostico"	"sexo"	"idade"
001	"thb"	"masculino"	34
002	"tdm"	"feminino"	25
003	"tdm"	"masculino"	19
004	"thb"	"feminino"	31
005	"tdm"	"feminino"	24
006	"thb"	"masculino"	21
```

:::

::::

. . .

Ou poderíamos ter um arquivo em **.txt** separado por barras, por exemplo:

```
"id"/"diagnostico"/"sexo"/"idade"
001/"thb"/"masculino"/34
002/"tdm"/"feminino"/25
003/"tdm"/"masculino"/19
004/"thb"/"feminino"/31
005/"tdm"/"feminino"/24
006/"thb"/"masculino"/21
```


## `readr`


O pacote `readr` possui várias funções para carregar arquivos de texto delimitados:
`read_csv()`, `read_csv2()`, `read_tsv()` e `read_delim()`.

. . .

`readr` possui algumas vantagens:

- É mais rápido!
- Trabalha melhor com data e hora
- Barra de progresso para arquivos grandes

. . .

Também podemos exportar dados em `.csv`, por exemplo:

```{r exportar-csv}
#| eval: false
library(dados)
library(readr)

write_csv(
  x = pixar_bilheteria,
  file = "/home/bruno/tmp/dados_bilheteria.csv"
)
```

## `haven` e `readxl`

Na saúde, é comum trabalhar com dados provenientes de outros softwares.

. . .

Podemos usar algumas funções dos pacotes `haven` e `readxl` para lê-los:

- Arquivos do SPSS: `read_spss()` do pacote `haven`
- Arquivos do SAS: `read_sas()` do pacote `haven`
- Arquivos do Stata: `read_stata()` do pacote `haven`
- Arquivos do Excel: `read_xlsx()` do pacote `readxl`

. . .

Da mesma forma, podemos exportar dados em `.sav` (formato do SPSS):

```{r exportar-sav}
#| eval: false
library(dados)
library(haven)

write_sav(
  data = pixar_bilheteria,
  path = "/home/bruno/tmp/dados_bilheteria.sav"
)

```

## Pacote `dplyr`

![](../assets/logo_dplyr.png){fig-align="center" width=45%}

## `dplyr`

O pacote `dplyr` provê um conjunto de funções que nos ajudam nos problemas
mais comuns em manipulação de dados.

- `mutate()`: Adicionar ou modificar variáveis
- `select()`: Selecionar variáveis (colunas)
- `filter()`: Selecionar observações (linhas)
- `summarise()`: Reduzir múltiplos valores a um único resumo
- `arrange()`: Reordenar as observações (linhas)

. . .

O `dplyr` possibilita o uso da função `group_by()` para performar as operações
de forma agrupada.

. . .

Vamos ver cada uma destas funções separadamente.

## Mas antes, *pipes* (`|>`)

A maior parte das funções do `tidyverse` são construídas com o uso do
**pipe** (`|>`) em mente.

. . .

Os atalhos para inserir o pipe são:
`Ctrl + Shift + M` ou `⌘ + Shift + M`.

. . .

Os pipes pegam o objeto da *esquerda* e aplicam a função da *direita*.
Lemos como: "e então...".

```{r exemplo-pipe}
x <- c(2, 7, 40, 11, 21)

sqrt(sum(x)) # Somar valores do vetor x e tirar a raíz quadrada da soma

x |> sum() |> sqrt() # Mesmo cálculo, agora com pipe!
```

. . .

Os pipes nos poupam tempo de digitação, tornam o código legível e permitem o
encadeamento de funções como acima, por isso os usamos o tempo todo quando
manipulamos data frames.

## Usando pipe

Os pipes são mais legíveis quando temos cada função em uma nova linha.

. . .

```{r estrutura-pipe}
#| eval: false
pegue_estes_dados |> 
  aplicar_primeira_funcao(com = este_valor) |> 
  aplicar_proxima_funcao(usando = esse_valor) |> ...
```

. . .

O que estiver à esquerda do pipe (ou no exemplo, o que estiver acima) é repassado como
*primeiro argumento* da
função na direita (ou abaixo). Outros argumentos seguem à direita.

## Atribuindo valores ao usar pipe

Ao criar objetos provenientes da saída de funções encadeadas com pipe,
coloque o operador de atribuição (`<-`) no início.

```{r atribuir-com-pipe}
raiz_quadrada_da_soma <- x |> 
  sum() |> 
  sqrt()

raiz_quadrada_da_soma
```

. . .

Não importa o tamanho da cadeia de funções, eu recomendo que vocês realizem a
atribuição sempre no topo.

## Vamos colocar a mão na massa no `questionario`

`questionario` é uma base de dados disponibilizada no pacote `dados`.

```{r carregar-questionario}
# install.packages("dados")
library(dados)

questionario
```

Trata-se de uma base de dados do General Social Survey (GSS). Dados de
2000 a 2014.

## Valores ausentes

Valores ausentes ocorrem quando nenhum valor é armazenado para uma variável em uma
observação.

. . .

O R identifica os valores ausentes através do `NA`. Vamos entender as implicações
do `NA`.

. . .

```{r criar-vetor-com-missing-e-media}
vetor_com_missing <- c(25, NA, 13, 44, 12, NA)

mean(vetor_com_missing)
```

. . .

No entanto, existem maneiras de aplicar funções em vetores (ou colunas) com
`NA`s.

```{r media-com-narm}
mean(vetor_com_missing, na.rm = TRUE)
```

. . .

```{r media-narm-na-mao}
mean(vetor_com_missing[!is.na(vetor_com_missing)])
```

## Fatores

**Fatores** são uma classe de dados para categorizar dados e armazenar como **níveis**.

. . .

Variáveis como sexo e diagnóstico psiquiátrico seriam bons exemplos
de fatores.

. . .

```{r vetor-com-fator}
sexo <- factor(c("Masculino", "Feminino", "Feminino", "Masculino", "Masculino"))

sexo
```

```{r printar-questionario}
questionario
```

## Filtrando linhas com `filter()`

Podemos usar a função `filter()` para filtrar as observações da base de dados.

. . .

::: {style="font-size: 0.68em"}
:::: {.columns}

::: {.column width="50%"}
```{r filtrar-divorciado}
library(dplyr)

divorciados <- questionario |> 
  filter(estado_civil == "Divorciado(a)")

divorciados
```
:::

::: {.column width="50%"}
```{r divorciados-sem-missing-horas-tv}
divorciados |> 
  filter(!is.na(horas_tv))
```
:::

::::
:::

. . .

No segundo exemplo, `!is.na(horas_tv)` mantém na base de dados apenas as
observações dos divorciados que **não** possuem valores ausentes na coluna
`horas_tv`.


## Ordenando linhas com `arrange()`

Com a função `arrange()`, nós podemos reordenar as observações da base de dados.

. . .

```{r reordenar-questionario}
questionario |> 
  arrange(ano, desc(idade))
```

. . .

Os dados foram ordenados pelo `ano` de forma ascendente e `idade`
de forma descendente.

## Selecionando colunas com `select()`

Não apenas podemos limitar as linhas, mas podemos incluir colunas específicas (e
colocá-las na ordem listada) usando `select()`.

. . .

```{r selecionar-variaveis-divorciados}
divorciados |> 
  select(ano, idade, horas_tv)
```

## Removendo colunas com `select()`

Ao invés de selecionar, podemos remover colunas específicas com `select()` usando `-`.

```{r removendo-com-select}
divorciados |> 
  select(-estado_civil, -renda, -denominacao)
```

## Funções auxiliares para o `select()`

`select()` tem uma série de funções auxiliares como `starts_with()`, `ends_with()`,
e `contains()`, ou pode ser dada uma gama de colunas em sequência `varinicial:varfinal`.

. . .



:::: {.columns}

::: {.column width="50%"}
```{r select-starts-with}
questionario |>
  select(ends_with("ao"))
```
:::

::: {.column width="50%"}
```{r select-sequencia}
questionario |> 
  select(ano:raca)
```
:::

::::

. . . 

`?select` para mais detalhes.

## Criando e modificando colunas com `mutate()`

No `dplyr`, nós podemos adicionar ou modificar colunas usando `mutate()`.

. . .

:::: {.columns}

::: {.column width="56%"}
```{r adicionar-colunas-mutate}
divorciados |> 
  filter(raca == "Branca") |> 
  select(ano, idade, horas_tv) |> 
  mutate(idade_em_decadas = idade / 10,
         horas_tv_em_minutos = horas_tv * 60)
```
:::

::: {.column width="44%"}
```{r modificar-colunas-mutate}
divorciados |> 
  filter(religiao == "Protestante") |> 
  select(ano, idade, horas_tv) |> 
  mutate(horas_tv = horas_tv * 60)
```
:::

::::

## Agregando dados com `summarise()`

`summarise()` pega suas colunas de dados e computa algo usando todas as linhas.

- Contar a quantidade de linhas
- Calcular a média ou mediana
- Computar a soma
- Obter um valor mínimo ou máximo

. . .

Ou seja, qualquer função que agregue *múltiplos valores* em um *único valor*
(por exemplo, `sd()`, `mean()` ou `max()`) podem ser usadas com o
`summarise()`.

## Exemplo com `summarise()`

Para os divorciados do ano de 2000, vamos captar o número de observações,
a média da idade, a mediana das horas de TV assistidas diariamente e
a amplitude de horas de TV assistidas por dia.

. . .

```{r exemplo-summarise}
divorciados |> 
  filter(ano == 2000) |> 
  summarise(n_observacoes = n(),
            media_idade = mean(idade, na.rm = TRUE),
            mediana_horas_tv = median(horas_tv, na.rm = TRUE),
            amplitude_horas_tv = max(horas_tv, na.rm = TRUE) - min(horas_tv, na.rm = TRUE))
```

. . .

Estas novas variáveis foram calculadas usando *todas as linhas* do conjunto de
dados `divorciados`.

## Evitando repetição com `summarise(across())`

Talvez vocês precisem calcular a média e o desvio padrão de um conjunto de
colunas. Com `across()`, coloquem as variáveis a serem calculadas primeiro (usando
`c()`) e coloque as funções a serem usadas em uma `list()`
depois.

. . .

```{r summarise-across}
divorciados |> 
  filter(ano == 2014) |> 
  summarise(across(c(idade, horas_tv),
                   list(media = \(x) mean(x, na.rm = TRUE),
                        desvio_padrao = \(x) sd(x, na.rm = TRUE))))
```

## Agrupando com `group_by()`

A função `group_by()` muda como as funções operam sobre os dados, em especial,
a `summarise()`.

. . .

Funções usadas após o `group_by()` são computadas dentro de cada grupo como
definido pelas variáveis dadas, em vez de sobre todas as linhas de uma só vez.

. . .

Normalmente, vamos agrupar por variáveis de valores:

- Inteiros
- Fatores
- Caracteres

. . .

E **não** por valores contínuos (números com vírgula).

## Exemplo de `group_by()`

Vamos supor que eu queira saber o número de religiões reportadas pelos
entrevistados, o número de observações (tamanho da amostra) e a média
de horas diárias assistidas de TV em cada ano, ou seja, *agrupado* pelo
ano.

. . .

```{r exemplo-group-by}
questionario |> 
  group_by(ano) |> 
  summarise(numero_de_religioes = n_distinct(religiao),
            n_observacoes = n(),
            media_horas_tv = mean(horas_tv, na.rm = TRUE))
```

## Tarefa de casa

- Escolha uma das bases de dados do pacote `dados` e utilize ao menos uma vez
as funções: `select()`, `mutate()`, `filter()`, `arrange()`, `summarise()` e
`group_by()`
  - As bases disponíveis podem ser acessadas no [site de referência do pacote](https://cienciadedatos.github.io/dados/reference/index.html)
  
- Nos dados `questionario` do pacote `dados`, crie um subconjunto apenas com
as observações do ano de 2014 e armazene em um objeto chamado `dados_2014`

- Dica de leitura: Capítulo 4 de *Data transformation* do livro
[*R for Data Science (segunda edição)*](https://r4ds.hadley.nz/data-transform.html)