4  Módulo 3 | Manipulação de dados

Autor

A. Peralta-Santos e J Dionisio

Data de Publicação

14 de outubro de 2024

4.1 Setup e limpar o ambiente

Esta parte garante que tem as configurações padrão para todos os blocos de código R.

Pode ser definido num chunk ou no YAML com o parâmetro execute.

rm(list = ls(all.names = TRUE)) 
# limpa todos os objetos, incluindo os ocultos
# boa política se houver objetos antigos não relevantes
# melhoria da performance

4.1.1 Definir seed

É importante definir a seed sempre que o R precisa realizar cálculos aleatórios, para que os resultados permaneçam constantes.

Exemplo: Bootstrapping e Inferência Bayesiana; Algoritmos de Machine Learning; Legendas móveis em gráficos;

set.seed(123)

4.1.2 Instalar e carregar bibliotecas

Sempre que se inicia uma nova sessão, as bibliotecas têm de ser carregadas.

# install.packages("tidyverse", repos = "http://cran.us.r-project.org")
# install.packages("readxl", repos = "http://cran.us.r-project.org")
# install.packages("lubridate", repos = "http://cran.us.r-project.org")
# install.packages("janitor")
# install.packages("data.table", repos = "http://cran.us.r-project.org")
# install.packages("here")
# install.packages("haven")
# install.packages("rio")
library(janitor)
library(tidyverse)
library(readxl)
library(lubridate)
library(data.table)
library(here)
library(haven)
library(rio)
# Forma alternativa de instalar vários pacotes e carregá-los

# Packages
required_packages <- c("janitor",
                       "tidyverse",
                       "rio",
                       "here",
                       "haven",
                       "data.table",
                       "lubridate",
                       "readxl"
                       )      

for (pkg in required_packages) {
  # install packages if not already present
  if (!pkg %in% rownames(installed.packages())) {
    install.packages(pkg)
  }
  
  # load packages to this current session 
  library(pkg, character.only = TRUE)
}
remove(required_packages)
remove(pkg)

4.2 IMPORTAÇÃO DE DADOS

4.2.1 Importar dados

Em cursos anteriores usávamos pacotes específicos de importação e exportação.

# Nome do novo conjunto de dados <- read_excel("caminho")
# Use um caminho genérico para garantir a reprodutibilidade

inpatient_hospital <- read_excel("datasets/atividade_internamento_hospitalar.xlsx")

Importar dados por cliques

Figura 4.1: Importar dados

Pode importar um dataset no RStudio Figura 4.1 através de cliques no painel “Files” é um processo intuitivo, especialmente para quem prefere uma abordagem mais visual em vez de escrever código manualmente. Os passos são os seguintes:

Passos para Importar um Dataset no RStudio Usando o Painel “Files”

  1. Painel “Files”: No canto inferior direito do RStudio, você encontrará várias abas, incluindo “Files”, “Plots”, “Packages”, etc. Clique na aba “Files”.

  2. Localizar o dataset: Navegue até a pasta onde o seu arquivo de dados está armazenado. Se você acabou de iniciar um projeto novo, pode ser necessário primeiro copiar ou mover o arquivo de dados para a pasta do projeto.

  3. Importar o Arquivo de Dados:

    • Clique no arquivo desejado para selecioná-lo.
    • Uma vez selecionado o arquivo, clique no botão “Import” que aparece no menu do painel. Para arquivos .csv, por exemplo, aparecerá uma opção “Import Dataset”.
  4. Configurar a Importação:

    • O RStudio abrirá um assistente de importação. Aqui pode visualizar os dados e definir várias opções de importação, como delimitadores, se a primeira linha contém os nomes das colunas, codificação, etc.
    • Ajuste essas configurações conforme necessário até que os dados sejam exibidos corretamente na pré-visualização.
  5. Executar e Salvar o Código de Importação:

    • Uma vez satisfeito com a pré-visualização, você pode clicar no botão “Import” no assistente. Isso não só importa os dados para o ambiente do RStudio, mas também gera código na consola mas não no script.
    • Tem copiar e colar esse código para o script R para utilizar e fazer render.

4.2.2 Pacote RIO

O pacote “rio” flexibilixa a importação e a exportação de dados.

Este pacote lida com múltiplos formatos:

  1. Excel

  2. GoogleSheets (colocar URL no lugar do ficheiro)

  3. CSV

  4. SAS

  5. SPSS

  6. STATA

  7. JSON

Lista Completa dos formatos suportados

Ver aqui https://cran.r-project.org/web/packages/rio/vignettes/rio.html

Exemplo do uso do pacote RIO num worflow de Data Science

Aviso

Relembrar: a referência dos ficheiros é o working directory que por default é o local do projeto R.

covid_inc <- import("datasets/covid_inc.csv")
hypoxia <- import("datasets/hypoxia.xlsx")

# é possível definir folhas de Excel com o argumento which
# é possível remover linhas supérfulas com o argumento skip
# é possível transformar valores em na na importação com o argumento na - Ex: na= c("na", "NA", "9","99",Missing", "", " ")

Importação avançada

Em algumas situações em que temos múltiplos ficheiros e queremos importar o mais recente podemos fazê-lo utilizando a função file.info() e list.files()

1ficheiros <- file.info(list.files("datasets", full.names = TRUE)) |>
2    rownames_to_column(var = "path")

ficheiro_recente <- ficheiros |> 
3  filter(mtime == max(mtime)) |>
4  pull(path)

5importar_recente <- import(ficheiro_recente)
1
Retirar os ficheiros da pasta datasets e dar a informação do mesmo
2
Passar os índices (caminhos dos ficheiros) para uam coluna chamada path
3
Filtra o ficheiro com o máximo da coluna mtime (data de modificação)
4
Retira o caminho do ficheiro para a variável ficheiro recente
5
O ficheiro é importado

4.3 MANIPULAÇÃO DADOS (DATA WRANGLING)

4.3.1 Limpeza de nomes de colunas (clean_names)

Ao trabalhar com R, a nomeação clara e consistente das colunas é crucial para garantir a facilidade de leitura, compreensão e manuseio dos dados. Isso é especialmente importante quando os nomes das colunas servem como referência para legendas de figuras ou para a manipulação de dados em scripts. Abaixo, você encontrará uma versão aprimorada do texto com boas práticas para nomear colunas em R:

