Aula 2
Grupo Alliance
Programa de Pós-Graduação em Psiquiatria e Ciências do Comportamento
Universidade Federal do Rio Grande do Sul
25 de abril de 2023
tidyverse
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 dadosdplyr
: manipulação de dadosggplot2
: visualização de dadosreadr
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.
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()
:
A função retorna uma string com o caminho do seu diretório de trabalho.
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 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!
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).
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
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:
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:
read_spss()
do pacote haven
read_sas()
do pacote haven
read_stata()
do pacote haven
read_xlsx()
do pacote readxl
dplyr
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áveisselect()
: Selecionar variáveis (colunas)filter()
: Selecionar observações (linhas)summarise()
: Reduzir múltiplos valores a um único resumoarrange()
: 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.
|>
)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…”.
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.
Os pipes são mais legíveis quando temos cada função em uma nova linha.
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.
Ao criar objetos provenientes da saída de funções encadeadas com pipe, coloque o operador de atribuição (<-
) no início.
Não importa o tamanho da cadeia de funções, eu recomendo que vocês realizem a atribuição sempre no topo.
questionario
questionario
é uma base de dados disponibilizada no pacote dados
.
# A tibble: 21,483 × 9
ano estado_civil idade raca renda partido religiao denominacao horas_tv
<int> <fct> <int> <fct> <fct> <fct> <fct> <fct> <int>
1 2000 Nunca casou 26 Branca US$ 8… Indepe… Protest… Batistas d… 12
2 2000 Divorciado(a) 48 Branca US$ 8… Não fo… Protest… Batista, n… NA
3 2000 Viúvo(a) 67 Branca Não s… Indepe… Protest… Sem denomi… 2
4 2000 Nunca casou 39 Branca Não s… Indepe… Cristã … Não se apl… 4
5 2000 Divorciado(a) 25 Branca Não s… Não fo… Nenhuma Não se apl… 1
6 2000 Casado(a) 25 Branca US$ 2… Fortem… Protest… Batistas d… NA
7 2000 Nunca casou 36 Branca US$ 2… Não fo… Cristã Não se apl… 3
8 2000 Divorciado(a) 44 Branca US$ 7… Indepe… Protest… Sínodo lut… NA
9 2000 Casado(a) 44 Branca US$ 2… Não fo… Protest… Outra 0
10 2000 Casado(a) 47 Branca US$ 2… Fortem… Protest… Batistas d… 3
# ℹ 21,473 more rows
Trata-se de uma base de dados do General Social Survey (GSS). Dados de 2000 a 2014.
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
.
No entanto, existem maneiras de aplicar funções em vetores (ou colunas) com NA
s.
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.
[1] Masculino Feminino Feminino Masculino Masculino
Levels: Feminino Masculino
# A tibble: 21,483 × 9
ano estado_civil idade raca renda partido religiao denominacao horas_tv
<int> <fct> <int> <fct> <fct> <fct> <fct> <fct> <int>
1 2000 Nunca casou 26 Branca US$ 8… Indepe… Protest… Batistas d… 12
2 2000 Divorciado(a) 48 Branca US$ 8… Não fo… Protest… Batista, n… NA
3 2000 Viúvo(a) 67 Branca Não s… Indepe… Protest… Sem denomi… 2
4 2000 Nunca casou 39 Branca Não s… Indepe… Cristã … Não se apl… 4
5 2000 Divorciado(a) 25 Branca Não s… Não fo… Nenhuma Não se apl… 1
6 2000 Casado(a) 25 Branca US$ 2… Fortem… Protest… Batistas d… NA
7 2000 Nunca casou 36 Branca US$ 2… Não fo… Cristã Não se apl… 3
8 2000 Divorciado(a) 44 Branca US$ 7… Indepe… Protest… Sínodo lut… NA
9 2000 Casado(a) 44 Branca US$ 2… Não fo… Protest… Outra 0
10 2000 Casado(a) 47 Branca US$ 2… Fortem… Protest… Batistas d… 3
# ℹ 21,473 more rows
filter()
Podemos usar a função filter()
para filtrar as observações da base de dados.
# A tibble: 3,383 × 9
ano estado_civil idade raca renda partido religiao denominacao horas_tv
<int> <fct> <int> <fct> <fct> <fct> <fct> <fct> <int>
1 2000 Divorciado(a) 48 Branca US$ 8… Não fo… Protest… Batista, n… NA
2 2000 Divorciado(a) 25 Branca Não s… Não fo… Nenhuma Não se apl… 1
3 2000 Divorciado(a) 44 Branca US$ 7… Indepe… Protest… Sínodo lut… NA
4 2000 Divorciado(a) 52 Branca US$ 2… Indepe… Nenhuma Não se apl… 1
5 2000 Divorciado(a) 72 Branca Não s… Fortem… Protest… Batistas d… 7
6 2000 Divorciado(a) 36 Negra US$ 1… Fortem… Nenhuma Não se apl… NA
7 2000 Divorciado(a) 39 Negra Não s… Indepe… Nenhuma Não se apl… NA
8 2000 Divorciado(a) 51 Branca US$ 2… Indepe… Protest… Batista, n… 2
9 2000 Divorciado(a) 45 Branca US$ 2… Indepe… Protest… Batistas d… 2
10 2000 Divorciado(a) 78 Branca Não s… Indepe… Protest… Batistas d… 4
# ℹ 3,373 more rows
# A tibble: 1,768 × 9
ano estado_civil idade raca renda partido religiao denominacao horas_tv
<int> <fct> <int> <fct> <fct> <fct> <fct> <fct> <int>
1 2000 Divorciado(a) 25 Branca Não s… Não fo… Nenhuma Não se apl… 1
2 2000 Divorciado(a) 52 Branca US$ 2… Indepe… Nenhuma Não se apl… 1
3 2000 Divorciado(a) 72 Branca Não s… Fortem… Protest… Batistas d… 7
4 2000 Divorciado(a) 51 Branca US$ 2… Indepe… Protest… Batista, n… 2
5 2000 Divorciado(a) 45 Branca US$ 2… Indepe… Protest… Batistas d… 2
6 2000 Divorciado(a) 78 Branca Não s… Indepe… Protest… Batistas d… 4
7 2000 Divorciado(a) 75 Branca Não s… Fortem… Protest… Associação… 7
8 2000 Divorciado(a) 46 Branca US$ 2… Não fo… Inter n… Não se apl… 2
9 2000 Divorciado(a) 39 Branca Se ne… Indepe… Nenhuma Não se apl… 0
10 2000 Divorciado(a) 56 Branca Se ne… Não fo… Judaísmo Não se apl… 3
# ℹ 1,758 more rows
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
.
arrange()
Com a função arrange()
, nós podemos reordenar as observações da base de dados.
# A tibble: 21,483 × 9
ano estado_civil idade raca renda partido religiao denominacao horas_tv
<int> <fct> <int> <fct> <fct> <fct> <fct> <fct> <int>
1 2000 Viúvo(a) 89 Branca Não s… Não fo… Protest… Outras lut… 4
2 2000 Viúvo(a) 89 Branca Não s… Indepe… Protest… Outras met… 3
3 2000 Nunca casou 89 Branca Não s… Indepe… Protest… Igreja lut… 2
4 2000 Viúvo(a) 89 Negra Não s… Indepe… Protest… Batista, n… 8
5 2000 Viúvo(a) 89 Branca Não s… Não fo… Protest… Evangélica… 3
6 2000 Divorciado(a) 89 Branca Não s… Não fo… Protest… Igreja met… 3
7 2000 Casado(a) 89 Branca Não s… Fortem… Protest… União pres… 5
8 2000 Viúvo(a) 89 Negra Não s… Não fo… Protest… Batista, n… 10
9 2000 Casado(a) 89 Negra Não s… Fortem… Protest… Convenção … 3
10 2000 Viúvo(a) 89 Negra Não s… Fortem… Protest… Outras bat… 8
# ℹ 21,473 more rows
Os dados foram ordenados pelo ano
de forma ascendente e idade
de forma descendente.
select()
Não apenas podemos limitar as linhas, mas podemos incluir colunas específicas (e colocá-las na ordem listada) usando select()
.
select()
Ao invés de selecionar, podemos remover colunas específicas com select()
usando -
.
# A tibble: 3,383 × 6
ano idade raca partido religiao horas_tv
<int> <int> <fct> <fct> <fct> <int>
1 2000 48 Branca Não fortemente repubicano Protestante NA
2 2000 25 Branca Não fortemente democrata Nenhuma 1
3 2000 44 Branca Independente, inclinação democrata Protestante NA
4 2000 52 Branca Independente, inclinação democrata Nenhuma 1
5 2000 72 Branca Fortemente democrata Protestante 7
6 2000 36 Negra Fortemente democrata Nenhuma NA
7 2000 39 Negra Independente Nenhuma NA
8 2000 51 Branca Independente Protestante 2
9 2000 45 Branca Independente, inclinação republicana Protestante 2
10 2000 78 Branca Independente, inclinação democrata Protestante 4
# ℹ 3,373 more rows
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
.
# A tibble: 21,483 × 2
religiao denominacao
<fct> <fct>
1 Protestante Batistas do sul
2 Protestante Batista, não sabe qual
3 Protestante Sem denominação
4 Cristã ortodoxa Não se aplica
5 Nenhuma Não se aplica
6 Protestante Batistas do sul
7 Cristã Não se aplica
8 Protestante Sínodo luterano
9 Protestante Outra
10 Protestante Batistas do sul
# ℹ 21,473 more rows
# A tibble: 21,483 × 4
ano estado_civil idade raca
<int> <fct> <int> <fct>
1 2000 Nunca casou 26 Branca
2 2000 Divorciado(a) 48 Branca
3 2000 Viúvo(a) 67 Branca
4 2000 Nunca casou 39 Branca
5 2000 Divorciado(a) 25 Branca
6 2000 Casado(a) 25 Branca
7 2000 Nunca casou 36 Branca
8 2000 Divorciado(a) 44 Branca
9 2000 Casado(a) 44 Branca
10 2000 Casado(a) 47 Branca
# ℹ 21,473 more rows
?select
para mais detalhes.
mutate()
No dplyr
, nós podemos adicionar ou modificar colunas usando mutate()
.
divorciados |>
filter(raca == "Branca") |>
select(ano, idade, horas_tv) |>
mutate(idade_em_decadas = idade / 10,
horas_tv_em_minutos = horas_tv * 60)
# A tibble: 2,676 × 5
ano idade horas_tv idade_em_decadas horas_tv_em_minutos
<int> <int> <int> <dbl> <dbl>
1 2000 48 NA 4.8 NA
2 2000 25 1 2.5 60
3 2000 44 NA 4.4 NA
4 2000 52 1 5.2 60
5 2000 72 7 7.2 420
6 2000 51 2 5.1 120
7 2000 45 2 4.5 120
8 2000 78 4 7.8 240
9 2000 61 NA 6.1 NA
10 2000 75 7 7.5 420
# ℹ 2,666 more rows
divorciados |>
filter(religiao == "Protestante") |>
select(ano, idade, horas_tv) |>
mutate(horas_tv = horas_tv * 60)
# A tibble: 1,792 × 3
ano idade horas_tv
<int> <int> <dbl>
1 2000 48 NA
2 2000 44 NA
3 2000 72 420
4 2000 51 120
5 2000 45 120
6 2000 78 240
7 2000 75 420
8 2000 62 NA
9 2000 40 NA
10 2000 56 120
# ℹ 1,782 more rows
summarise()
summarise()
pega suas colunas de dados e computa algo usando todas as linhas.
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()
.
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.
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))
# A tibble: 1 × 4
n_observacoes media_idade mediana_horas_tv amplitude_horas_tv
<int> <dbl> <dbl> <int>
1 441 48.6 2 15
Estas novas variáveis foram calculadas usando todas as linhas do conjunto de dados divorciados
.
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.
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:
E não por valores contínuos (números com vírgula).
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.
questionario |>
group_by(ano) |>
summarise(numero_de_religioes = n_distinct(religiao),
n_observacoes = n(),
media_horas_tv = mean(horas_tv, na.rm = TRUE))
# A tibble: 8 × 4
ano numero_de_religioes n_observacoes media_horas_tv
<int> <int> <int> <dbl>
1 2000 15 2817 2.97
2 2002 15 2765 2.98
3 2004 14 2812 2.87
4 2006 14 4510 2.94
5 2008 15 2023 2.98
6 2010 15 2044 3.03
7 2012 15 1974 3.09
8 2014 15 2538 2.98
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()
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)