Skip to Tutorial Content

Bem-vindo

Este é um tutorial do Prof Henrique Alvarenga para alunos da disciplina Análise de dados com a Linguarem R, do curso de medicina da UFSJ.

O Objetivo desse tutorial é aprender a filtrar observações em um data frame usando filter() e usar operadores lógicos para extrair observações de um data frame. Esse tutorial foi traduzido a partir do código-fonte que o gerou.

Neste tutorial, você aprenderá a:

  • Usar filter() para extrair observações de um data frame ou tibble
  • Escrever testes lógicos em R
  • Combinar testes lógicos com operadores Booleanos
  • Lidar com valores ausentes dentro de testes lógicos

As leituras deste tutorial seguem a seção 5.2 do livro R for Data Science.

Pré-requisitos

Para praticar essas habilidades, usaremos o conjunto de dados diabetes. Esses dados são cortesia do Dr. John Schorling, Departamento de Medicina, Faculdade de Medicina da Universidade da Virgínia. Os dados consistem em 19 variáveis em 403 indivíduos de 1046 indivíduos que foram entrevistados em um estudo para compreender a prevalência de obesidade, diabetes e outros fatores de risco cardiovascular na Virgínia central para afro-americanos. De acordo com John Hong, Diabetes Mellitus Tipo II (DM II) está associado à obesidade e a relação entre a estatura / quadril pode ser um preditor de diabetes e doenças cardíacas. DM II também também está associado à hipertensão.

Para fins desse estudo iremos considerar um nível de hemoglobina glicosilada acima de 7 como um sinal positivo de diabetes.

Para mais informações sobre este estudo, consulte Willems JP, Saunders JT, DE Hunt, JB Schorling: Prevalence of coronary heart disease risk factors among rural blacks: A community-based study. Southern Medical Journal 90:814-820; 1997 & Schorling JB, Roach J, Siegel M , Baturka N, Hunt DE, Guterbock TM , Stewart HL: A trial cessation interventions for rural African Americans. Preventive Medicine26:92-101; 1997.

Esses banco de dados pode ser obtido no endereço: https://hbiostat.org/data/

Também usaremos o pacote ggplot2 para visualizar os dados.

Conhecendo os dados

Dicionário de Variáveis do Dataset de Diabetes

Variável Tipo Descrição
id Numérica Identificador único do paciente.
chol Numérica Nível de colesterol total (mg/dL).
stab.glu Numérica Nível de glicose estável (mg/dL).
hdl Numérica Nível de colesterol HDL (mg/dL).
ratio Numérica Razão entre colesterol total e HDL.
glyhb Numérica Nível de hemoglobina glicada (%).
location Categórica Localização do paciente (Buckingham ou Louisa).
age Numérica Idade do paciente (anos).
gender Categórica Gênero do paciente (male ou female).
height Numérica Altura do paciente (polegadas).
weight Numérica Peso do paciente (libras).
frame Categórica Estrutura corporal (small, medium, large).
bp.1s Numérica Pressão arterial sistólica na primeira leitura (mm Hg).
bp.1d Numérica Pressão arterial diastólica na primeira leitura (mm Hg).
bp.2s Numérica Pressão arterial sistólica na segunda leitura (mm Hg).
bp.2d Numérica Pressão arterial diastólica na segunda leitura (mm Hg).
waist Numérica Circunferência da cintura (polegadas).
hip Numérica Circunferência do quadril (polegadas).
time.ppn Numérica Tempo desde a última ingestão de comida até a coleta de sangue (minutos).

Se estiver pronto para começar, clique em Começar!

Filtrar linhas com filter()

filter()

filter() permite que você use um teste lógico para extrair linhas específicas de um data frame. Para usar filter(), passe o data frame seguido de um ou mais testes lógicos. filter() retornará todas as linhas que passarem em cada teste lógico.

Por exemplo, podemos usar filter() para selecionar todos os pacientes no conjunto diabetes do sexo feminino e da cidade de Buckingham. Clique em Executar Código para tentar:

diabetes |>
filter(gender == "female", location == "Buckingham")

Saída

Como todas as funções do dplyr, filter() retorna um novo data frame para você salvar ou usar. Ele não sobrescreve o data frame original.

Se você quiser salvar a saída de filter(), precisará usar o operador de atribuição <-.