1. Nomes curtos e concisos: Opte por nomes breves, e descritivos, que facilitem a compreensão do conteúdo da coluna. Nomes longos podem dificultar a leitura e a escrita do código.

2. Evitar espaços: Não use espaços nos nomes das colunas. Espaços podem levar a erros de sintaxe e complicam o acesso aos dados. Utilize underlines (_) ou camelCase para separar palavras (por exemplo, idadeMeses).

3. Minimizar o uso de letras maiúsculas: Como o R é sensível a maiúsculas e minúsculas, prefira nomes de colunas em minúsculas para evitar confusões e erros decorrentes de inconsistências no uso de maiúsculas/minúsculas.

4. Evitar caracteres especiais: Não inclua caracteres como &, #, <, >.

5. Consistência entre colunas: Mantenha um padrão na nomeação de colunas semelhantes. Por exemplo, se estiver usando prefixos ou sufixos em nomes de colunas relacionadas a datas, aplique essa convenção de maneira consistente em todo o conjunto de dados (por exemplo, dataInicio, dataFim).

# Vamos inspecionar o conjunto de dados
head(inpatient_hospital)
# A tibble: 6 × 7
  Período Região       Instituição Localização Geográfi…¹ Tipo de Especialidad…²
  <chr>   <chr>        <chr>       <chr>                  <chr>                 
1 2015-01 Região de S… Unidade Lo… 38.014123, -7.8721227  Especialidade Cirurgi…
2 2015-01 Região de S… Centro Hos… 40.2804158, -7.4922407 Especialidade Cirurgi…
3 2015-01 Região de S… Centro Hos… 40.6362453, -8.6543716 Especialidade Cirurgi…
4 2015-01 Região de S… Instituto … 40.2162514, -8.4103814 Especialidade Cirurgi…
5 2015-01 Região de S… Unidade Lo… 40.5309916, -7.2734793 Especialidade Cirurgi…
6 2015-01 Região de S… Centro Hos… 38.5283754, -8.8818638 Especialidade Cirurgi…
# ℹ abbreviated names: ¹​`Localização Geográfica`, ²​`Tipo de Especialidade`
# ℹ 2 more variables: `Doentes Saídos` <dbl>, `Dias de Internamento` <dbl>
# Como saber nomes das colunas
names(inpatient_hospital) # mais genérico
[1] "Período"                "Região"                 "Instituição"           
[4] "Localização Geográfica" "Tipo de Especialidade"  "Doentes Saídos"        
[7] "Dias de Internamento"  
# Limpar nomes
# Este comando garante que todos os nomes das variáveis estão em minúsculas e sem espaços
inpatient_hospital <- clean_names(inpatient_hospital)

covid_inc_limp <- clean_names(covid_inc)

colnames(inpatient_hospital) # ver nomes alterados
[1] "periodo"                "regiao"                 "instituicao"           
[4] "localizacao_geografica" "tipo_de_especialidade"  "doentes_saidos"        
[7] "dias_de_internamento"  

4.3.2 Alterar nomes colunas (rename)

Esta função permite renomear variáveis

Aviso

A Sintaxe desta função deve ser novo_nome = nome_anterior. A variável nome_anterior deve existir nos dados senão temos um erro

hypoxia_clean <- hypoxia |> 
  clean_names() |> 
  rename(
    sex = female
  )

Renomeámos a variável female para a mais comum sex.

4.3.3 Selecionar variaveis (Select)

Este argumento permite selecionar variáveis; temos 7 variáveis em nosso conjunto de dados. Vamos verificar se precisamos de todas elas Figura 4.2.

Figura 4.2: Esquema de uso do Select
# 1. Nome do conjunto de dados final
# 2. Nome do conjunto de dados original
# 3. Pipe %>%  ou |> (ambos funcionam)
# 4. Argumento, neste caso, é select

inpatient_hospital_lite <- inpatient_hospital |> 
  select(
    periodo, 
    instituicao, 
    tipo_de_especialidade,
    doentes_saidos,
    dias_de_internamento
  ) 

test <- inpatient_hospital |> 
  select(periodo, instituicao)
# Também podemos não selecionar algumas variáveis
# PASSOS:
# 1. Crie um vetor com as variáveis alvo
# 2. use o argumento lógico ! ou para excluir as variáveis alvo

target <- c("regiao", "localizacao_geografica")

inpatient_hospital_exclude <- inpatient_hospital |> 
  select(
    !all_of(target)
  )

# a mesma versão pode ser efetuada com o operador -
inpatient_hospital_exclude1 <- inpatient_hospital |> 
  select(
    -regiao,
    -localizacao_geografica,
    -dias_de_internamento
  )

4.3.4 Filtrar conteúdo (Filter)

Este argumento permite filtrar valores ou strings dentro das variáveis, ver Figura 4.3.

Figura 4.3: Esquema de uso do filtro
# 1. Nome do conjunto de dados final
# 2. Nome do conjunto de dados original
# 3. pipe %>%  ou | >
# 4. argumento, neste caso, é filter
# 5. use um argumento lógico <, >, <=, ==

inpatient_hospital_less_1000 <- inpatient_hospital_lite  |> 
  filter(dias_de_internamento <= 1000)

# Vamos inspecionar o conjunto de dados
view(inpatient_hospital_less_1000)

# Podemos usar filter para strings
inpatient_hospital_surgery <- inpatient_hospital_lite |>
  filter(tipo_de_especialidade == "Especialidade Cirurgica")

inpatient_hospital_medicine <- inpatient_hospital_lite |>
  filter(tipo_de_especialidade == "Especialidade Médica")
  
# Também podemos combinar vários filtros com argumentos lógicos & (e), | (ou)
# Podemos usar filter para strings
inpatient_hospital_surgery_less_500 <- inpatient_hospital_lite |>
  filter(tipo_de_especialidade=="Especialidade Cirurgica" & 
           dias_de_internamento<=500)

head(inpatient_hospital_less_1000)
# A tibble: 6 × 5
  periodo instituicao  tipo_de_especialidade doentes_saidos dias_de_internamento
  <chr>   <chr>        <chr>                          <dbl>                <dbl>
