50 Data Table
Este livro centra-se nos “verbos” (funções) do pacote dplyr e no operador pipe %>%
do pacote magrittr como método para limpar e agrupar dados, mas o pacote data.table oferece um método alternativo que você poderá incorporar em seu uso do R.
50.1 Introdução ao Data Table
Uma tabela de dados (data table) é uma estrutura de dados bidimensional como um data frame, que permite a realização de operações complexas de agrupamento. A sintaxe data.table é estruturada para que as operações possam ser realizadas em linhas, colunas e grupos.
A estrutura é DT[i, j, by], separada por 3 partes; os argumentos i, j e by. O argumento i permite filtrar linhas, o argumento j permite operar em colunas e o argumento by permite operar em colunas por grupos.
Esta página abordará os seguintes tópicos:
- Importação de dados e uso das funções
fread()
efwrite()
- Filtragem de linhas utilizando o argumento i
- Utilização das funções de ajuda
%like%
,%chin%
e%between%
- Seleção e operação com colunas utilizando o argumento j
- Operar por grupos utilizando o argumento by
- Adição de dados e atualização de data tables (tabelas de dados) utilizando
:=
50.2 Carregar pacotes e importar dados
Carregar pacotes
Utilizando a função p_load()
de pacman, carregamos (e instalamos, se necessário) os pacotes necessários para esta análise.
pacman::p_load(
rio, # para importar dados
data.table, # para agrupar e limpar dados
tidyverse, # permite o uso da função pipe (%>%) neste capítulo
here
)
Importar dados
Esta página vai explorar algumas das funções centrais do pacote data.table recorrendo à mesma linelist de casos utilizada ao longo do manual.
Importamos o conjunto de dados dos casos de uma epidemia simulada de Ébola. Se você quiser baixar os dados para seguir passo a passo, veja as instruções na página Baixar livro e dados. O conjunto de dados é importado utilizando a função import()
do pacote rio. Veja a página em Importar e exportar para várias formas de importação de dados. Em seguida, utilizamos data.table()
para converter o quadro de dados em um data table.
A função fread()
é utilizada para importar arquivos delimitados por caracteres, como arquivos .csv, diretamente para um formato de data table. Esta função, e sua contraparte fwrite()
, utilizada para escrever data.tables como arquivos delimitados, são opções muito rápidas e computacionalmente eficientes para grandes bancos de dados.
As primeiras 20 linhas da linelist
:
Comandos do R Base como dim()
que são utilizados para data frames também podem ser utilizados para data tables (tabelas de dados).
dim(linelist) #dispõe o número de linhas e colunas na tabela de dados
## [1] 5888 30
50.3 O argumento i: selecionando e filtrando linhas
Relembrando a estrutura DT[i, j, by], podemos filtrar linhas usando números de linha ou expressões lógicas. O argumento i é o primeiro; portanto, a sintaxe DT[i] ou DT[i,] pode ser usada.
O primeiro exemplo recupera as primeiras 5 linhas do data table, o segundo exemplo retorna casos com 18 anos ou mais, e o terceiro exemplo gera um subconjunto de casos com 18 anos ou mais, mas não diagnosticados no Hospital Central:
linelist[1:5] # retorna da 1ª à 5ª fileira
linelist[age >= 18] # subconjunto de casos com 18 anos ou mais
linelist[age >= 18 & hospital != "Central Hospital"] # conjunto de casos com idade igual ou superior a 18 anos, mas não diagnosticados no Hospital Central
O uso de .N no argumento i representa o número total de linhas no data table. Isto pode ser usado para criar subconjuntos com base nos números das linhas:
linelist[.N] # retorna a última linha
linelist[15:.N] # retorna da 15ª à última linha
Funções de ajuda para filtragem
Data tables (tabelas de dados) utilizam funções de auxílio que facilitam a filtragem linhas. A função %like%
é utilizada para corresponder a um padrão em uma coluna, %chin%
é utilizada para corresponder a um caractere específico, e a função %between%
é utilizada para corresponder a colunas numéricas dentro de uma faixa pré-especificada.
Nos exemplos a seguir, nós: * filtramos linhas em que a variável hospital contém “Hospital” * filtramos linhas em que o resultado é “Recover” ou “Death” * filtramos linhas em que a faixa etária (age) é 40-60 anos
linelist[hospital %like% "Hospital"] # filtrar linhas em que a variável hospital contém "Hospital"
linelist[outcome %chin% c("Recover", "Death")] # filtrar linhas em que o resultado (outcome) é "Recover" ou "Death"
linelist[age %between% c(40, 60)] # filtrar linhas em que a faixa etária (age) é de 40-60 anos
#%between% deve receber um vetor de comprimento 2, enquanto %chin% pode receber vetores de comprimento >= 1
50.4 O argumento j: seleção e cálculo nas colunas
Usando a estrutura DT[i, j, by], podemos selecionar colunas usando números ou nomes. O argumento j é o segundo; portanto, a sintaxe DT[, j] é usada. Para facilitar os cálculos no argumento j, a coluna é envolvida utilizando list()
ou .()
.
Seleção de colunas
O primeiro exemplo recupera a primeira, terceira e quinta colunas do data table, o segundo exemplo seleciona todas as colunas, exceto as colunas gender, age, wt_kg e ht_cm. O terceiro exemplo utiliza o envelope .()
para selecionar as colunas case_id e outcome.
Cálculo nas colunas
Combinando os argumentos i e j é possível filtrar linhas e calcular colunas. Usar .N no argumento j também representa o número total de linhas no data table e pode ser útil para retornar o número de linhas após a filtragem.
Nos exemplos a seguir, nós: * contamos o número de casos que permaneceram mais de 7 dias no hospital * calculamos a idade média dos casos que vieram a óbito no hospital militar * calculamos o desvio padrão, mediana, e média da idade dos casos que se recuperaram no hospital central
linelist[days_onset_hosp > 7 , .N]
## [1] 189
linelist[hospital %like% "Military" & outcome %chin% "Death", .(mean(age, na.rm = T))] #na.rm = T remove valores N/A
## V1
## 1: 15.9084
linelist[hospital == "Central Hospital" & outcome == "Recover",
.(mean_age = mean(age, na.rm = T),
median_age = median(age, na.rm = T),
sd_age = sd(age, na.rm = T))] # esta sintaxe não utiliza as funções de ajuda, mas funciona tão bem quanto
## mean_age median_age sd_age
## 1: 16.85185 14 12.93857
Lembre-se que usar o envelope .() no argumento j facilita o cálculo, retorna um data table e permite a nomeação de colunas.
50.5 The by argument: computing by groups
O argumento by é o terceiro argumento na estrutura DT[i, j, by]. Ele aceita tanto um vetor de caracteres quanto a sintaxe list()
ou .()
. A utilização da sintaxe .()
no argumento by permite renomear a coluna imediatamente.
Nos exemplos a seguir, nós: * agrupamos o número de casos por hospital * calculamos a altura média e o peso dos casos com 18 anos ou mais, de acordo com o sexo e desfecho (se eles se recuperaram ou vieram a óbito) * contamos o número de casos com tempo de internação > 7 dias, de acordo com o mês e o hospital em que foram admitidos
linelist[, .N, .(hospital)] # número de casos por hospital
## hospital N
## 1: Other 885
## 2: Missing 1469
## 3: St. Mark's Maternity Hospital (SMMH) 422
## 4: Port Hospital 1762
## 5: Military Hospital 896
## 6: Central Hospital 454
linelist[age > 18, .(mean_wt = mean(wt_kg, na.rm = T),
mean_ht = mean(ht_cm, na.rm = T)), .(gender, outcome)] #NAs representam as categorias em que os dados estão faltando
## gender outcome mean_wt mean_ht
## 1: m Recover 71.90227 178.1977
## 2: f Death 63.27273 159.9448
## 3: m Death 71.61770 175.4726
## 4: f <NA> 64.49375 162.7875
## 5: m <NA> 72.65505 176.9686
## 6: f Recover 62.86498 159.2996
## 7: <NA> Recover 67.21429 175.2143
## 8: <NA> Death 69.16667 170.7917
## 9: <NA> <NA> 70.25000 175.5000
linelist[days_onset_hosp > 7, .N, .(month = month(date_hospitalisation), hospital)]
## month hospital N
## 1: 5 Military Hospital 3
## 2: 6 Port Hospital 4
## 3: 7 Port Hospital 8
## 4: 8 St. Mark's Maternity Hospital (SMMH) 5
## 5: 8 Military Hospital 9
## 6: 8 Other 10
## 7: 8 Port Hospital 10
## 8: 9 Port Hospital 28
## 9: 9 Missing 27
## 10: 9 Central Hospital 10
## 11: 9 St. Mark's Maternity Hospital (SMMH) 6
## 12: 10 Missing 2
## 13: 10 Military Hospital 3
## 14: 3 Port Hospital 1
## 15: 4 Military Hospital 1
## 16: 5 Other 2
## 17: 5 Central Hospital 1
## 18: 5 Missing 1
## 19: 6 Missing 7
## 20: 6 St. Mark's Maternity Hospital (SMMH) 2
## 21: 6 Military Hospital 1
## 22: 7 Military Hospital 3
## 23: 7 Other 1
## 24: 7 Missing 2
## 25: 7 St. Mark's Maternity Hospital (SMMH) 1
## 26: 8 Central Hospital 2
## 27: 8 Missing 6
## 28: 9 Other 9
## 29: 9 Military Hospital 11
## 30: 10 Port Hospital 3
## 31: 10 Other 4
## 32: 10 St. Mark's Maternity Hospital (SMMH) 1
## 33: 10 Central Hospital 1
## 34: 11 Missing 2
## 35: 11 Port Hospital 1
## 36: 12 Port Hospital 1
## month hospital N
Data.table também permite expressões em serquência:
linelist[, .N, .(hospital)][order(-N)][1:3] #1º seleciona todos os casos por hospital, 2º ordena os casos em ordem decrescente, 3º seleciona um subconjunto dos 3 hospitais com o maior número de casos
## hospital N
## 1: Port Hospital 1762
## 2: Missing 1469
## 3: Military Hospital 896
Nestes exemplos, estamos seguindo a suposição de que uma linha no data table é igual a um novo caso, e assim podemos usar o .N para representar o número de linhas no data table. Outra função útil para representar o número de casos únicos é uniqueN()
, que retorna o número de valores únicos em uma determinada entrada. Como ilustrado aqui:
linelist[, .(uniqueN(gender))] # lembre que o envelope .() no argumento j retorna um data table
## V1
## 1: 3
A resposta é 3, pois os valores únicos na coluna de gênero são m, f e N/A. Compare com a função unique()
do R Base, que retorna todos os valores únicos em uma determinada entrada:
linelist[, .(unique(gender))]
## V1
## 1: m
## 2: f
## 3: <NA>
Para encontrar o número de casos únicos em um determinado mês, escrevemos o seguinte:
linelist[, .(uniqueN(case_id)), .(month = month(date_hospitalisation))]
## month V1
## 1: 5 62
## 2: 6 100
## 3: 7 198
## 4: 8 509
## 5: 9 1170
## 6: 10 1228
## 7: 11 813
## 8: 12 576
## 9: 1 434
## 10: 2 310
## 11: 3 290
## 12: 4 198
50.6 Adicionar e atualizar data tables (tabelas de dados)
O operador :=
é utilizado para adicionar ou atualizar dados em um data table. A adição de colunas pode ser feita das seguintes maneiras:
linelist[, adult := age >= 18] # adiciona uma coluna
linelist[, c("child", "wt_lbs") := .(age < 18, wt_kg*2.204)] #para adicionar múltiplas colunas é necessário usar as sintaxes c(""), list() ou .() syntax
linelist[, `:=` (bmi_in_range = (bmi > 16 & bmi < 40),
no_infector_source_data = is.na(infector) | is.na(source))] #Este método utiliza `:=` como um operador funcional
linelist[, adult := NULL] # deleta a coluna
Outras agregações complexas estão além do objetivo deste capítulo introdutório, mas a ideia é fornecer uma alternativa popular e viável ao dplyr para agrupamento e limpeza de dados. O pacote data.table é um grande pacote que permite um código limpo e legível.
50.7 Recursos
Aqui estão alguns recursos úteis para maiores informações: * https://cran.r-project.org/web/packages/data.table/vignettes/datatable-intro.html * https://github.com/Rdatatable/data.table * https://s3.amazonaws.com/assets.datacamp.com/img/blog/data+table+cheat+sheet.pdf * https://www.machinelearningplus.com/data-manipulation/datatable-in-r-complete-guide/ * https://www.datacamp.com/community/tutorials/data-table-r-tutorial
Você pode realizar qualquer função de resumo sobre dados agrupados; veja a Cheat Sheet para mais informações: https://s3.amazonaws.com/assets.datacamp.com/blog_assets/datatable_Cheat_Sheet_R.pdf