Execute novamente o comando no bloco de código abaixo, mas primeiro arranje para salvar a saída em um objeto chamado BuckGirls.

filter(diabetes, gender == "female", location == "Buckingham")
BuckGirls <- filter(diabetes, gender == "female", location == "Buckingham")

Bom trabalho! Agora você pode ver os resultados executando o nome BuckGirls por conta própria. Ou você pode passar BuckGirls para uma função que aceita data frames como entrada.

Você notou que esse código usou o operador de igualdade dupla, ==?  == é um dos operadores de comparação lógica do R. Operadores de comparação são fundamentais para usar filter(), então vamos dar uma olhada neles.

Comparações Lógicas

Operadores de comparação

O R fornece um conjunto de operadores de comparação que você pode usar para comparar valores: >, >=, <, <=, != (diferente), e == (igual). Cada um cria um teste lógico. Por exemplo, o pi é maior que três?

pi > 3
## [1] TRUE

Quando você coloca um teste lógico dentro de filter(), o filter aplica o teste a cada linha do data frame e, em seguida, retorna as linhas que passam no teste, como um novo data frame.

Nosso código acima retornou todas as linhas cujo valor do sexo (gender) era igual a female e cujo valor da cidade (location) era igual a Buckingham.

Atenção!

Quando você está começando com R, o erro mais comum é testar a igualdade com = em vez de ==. Quando isso acontecer, você receberá uma mensagem de erro informativa:

filter(diabetes, gender = "female")
## Error in `filter()`:
## ! We detected a named input.
## ℹ This usually means that you've used `=` instead of `==`.
## ℹ Did you mean `gender == "female"`?

Múltiplos testes

Se você passar mais de um teste lógico para filter(), ele combinará os testes com um “e” implícito. Em outras palavras, filter() retornará apenas as linhas que retornam TRUE para todos os testes. Você pode combinar testes de outras maneiras usando operadores booleanos.

Operadores Booleanos

&, |, e !

O R usa operadores booleanos para combinar múltiplas comparações lógicas em um único teste lógico. Esses operadores incluem & (e), | (ou), ! (não ou negação), e xor() (ou exclusivo).

Tanto | quanto xor() retornarão TRUE se uma ou outra comparação lógica retornar TRUE. xor() difere de | porque retornará FALSE se ambas as comparações lógicas retornarem TRUE. O nome xor significa ou exclusivo.

Estude o diagrama abaixo para entender melhor como esses operadores funcionam.

## Error in knitr::include_graphics("images/transform-logical.png"): Cannot find the file(s): "images/transform-logical.png"

Teste seu Conhecimento

Erros comuns

Em R, a ordem das operações não funciona como no inglês. Você não pode escrever filter(diabetes, frame == 'medium' $ 'large'), mesmo que você possa dizer “encontre todos pacientes medios e grandes”. Certifique-se de escrever um teste completo em cada lado de um operador booleano.

Aqui estão mais quatro dicas para ajudá-lo a usar testes lógicos e operadores booleanos em R:

  1. Um atalho útil para esse problema é x %in% y. Isso selecionará todas as linhas onde x é um dos valores em y. Poderíamos usá-lo para reescrever o código na questão acima:
medium_large <- filter(diabetes, frame %in% c("medium", "large"))

  1. Às vezes, você pode simplificar subsetting complicado lembrando da Lei de De Morgan:
  • !(x & y) é o mesmo que !x | !y
  • !(x | y) é o mesmo que !x & !y.

    Por exemplo, se você quisesse encontrar pacientes do sexo feminino (female) com biotipo grande (large) ou médio (medium), da podemos dizer que queremos os pacientes femininos que não sejam pequenos (small)
filter(diabetes, gender != "male" & frame !=  "small")
filter(diabetes, !(gender == "male" | frame ==  "small"))

Precisamos ter cuidado com um detalhe: ao filtramos que não é pequeno, incluímos no dataframe criado os pacientes que tem dados ausentes nessa variável.

  1. Assim como & e |, o R também possui && e ||. Não use esses operadores com filter()! Você aprenderá quando deve usá-los mais adiante.

  1. Sempre que começar a usar expressões complicadas e multipartes em filter(), considere transformá-las em variáveis explícitas. Isso facilita muito a verificação do seu trabalho. Você aprenderá como criar novas variáveis em breve.

Valores ausentes

NA