1 2015-01 Hospital Sa… Especialidade Cirurg…            149                  827
2 2015-02 Hospital Dr… Especialidade Cirurg…             80                  304
3 2015-04 Hospital Dr… Especialidade Cirurg…            167                  686
4 2016-02 Hospital Dr… Especialidade Cirurg…             80                  335
5 2016-03 Hospital Dr… Especialidade Cirurg…            125                  509
6 2018-01 Unidade Loc… Especialidade Cirurg…            189                  926

4.3.5 Criar variável (Mutate)

O mutate() é uma função usada para transformar ou adicionar novas colunas a um conjunto de dados (data frame ou tibble), ver Figura 4.4.

Figura 4.4: Esquema de utilização do Mutate
# 1. Nome do conjunto de dados final
# 2. Nome do conjunto de dados original
# 3. pipe %>% ou |>
# 4. argumento, neste caso, é mutate
# 5. especifique o nome da nova variável
# 6. adicione a função

inpatient_hospital_lite <- inpatient_hospital_lite |>
  mutate(
    length_patient =
      round((dias_de_internamento/doentes_saidos), digits = 1)
    )

# Vamos inspecionar o conjunto de dados
head(inpatient_hospital_lite)
# A tibble: 6 × 6
  periodo instituicao  tipo_de_especialidade doentes_saidos dias_de_internamento
  <chr>   <chr>        <chr>                          <dbl>                <dbl>
1 2015-01 Unidade Loc… Especialidade Cirurg…            360                 2026
2 2015-01 Centro Hosp… Especialidade Cirurg…            352                 2626
3 2015-01 Centro Hosp… Especialidade Cirurg…            651                 3958
4 2015-01 Instituto P… Especialidade Cirurg…            330                 2183
5 2015-01 Unidade Loc… Especialidade Cirurg…            329                 2640
6 2015-01 Centro Hosp… Especialidade Cirurg…            525                 3442
# ℹ 1 more variable: length_patient <dbl>
# Também podemos criar uma nova variável com valores fixos

inpatient_hospital_lite <- inpatient_hospital_lite |>
  mutate(
    new_var = 2,
    fonte = "transparencia_sns",
    multiplicacao = dias_de_internamento*doentes_saidos
  )

# Vamos inspecionar o conjunto de dados
head(inpatient_hospital_lite)
# A tibble: 6 × 9
  periodo instituicao  tipo_de_especialidade doentes_saidos dias_de_internamento
  <chr>   <chr>        <chr>                          <dbl>                <dbl>
1 2015-01 Unidade Loc… Especialidade Cirurg…            360                 2026
2 2015-01 Centro Hosp… Especialidade Cirurg…            352                 2626
3 2015-01 Centro Hosp… Especialidade Cirurg…            651                 3958
4 2015-01 Instituto P… Especialidade Cirurg…            330                 2183
5 2015-01 Unidade Loc… Especialidade Cirurg…            329                 2640
6 2015-01 Centro Hosp… Especialidade Cirurg…            525                 3442
# ℹ 4 more variables: length_patient <dbl>, new_var <dbl>, fonte <chr>,
#   multiplicacao <dbl>

4.3.6 Medidas sumário (summarise)

Agregação de Dados: summarise() é usada para aplicar funções de agregação a colunas de um dataset, resulta num novo conjunto de dados com um resumo estatístico. As funções comuns incluem mean(), sum(), min(), max(), median(), sd() (desvio padrão), e muitas outras.

Uso com group_by(): Frequentemente, summarise() é usada em conjunto com group_by(), o que permite calcular resumos agrupados por uma ou mais variáveis. Por exemplo, calcular a média de uma variável para diferentes grupos, ver Figura 4.5.

Figura 4.5: Esquema de utilização do summarise
# Criar uma variável para armazenar a soma de todos os pacientes que tiveram alta

# PASSOS
# 1. Confirme se a variável de data é válida e está definida como as.Date
# 2. ...

# Soma inicial dos pacientes que tiveram alta do hospital
sum_patients <- inpatient_hospital_lite |>
  summarise(
    all_patients = sum(doentes_saidos) # Soma dos pacientes que tiveram alta
  )

# Verificar a presença de valores NA (ausentes) na variável 'doentes_saidos'
anyNA(inpatient_hospital_lite$doentes_saidos)
[1] TRUE
Aviso

Não obtivemos um resultado válido porque há NA no conjunto de dados, precisamos especificar para ignorar os valores NA

Para isso, usamos na.rm = TRUE

Este erro é muito comum em principiantes

# Recalculando a soma dos pacientes que tiveram alta, desta vez ignorando valores NA
sum_patients <- inpatient_hospital_lite |> 
  summarise(
    all_patients=sum(doentes_saidos, na.rm = TRUE) # Soma com na.rm = TRUE para ignorar NA
  )

# Agora, vamos somar todos os dias de internamento também
sum_patients <- inpatient_hospital_lite |> 
  summarise(
    all_patients = sum(doentes_saidos, na.rm = TRUE),                # Soma total de pacientes
    days_patients = sum(dias_de_internamento, na.rm = TRUE),         # Soma total dos dias de internamento
    mean_patient_days = mean(dias_de_internamento, na.rm = TRUE),    # Média de dias de internamento
    sd_patient_days = sd(dias_de_internamento, na.rm = TRUE),        # Desvio padrão dos dias de internamento
    max_patient_days = max(dias_de_internamento, na.rm = TRUE),      # Máximo de dias de internamento
    min_patient_days = min(dias_de_internamento, na.rm = TRUE)       # Mínimo de dias de internamento
  )

4.3.7 Agrupar

‘Group by’ (antigo)

Por vezes é necessário agregar ou criar novas variáveis agregadas por outras variáveis. Vamos repetir o exercício anterior, mas com dados agregados por ano.

# Este código extrai a data será explorado de seguida
inpatient_hospital_lite <- inpatient_hospital_lite |>
  mutate(
    periodo=paste0(periodo, "-01"),
    periodo=as.Date(periodo, format = "%Y-%m-%d"),
    year = year(periodo),
    month=lubridate::month(periodo, label = FALSE),
    week=week(periodo),
    weekday=lubridate::wday(periodo, label=TRUE)
  )
#sumarizar por ano os dados
sum_patients_year <- inpatient_hospital_lite |>
  group_by(year) |>
  summarise(
    all_patients = sum(doentes_saidos, na.rm = TRUE),
    days_patients = sum(dias_de_internamento, na.rm = TRUE),
    mean_patient_days = mean(dias_de_internamento, na.rm = TRUE),
    sd_patient_days = sd(dias_de_internamento, na.rm = TRUE),
    max_patient_days = max(dias_de_internamento, na.rm = TRUE),
    min_patient_days = min(dias_de_internamento, na.rm = TRUE)
  )

head(sum_patients_year)
# A tibble: 6 × 7
   year all_patients days_patients mean_patient_days sd_patient_days
  <int>        <dbl>         <dbl>             <dbl>           <dbl>
1  2015      5125554      40245868            36855.          35924.
2  2016      5106995      40652359            37227.          36364.
3  2017      5040977      40595823            37176.          36370.
4  2018      4948916      41034190            37577.          36612.
5  2019      4929261      40737186            37305.          36435.
6  2020      4228122      36079624            33040.          31287.
# ℹ 2 more variables: max_patient_days <dbl>, min_patient_days <dbl>
# Podemos agregar por mais que uma variável 

sum_patients_year_speciality <- inpatient_hospital_lite |>
  group_by(year, tipo_de_especialidade) |>
  summarise(
    all_patients = sum(doentes_saidos, na.rm = TRUE),
    days_patients = sum(dias_de_internamento, na.rm = TRUE),
    mean_patient_days = mean(dias_de_internamento, na.rm = TRUE),
    sd_patient_days = sd(dias_de_internamento, na.rm = TRUE),
    max_patient_days = max(dias_de_internamento, na.rm = TRUE),
    min_patient_days = min(dias_de_internamento, na.rm = TRUE)
  ) |> 
  ungroup()

É boa prática fazer o ungroup após terminadas as operações em que necessitamos de variáveis agrupadas

.by ou by (novo)

A operação group_by está a ser subtituída pelo argumento .by nas operações do tidyverse.

Verbos suportados do .by

  • mutate(.by = )

  • summarise(.by = )

  • reframe(.by = )

  • filter(.by = )

  • slice(.by = )

  • slice_head(by = ) and slice_tail(by = )

  • slice_min(by = ) and slice_max(by = )

  • slice_sample(by = )

O mesmo código anterior com a nova sintaxe.

sum_patients_year <- inpatient_hospital_lite |> 
  summarise(
    all_patients = sum(doentes_saidos, na.rm = TRUE),
    days_patients = sum(dias_de_internamento, na.rm = TRUE),
    mean_patient_days = mean(dias_de_internamento, na.rm = TRUE),
    sd_patient_days = sd(dias_de_internamento, na.rm = TRUE),
    max_patient_days = max(dias_de_internamento, na.rm = TRUE),
    min_patient_days = min(dias_de_internamento, na.rm = TRUE),
    .by = year
  )
# Podemos agregar por mais que uma variável 

sum_patients_year_speciality <- inpatient_hospital_lite |> 
  summarise(
    all_patients = sum(doentes_saidos, na.rm = TRUE),
    days_patients = sum(dias_de_internamento, na.rm = TRUE),
    mean_patient_days = mean(dias_de_internamento, na.rm = TRUE),
    sd_patient_days = sd(dias_de_internamento, na.rm = TRUE),
    max_patient_days = max(dias_de_internamento, na.rm = TRUE),
    min_patient_days = min(dias_de_internamento, na.rm = TRUE),
    .by = c(year, tipo_de_especialidade)
  )

4.3.8 Cortar dados (Slice)

As operações de cortar elementos são úteis para retirar linhas específicas, particularmente em dados ordenados.

Existem várias versões:

  1. slice (selecionar por posição)
  2. slice_head ou slice_tail (selecionar por posição no ínicio ou final dos dados)
  3. slice_sample (remover amostra de linhas - por número [n] ou proporção [prop])
  4. slice_min slice (remover amostra de linhas - por número [n] ou proporção [prop])
#retirar 2a linha
linha_2 <- inpatient_hospital_lite |> 
  slice(2)
#retirar os dois primeiros elementos
primeiros_2<- inpatient_hospital_lite |> 
  slice_head(n=2)

#remover 50% das amostras
amostra_50 <- inpatient_hospital_lite |> 
  slice_sample(prop=0.5)

#retirar os 50% maiores registos de estadia dos pacientes
quartil1_estadia <- inpatient_hospital_lite |> 
  slice_max(length_patient,prop=0.5)

4.3.9 Distinct

Por vezes queremos extrair os valores únicos de uma ou mais variáveis.

Suponhamos que queremos selcionar doentes para reavaliar no nosso estudos de pacientes de hipóxia (dataset hypoxia). Só queremos 1 doente com a combinação sexo, race, AHI score e Smoking

# limpar as variáveis do dataset

hypoxia_clean <- hypoxia_clean |> 
  distinct(age, sex, race, ahi, smoking)

original_n <- length(hypoxia)
final_n <- length(hypoxia_clean)

Passámos de 36 doentes para 5 doentes para o follow-up.

4.3.10 Pull

O comando Pull permite retirar um vector dos dados de uma coluna.

Pode ser útil para loops em que iteramos por vários elementos de um vector. Vamos retirar os nomes dos hospitais dos nossos dados.

hospitais <- inpatient_hospital_lite |> 
1  distinct(instituicao) |>
2  pull(instituicao)

3head(hospitais)
1
Remover os valores distintos da variavel instituição
2
Retirar um vector com cada
3
Apresentar os dados dos hospitais
[1] "Unidade Local de Saúde do Baixo Alentejo, EPE"     
[2] "Centro Hospitalar Universitário Cova da Beira, EPE"
[3] "Centro Hospitalar do Baixo Vouga, EPE"             
[4] "Instituto Português Oncologia de Coimbra, EPE"     
[5] "Unidade Local de Saúde da Guarda, EPE"             
[6] "Centro Hospitalar de Setúbal, EPE"                 

O Pull tambem pode ser usado para facilitar inline coding

hospitais_max_doentes_saidos <- inpatient_hospital_lite |> 
  summarise(
    max_doentes_saidos=max(doentes_saidos, na.rm = TRUE)
    ) |> pull(max_doentes_saidos)

O número máximo de doentes saíde foi de 3.4354^{4}

4.3.11 Quartis