Valores ausentes podem tornar comparações complicadas em R. O R usa NA para representar valores ausentes ou desconhecidos. Os NAs são “contagiosos” porque quase qualquer operação envolvendo um valor desconhecido (NA) também será desconhecida (NA). Por exemplo, você pode determinar a que valor essas expressões que usam valores ausentes devem ser avaliadas? Faça uma previsão e depois clique em “Enviar Resposta”.

NA > 5
10 == NA
NA + 10
NA / 2
NA == NA

is.na()

O código abaixo é o mais confuso de todos:

NA == NA
## [1] NA

“É mais fácil entender por que isso é verdade com um pouco mais de contexto:”

# Seja x a idade de Maria. Não sabemos quantos anos ela tem.
x <- NA

# Seja y a idade de João. Não sabemos quantos anos ele tem.
y <- NA

# João e Maria têm a mesma idade?
x == y
## [1] NA
# Não sabemos!

“Se você deseja determinar se um valor está ausente, use is.na():”

is.na(x)
## [1] TRUE

filter() and NAs

filter() inclui apenas as linhas onde a condição é TRUE; ela exclui tanto os valores FALSE quanto os valores NA. Se você quiser preservar os valores ausentes, solicite-os explicitamente:”

df <- tibble(x = c(1, NA, 3))
filter(df, x > 1)
filter(df, is.na(x) | x > 1)

Exercícios

Exercício 1

Use os blocos de código abaixo para encontrar todos os pacientes solicitados

  1. Filtre os pacientes diabéticos, ou seja, tem níveis de glicohemoglobina maiores do que 7.
filter(diabetes, glyhb > 7) # 

Dica: Os níveis de glicohemoglobina estão na variável glyhb

  1. Filtre os pacientes com biotipos pequeno (small) e médio (medium)
filter(diabetes, frame %in% c("small", "medium"))

Hint: Este é um bom caso para o operador %in%.

  1. Filtre os pacientes do sexo feminino do biotipo pequeno ou médio
filter(diabetes, gender == "female" & frame %in% c("small", "medium"))

Dica: gender == “female” & frame %in% c(“small”, “medium”).

  1. Filtre os pacientes do sexo masculino, da cidade de Louisa e diabéticos.
filter(diabetes, gender == "male" & glyhb > 7 & location == "Louisa")

Dica: gender == “male” & glyhb > 7 & location == “Louisa”.

  1. Quais pacientes diabéticos e com níveis de colesterol altos (>240)
filter(diabetes, glyhb > 7 & chol > 240)

Dica: glyhb > 7 & chol > 240.

  1. Filtre os pacientes com idade igual maior que 80 anos e diabeticos (glyhb >7)
filter(diabetes, glyhb >7 & age >= 80)

Dica: glyhb >7 & age >= 80

Exercise 2

Outro auxiliar de filtragem útil do dplyr é between(). O que ele faz? Você pode usar between() para simplificar o código necessário para responder aos desafios anteriores?

?between
  1. Filtre os pacientes entre 21 e 25 anos do sexo feminino, incluindo as idades de 21 e 25 anos
filter(diabetes, gender == "female" & between(age, 21, 25))

Dica: gender == “female” & between(age, 21, 25).

Exercise 3

Quantos pacientes têm um valores ausentes na medida da glicohemoglobina (glyhb)?
filter(diabetes, is.na(glyhb))

Hint: Este é um bom caso para is.na().

Exercise 4

Por que NA ^ 0 não é um valor ausente? Por que NA | TRUE não é ausente? Por que FALSE & NA não é ausente? Você consegue descobrir a regra geral? (NA * 0 é um contraexemplo complicado!)

# Qualquer número com um expoente zero é igual a um
NA ^ 0
# valor desconhecido ou verdadeiro avalia como verdadeiro
# (porque se um dos operandos de "ou" for verdadeiro, podemos ter certeza de que o resultado é verdadeiro)
NA | TRUE
# falso e valor desconhecido avalia como falso
# (porque se um dos operandos de "e" for falso, podemos ter certeza de que o resultado é falso)
FALSE & NA
# isso não é uma comparação lógica, é um cálculo numérico envolvendo um
# valor desconhecido, resultando assim em um valor desconhecido
NA * 0

Lab_13_Filtros_e_Expressões_Lógicas

Henrique Alvarenga

08/09/2024