A função ntile() é usada para criar uma classificação ou divisão de um vetor numérico em “n” número de grupos (tile, se forem 4 grupos é um quartil) de aproximadamente o mesmo tamanho. Essa função é particularmente útil para dividir dados contínuos em categorias discretas.

# este código cria uma nova variável quartis estadia que divide as observações de cada hospital em quartis
# os dois comandos finais sao apenas para visualização

quartis_estadia <- inpatient_hospital_lite |> 
  mutate(
    quartis_estadia= ntile(length_patient, 4),.by = instituicao) |> 
  filter(instituicao=="Centro Hospitalar de Setúbal, EPE") |> 
  select(instituicao, length_patient, quartis_estadia) |> 
  arrange(length_patient)


head(quartis_estadia)
# A tibble: 6 × 3
  instituicao                       length_patient quartis_estadia
  <chr>                                      <dbl>           <int>
1 Centro Hospitalar de Setúbal, EPE            5.3               1
2 Centro Hospitalar de Setúbal, EPE            5.9               1
3 Centro Hospitalar de Setúbal, EPE            5.9               1
4 Centro Hospitalar de Setúbal, EPE            5.9               1
5 Centro Hospitalar de Setúbal, EPE            6                 1
6 Centro Hospitalar de Setúbal, EPE            6                 1

4.4 DATAS (DATETIME OBJECTS)

Lidar com datas pode ser complicado, mas é uma competência importante de dominar.

O tipo de dados em formato de data são muitas vezes interpretados como caracteres quando são importados.

Globalmente são objetos datetime mas podem ser POSIXt, POSIXct, and/or POSIXlt classes, ver formatos na Figura 4.6.

Existem alguns pacotes relevantes para lidade com dados em formato de data, mas o mais relevante é o “lubridate”.

Figura 4.6: Formato de datas no R
# Como obter o dia e o dia e hora, relevante na criação de relatórios e de diferenças de dados e o presente
Sys.Date()
[1] "2024-10-14"
Sys.time()
[1] "2024-10-14 17:40:43 BST"
# Precisamos de um truque para alterar o conjunto de dados existente nas datas
# Vamos usar paste0, que permite colar valores em uma variável

inpatient_hospital_lite <- inpatient_hospital_lite |>
  mutate(
    periodo=paste0(periodo, "-01")
  )
# Agora precisamos definir a variável periodo como uma data

inpatient_hospital_lite <- inpatient_hospital_lite |>
  mutate(
    periodo=as.Date(periodo, format = "%Y-%m-%d")
  )
inpatient_hospital_lite <- inpatient_hospital_lite |>
  mutate(
    year = year(periodo),
    month=lubridate::month(periodo, label = FALSE),
    week=week(periodo),
    weekday=lubridate::wday(periodo, label=TRUE)
  )
  
# Vamos inspecionar o conjunto de dados
head(inpatient_hospital_lite)
# A tibble: 6 × 13
  periodo    instituicao                    tipo_de_especialidade doentes_saidos
  <date>     <chr>                          <chr>                          <dbl>
1 2015-01-01 Unidade Local de Saúde do Bai… Especialidade Cirurg…            360
2 2015-01-01 Centro Hospitalar Universitár… Especialidade Cirurg…            352
3 2015-01-01 Centro Hospitalar do Baixo Vo… Especialidade Cirurg…            651
4 2015-01-01 Instituto Português Oncologia… Especialidade Cirurg…            330
5 2015-01-01 Unidade Local de Saúde da Gua… Especialidade Cirurg…            329
6 2015-01-01 Centro Hospitalar de Setúbal,… Especialidade Cirurg…            525
# ℹ 9 more variables: dias_de_internamento <dbl>, length_patient <dbl>,
#   new_var <dbl>, fonte <chr>, multiplicacao <dbl>, year <int>, month <dbl>,
#   week <int>, weekday <ord>
# É possível desagrupar por dia, semana, mês e ano.

Existem muitas abreviaturas relativas aos formatos de tempo. As mesmas podem ser consultadas utilizando o código ?strptime na consola.

Podem ser utilizadas no argumento format da função as.Date() para forçar a reconhecer como variavel de data.

Nota

Existem funções úteis neste pacote como make_date() que junta várias colunas numa única em formato data.

Aviso

Por vezes os programas guardam datas em formato numérico e é necessário informar o R sobre a origem, ou o valor 0 dos dados.

  1. Excel - as.Date(date_onset, origin = “1899-12-30”)

  2. Mac - as.Date(date_onset, origin = “1904-01-01”)

  3. R/Outros - as.Date(date_onset, origin = “1970-01-01”)

4.5 Ordenar Dados

A função arrange permite ordenar valores dentro de uma variável.

# Ordenar os doentes por ano e especialidade, em ordem crescente do número total de pacientes
sum_patients_year_speciality <- sum_patients_year_speciality |>
  arrange(all_patients)

# Visualizar o dataframe ordenado
head(sum_patients_year_speciality)
# A tibble: 6 × 8
   year tipo_de_especialidade   all_patients days_patients mean_patient_days
  <int> <chr>                          <dbl>         <dbl>             <dbl>
1  2022 Especialidade Médica           27610        290195             6309.
2  2022 Especialidade Cirurgica        28258        188436             4283.
3  2020 Especialidade Médica         2072265      22102427            39189.
4  2020 Especialidade Cirurgica      2155857      13977197            26472.
5  2021 Especialidade Médica         2198559      23131050            40158.
6  2021 Especialidade Cirurgica      2241712      14011698            26537.
# ℹ 3 more variables: sd_patient_days <dbl>, max_patient_days <dbl>,
#   min_patient_days <dbl>
# Ordenar em ordem descendente pelo número total de pacientes
# Pode também ser usado o sintaxe arrange(desc(variável))
sum_patients_year_speciality <- sum_patients_year_speciality |>
  arrange(-all_patients)

4.6 INTERMIDIATE DATA WRANGLING

4.6.1 Misturar funções

sum_patients_hospital <- inpatient_hospital_lite |>
  filter(
    tipo_de_especialidade == "Especialidade Cirurgica" &
    month == "12"
  ) |>
  summarise(
    mean_patients = mean(doentes_saidos, na.rm = TRUE),
    sd_patients = sd(doentes_saidos, na.rm = TRUE),
    median_patients = median(doentes_saidos, na.rm = TRUE), 
    iqr_patients = IQR(doentes_saidos, na.rm = TRUE),
  .by = instituicao)

4.7 Variáveis lag e lead

Podemos criar variáveis que representam o atraso ou avanço em relação a outras variaveis.

# O nosso objetivo é criar uma variação mensal das nossas variáveis de resultado
# O nosso dataset está organizado por tipo_de_especialidade e instituição
# E também com resultados acumulados por ano
# Precisamos de definir a unidade de atraso (lag)

inpatient_hospital_lite <- inpatient_hospital_lite |>
  mutate(
    doentes_saidos_lag = 
      lag(doentes_saidos, n = 1, order_by = periodo),
    dias_de_internamento_lag = 
      lag(dias_de_internamento, n = 1, order_by = periodo)
     ,.by= c(instituicao,tipo_de_especialidade,year)
  )

sanity <- inpatient_hospital_lite |> 
  select(
    periodo,
    instituicao,
    tipo_de_especialidade,
    year,
    doentes_saidos,
    doentes_saidos_lag
  )
hospital<-inpatient_hospital_lite |>
  filter(
    instituicao=="Centro Hospitalar de Setúbal, EPE",
    tipo_de_especialidade=="Especialidade Cirurgica",
    year=="2015"
  ) |>
  select(
    periodo,
    year,
    instituicao,
    doentes_saidos
  ) |>
  mutate(
    doentes_saidos_lag = 
      lag(doentes_saidos, n = 1, order_by = periodo ),
    doentes_saidos_var = doentes_saidos-doentes_saidos_lag,
    doentes_saidos_var1 =
      ifelse(is.na(doentes_saidos_var), doentes_saidos, doentes_saidos_var)
  )

USO: Criar Variáveis de Diferença no tempo.

  • Exemplo: Diferença mensal das diferenças
# Calcular a diferença mensal para pacientes e dias de internamento
inpatient_hospital_lite <- inpatient_hospital_lite |>
  mutate(doentes_saidos_var = doentes_saidos - doentes_saidos_lag,
         dias_de_internamento_var = dias_de_internamento - dias_de_internamento_lag)

4.8 Condições if_else

Os fluxos if_else são úteis para ir definindo níveis para determinda condição. No Excel será semelhante à utilização da fórmula IF ou SE

Nota

Estrutura da Função:

if_else(condição, verdadeiro, falso, tipo de dados faltante = NULL)

condição: Uma expressão lógica que é avaliada para cada elemento do vetor.

verdadeiro: O valor a retornar se a condição for verdadeira.

falso: O valor a retornar se a condição for falsa.

tipo de dados faltante: O tipo de dado a ser retornado em caso de valores NA. Se não especificado, assume-se NULL

inpatient_hospital_lite <- inpatient_hospital_lite |> 
  mutate(
    doentes_saidos_var =
      ifelse(is.na(doentes_saidos_var), doentes_saidos, doentes_saidos_var),
    dias_de_internamento_var = 
      ifelse(is.na(dias_de_internamento_var), dias_de_internamento, dias_de_internamento_var)
  )

inpatient_hospital_lite <- inpatient_hospital_lite |> 
  mutate(
    cat1 = ifelse(doentes_saidos >= 1000, "Muitos doentes", "Poucos doentes"),
    cat2 = ifelse(cat1 == "Poucos doentes", "Pouquissímos doentes", cat1)
  )


sanaty <- inpatient_hospital_lite |> 
  select(periodo, instituicao, tipo_de_especialidade, year, doentes_saidos, doentes_saidos_lag, doentes_saidos_var)

4.9 Case_when

Opção Tidyverse para apresentação de condições if_else

Esta veriação permite a definição de múltiplas condições de escape.

Utilizadores de Excel

No Excel será semelhante à utilização da fórmula IFS ou SE.S

Este tipo de fluxo pode terminar numa condição final que pode ser definida com o argumento .default ou com a condição TRUE

# Por vezes, precisamos de alterar as categorias dentro de uma variável
# Podemos usar case_when para fazer isso
# Podemos ver que o Hospital de Vila Franca de Xira e o Hospital de Braga têm duas designações diferentes que precisam de ser unificadas

# Corrigir designações inconsistentes na variável 'instituicao'
inpatient_hospital_lite <- inpatient_hospital_lite |>
  mutate(
    instituicao1 = case_when(
      instituicao =="Hospital de Vila Franca de Xira, PPP"  ~ "Hospital de Vila Franca de Xira, EPE",
      instituicao =="Hospital de Braga, PPP" ~ "Hospital de Braga, EPE",

    )
  )

inpatient_hospital_lite <- inpatient_hospital_lite |>
  mutate(
    instituicao2 = recode(
      instituicao,
      "Hospital de Vila Franca de Xira, PPP"  = "Hospital de Vila Franca de Xira, EPE",
      "Hospital de Braga, PPP" = "Hospital de Braga, EPE"
    )
  )



inpatient_hospital_lite <- inpatient_hospital_lite |>
  mutate(
    instituicao1 = case_when(
      instituicao =="Hospital de Vila Franca de Xira, PPP"  ~ "Hospital de Vila Franca de Xira, EPE",
      instituicao =="Hospital de Braga, PPP" ~ "Hospital de Braga, EPE"
    ),
    instituicao1 = ifelse(is.na(instituicao1), instituicao, instituicao1)
  )

inpatient_hospital_lite1 <- inpatient_hospital_lite |>
  mutate(
    instituicao = case_when(
      instituicao =="Hospital de Vila Franca de Xira, PPP"  ~ "Hospital de Vila Franca de Xira, EPE",
      instituicao =="Hospital de Braga, PPP" ~ "Hospital de Braga, EPE",
      .default = instituicao
      #TRUE = instituicao - tem o mesmo resultado que a expressão anterior
      )
  )

4.10 Mutate (avançada)

# Criar variável de duração da estadia
inpatient_hospital_lite <- inpatient_hospital_lite |>
  mutate(
    length_stay_var = dias_de_internamento_var / doentes_saidos_var, 
    length_stay_var = as.numeric(length_stay_var)
  ) |> 
  drop_na(length_stay_var) |>
  filter(length_stay_var!="Inf")

# Filtrar apenas duração de estadia positiva
inpatient_hospital_lite_apenas_pos <- inpatient_hospital_lite |>
  filter(length_stay_var >= 0)

Agora vamos criar um data wrangling mais complexo. Se a variável contiver uma expressão, podemos usar grepl para capturá-la e criar uma nova variável.

Utilizadores de Excel/Outras linguas de programação

O grepl é uma função que permite deteção de padrões de texto dentro de expressões.

Exemplo: grepl(“Universitário”, instituicao, ignore.case = TRUE) daria verdade para a expressão “Centro Hospitalar e Universitário de Coimbra, EPE”

# Os valores de length_stay_var tem valores impossiveis
# Decidi eliminar valores abaixo de zero e acima de 150 porque me pareceu razoavel 

inpatient_hospital_lite <- inpatient_hospital_lite |>
    mutate(
      tipo_instituicao = 
        case_when(
          grepl("Universitário", instituicao, ignore.case = TRUE) ~ "University",
          grepl("Oncologia", instituicao, ignore.case = TRUE) ~ "Cancer hospital"
        ),
    tipo_instituicao = 
      replace_na(tipo_instituicao, "Hospital"),
    length_stay_var = 
      ifelse(length_stay_var<=0 | length_stay_var>150, NA, length_stay_var),
    doentes_saidos_var = 
      ifelse(doentes_saidos_var<=0 , NA, doentes_saidos_var)
  ) 

4.11 Wide e long tables

4.11.1 Long to wide

Pivot long to wide
# Agrupar dados por período e tipo de instituição
inpatient_hospital_sum <- inpatient_hospital_lite |>
  summarise(
    doentes_saidos_var = sum(doentes_saidos_var, na.rm = TRUE), 
    .by = c(periodo, tipo_instituicao)
    )
# Converter uma tabela do formato longo para largo
# PASSOS
# 1. Especificar a variável de categoria
# 2. Especificar a variável numérica

# Converter 'inpatient_hospital_sum' de longo para largo
inpatient_hospital_wide <- inpatient_hospital_sum |>
  pivot_wider(
    names_from = tipo_instituicao,  # Nome das novas colunas vem de 'tipo_instituicao'
    values_from = doentes_saidos_var # Os valores dessas colunas vêm de 'doentes_saidos_var'
  )

4.11.2 Wide to long

Pivot long to wide
# Converter a tabela de volta para o formato longo
# PASSOS
# 1. Especificar a variável que não será alterada
# 2. Especificar o nome da variável categórica
# 3. Especificar o nome da variável numérica

# Converter 'inpatient_hospital_wide' de largo para longo
inpatient_hospital_long <- inpatient_hospital_wide |>
  pivot_longer(
    !periodo,                      # Manter 'periodo' como está
    names_to = "tipo_instituicao", # O nome das novas variáveis categóricas
    values_to = "doentes_saidos_var" # O nome da nova variável numérica
  )

5 JUNTAR DATASETS (JOIN)

No R, os “joins” são operações que combinam dois datasets com base em uma ou mais chaves comuns (key). Essas operações são fundamentais em análises de dados, especialmente quando se trabalha com conjuntos de dados relacionados que precisam ser combinados.

Os “join” são realizados com funções do pacote tidyverse, cada uma com características específicas:

Joins

5.1 Tipos de join

1. Inner Join

  • inner_join(a, b, by = "key")
  • Combina linhas de a e b que têm valores correspondentes na coluna especificada em by.
  • Retorna apenas as linhas que têm correspondências em ambas as tabelas.

2. Left Join

  • left_join(a, b, by = "key")
  • Retorna todas as linhas de a e as linhas correspondentes de b.
  • Se não houver correspondência em b, o resultado terá NA nas colunas de b.

3. Right Join

  • right_join(a, b, by = "key")
  • Funciona como um left_join, mas retorna todas as linhas de b e as linhas correspondentes de a.
  • Se não houver correspondência em a, o resultado terá NA nas colunas de a.

4. Full Join

  • full_join(a, b, by = "key")
  • Combina todas as linhas de a e b, com linhas correspondentes de ambos.
  • Se não houver correspondência, as colunas da tabela sem correspondência terão NA.

5. Anti Join

  • anti_join(a, b, by = "key")
  • Retorna as linhas de a que não têm correspondências em b.

5.1.1 Como Funcionam

  1. Especificação da key: As operações de join dependem da especificação de uma ou mais chaves (by = "key"). Esta key são colunas nas tabelas a e b que você deseja usar para combinar as linhas.

  2. Combinação de Linhas: O tipo de join determina como as linhas são combinadas e quais linhas são incluídas no resultado final.

  3. Tratamento de Valores Ausentes: Nos joins, valores ausentes (NA) são tratados como valores que não correspondem. Portanto, eles geralmente resultam em linhas com NA no conjunto de dados combinado.

inpatient <- inpatient_hospital_lite |>
  summarise(all_patients=sum(doentes_saidos, na.rm = TRUE),
            .by = c(periodo, instituicao) )
workers <- import("datasets/trabalhadores_por_grupo_profissional.csv", 
    delim = ";", escape_double = FALSE, trim_ws = TRUE)

workers <- janitor::clean_names(workers)
# https://data-lessons.github.io/gapminder-R/12-joins.html

# Ler dados sobre trabalhadores
workers <- workers |>
  select(periodo, instituicao, total_geral) |>
  mutate(
    periodo=paste0(periodo, "-01"),
    periodo=as.Date(periodo)
  )
inpatient_workers <- left_join(
  inpatient,
  workers,
  by= c("periodo", "instituicao")
)

inpatient_workers_inner <- inner_join(
  inpatient,
  workers,
  by = c("periodo", "instituicao")
) |> ## |>
  mutate(
    inpatient_worker_ratio = round(all_patients/ total_geral, digits = 4)
  )


anti_inpatient_workers <- anti_join(
  inpatient,
  workers,
  by=c("periodo", "instituicao")
)

5.2 Join by (atualização)

Em vez de definir o by numa acção join com um vector = ” string do nome da coluna do outro dataframe” fica o argumento join_by que é mais intuitivo.

5.2.1 Codigo antigo

df <- data.frame (ano  = c(1, 2,3,4,5, 6),
                  nome_ano = c("Pré-clinico1", "Pré-clinico2","Clínico1", "Clínico2","Clínico3", "Clínico4"))

ment_h1 <- import("datasets/ment_health.csv")

ment_h <- ment_h1 %>%
  filter(sex!=3)%>%
  mutate(sex = sex-1)%>%
  select(-id)%>%
  mutate(across(.cols = c( sex
                          , psyt
                          , glang
                          , job
                          ), .fns = as.factor))%>%
  mutate(across(.cols = c(year
                          ,health
                          ), .fns = as.ordered))
ment_hj1 <- ment_h1 %>%
  inner_join(df, by=c(year= "ano"))%>%
  select(year, nome_ano)

head(ment_hj1)
  year     nome_ano
1    1 Pré-clinico1
2    4     Clínico2
3    3     Clínico1
4    2 Pré-clinico2
5    3     Clínico1
6    5     Clínico3

5.2.2 Codigo Novo

ment_hj2 <- ment_h1 %>%
  inner_join(df, join_by(year == ano))%>%
  select(year, nome_ano)

head(ment_hj1)
  year     nome_ano
1    1 Pré-clinico1
2    4     Clínico2
3    3     Clínico1
4    2 Pré-clinico2
5    3     Clínico1
6    5     Clínico3

Pequena alteração de sintaxe mas que torna mais clara a linguagem. Para além disso permite mudanças de nome de denominaçao com o tempo.

Exemplos da utilidade:

  1. Mudança da designação de uma unidade/medicamento/doença ao longo do tempo
  2. Criação de eventos cardíacos baseado na definição de valores de frequência cardiaca

A função closest vai fazer um rolling join em que vai andar para baixo e vai procurar o mais próximo em que é verdade o age<= idade.

Isto é útil pois age <= idade vai ser verdade para ambas as condições se age for inferior que ambos os limites levando a duplicações

Outros exemplos de joins com desigualdade.

Joins_by Inequalities Variants

5.3 Operações de grupos/sets

Por vezes queremos confirmar se os dados esperados se encontram num dataset para validação do mesmo.

  • Saber todos os hospitais estão a reportar dados para o portal da transparência
# para este exemplo vamos remover os dados dos seguitnes hospti
inpatient_hospital_lite_diff <- inpatient_hospital_lite |> 
  filter(instituicao!=c("Centro Hospitalar e Universitário de Coimbra, EPE"))

#Vamos ficar com apenas os dados que estao no lite e não no lite diff
dplyr::setdiff(inpatient_hospital_lite, inpatient_hospital_lite_diff)
# A tibble: 170 × 23
   periodo    instituicao                   tipo_de_especialidade doentes_saidos
   <date>     <chr>                         <chr>                          <dbl>
 1 2015-04-01 Centro Hospitalar e Universi… Especialidade Cirurg…          11336
 2 2016-11-01 Centro Hospitalar e Universi… Especialidade Cirurg…          30800
 3 2017-02-01 Centro Hospitalar e Universi… Especialidade Cirurg…           5445
 4 2017-08-01 Centro Hospitalar e Universi… Especialidade Cirurg…          21843
 5 2017-09-01 Centro Hospitalar e Universi… Especialidade Cirurg…          24362
 6 2017-12-01 Centro Hospitalar e Universi… Especialidade Cirurg…          32885
 7 2018-02-01 Centro Hospitalar e Universi… Especialidade Cirurg…           5471
 8 2018-06-01 Centro Hospitalar e Universi… Especialidade Cirurg…          16446
 9 2019-02-01 Centro Hospitalar e Universi… Especialidade Cirurg…           5112
10 2019-09-01 Centro Hospitalar e Universi… Especialidade Cirurg…          23019
# ℹ 160 more rows
# ℹ 19 more variables: dias_de_internamento <dbl>, length_patient <dbl>,
#   new_var <dbl>, fonte <chr>, multiplicacao <dbl>, year <int>, month <dbl>,
#   week <int>, weekday <ord>, doentes_saidos_lag <dbl>,
#   dias_de_internamento_lag <dbl>, doentes_saidos_var <dbl>,
#   dias_de_internamento_var <dbl>, cat1 <chr>, cat2 <chr>, instituicao1 <chr>,
#   instituicao2 <chr>, length_stay_var <dbl>, tipo_instituicao <chr>
# Ficamos apenas com os dados de Coimbra

# podemos adidionar apenas novos dados com o union

6 OUTRAS FUNÇÕES

Algumas funções são úteis em determinadas circunstâncias específicas que se colocam aqui:

1. complete: Função utilizada para completar dados em falta - Uso: Útil em dados em série temporal

2. Funções genéricas de transformação: (as.numeric, as.double, as.character, as.factor, as.Date) - Uso: tranformação entre classes de variáveis

3. across Manipulação de múltplas variáveis ao mesmo tempo - Uso: Usar a mesma função em várias colunas ao mesmo tempo - Sintaxe: summarise(dataframe, across(selection, function without parenthesis))

4. Bind rows e Bind Colums: Combinar datasets em relação a colunas iguais ou id iguais - Uso: Juntar dados

Aviso

No bind rows temos de ter colunas com nomes em comum. No bind cols temos de ter o mesmo número de linhas.

7 EXPORTAR DADOS

Exemplos da expostação com outros pacotes sem o RIO.

# A função fwrite utilizada pelo rio permite guardar ficheiros csv muito grandes 

fwrite(
  inpatient_hospital_lite,
  file = here::here("output", "datasets", paste0("inpatient_hospital_lite", ".csv")) 
)
# SPSS

write_sav(
  inpatient_hospital_lite,
  path = "output/datasets/inpatient_hospital_lite.sav"
)

## gerar ficheiros com nome dinâmicos

write_sav(
  inpatient_hospital_lite,
  path = here::here("output", "datasets", paste0("inpatient_hospital_lite_", Sys.Date(), ".sav"))
)

# STATA
write_dta(
  inpatient_hospital_lite,
  path = here::here("output", "datasets", paste0("inpatient_hospital_lite", ".dta"))
)

7.0.1 Exportar com RIO

# exportar os dados de hypoxia para um csv
export(hypoxia,"datasets/hypoxia.csv")
#exportar tudo como um único ficheiro Excel
export(list(hypoxia,covid_inc) ,"datasets/all_data.xlsx")

7.1 FIM