International Physical Activity Questionnaire - IPAQ.

Classificando dados do IPAQ (Versão Curta) para análise do nível de atividade física (Versão em Português-BR).

Autor

Prof. Dr. Gleidson Mendes Rebouças

Cenário.

A associação entre a prática de atividade física e um melhor padrão de saúde tem sido relatada na literatura há muito tempo e tem aumentado nas últimas décadas. Esses estudos evidenciaram uma relação inversa entre o nível de atividade física (NAF) e a mortalidade. Desse modo, conhecer o NAF pode ser útil tanto na prática clínica quanto em pesquisas, sejam elas com amostras pequenas ou grandes. Quando a preocupação for alcançar grandes grupos populacionais, instrumentos de precisão, fácil aplicação e de baixo custo são fundamentais.

O Questionário Interacional de Atividade Física (IPAQ) foi inicialmente proposto por um grupo de trabalho de pesquisadores durante uma reunião cientifica em Genebra, Suíça, em abril de 1998. Como parte da Organização Mundial da Saúde - Comite Interacional em Atividade Física e Saúde, o CELAFISCS (Centro de Estudos do Laboratório de Aptidão Física de São Caetano do Sul) foi um dos 12 selecionados pelo mundo como parte da força tarefa para desenvolver o IPAQ assim como para ajudar outros centros da América Latina (Matsudo et al. 2001).

Desse modo, imagine-se tendo que analisar os dados da aplicação de uma amostra com 150 participantes de ambos os sexos e com idades entre 20 e 50 anos. Os questionários foram aplicados (está implícito que as questões éticas foram cumpridas) e os dados foram inseridos em planilha eletrônica (Microsoft Excel®). Agora você precisa analisa-los de acordo com o manual fornecido pela literatura. Se é isso que você precisa, então o script abaixo é para você. Aproveite!

Coleta e carregamento de dados

Preparação da planilha (dataset)

Conforme mencionamos antes, os dados devem estar em uma planilha de excel. Provavelmente você tem sua própria maneira de organizar as informações nela. Contudo, vale lembrar algumas regras de ouro:

  • Cada variável deve ocupar somente 1 coluna (nunca mescle colunas);
  • Cada observação (amostra), deve ocupar somente 1 linhas;
  • É recomendado que não utilize nomes compostos nos títulos das colunas (use “underline” se for necessário).

Abaixo está uma mostra de como está a nossa planilha para que você possa utilizar, caso não queira modificar coisas essenciais nos scripts que virão em seguida.

Figura 1: Estrutura da planilha para receber os dados e compor o banco de dados para análise.


A Figura 1 apresenta uma estrutura enxuta para receber todas as informações que são coletadas com o instrumento IPAQ - Versão Curta. A tabela Tabela 1 apresenta a correta interpretação de todos os rótulos da coluna. Voce pode verificar cada uma destas informações no questionário exibido na Figura 2

Tabela 1: Rótulos das variáveis da planilha na Figura 1 e sua descrição.
Nome da Variável Descrição
Nomes Nomes dos participantes.
sex Sexo declarado pelo participante. Será utilizado: Masculino ou Feminino como resposta.
age Idade em anos dos participantes. Preferencialmente utilizar um número inteiro.
ID Código do participante se necessário.
weight Peso corporal do participante em kg.
VigDays Frequência semanal, em dias, de realização de atividades vigorosas por pelo menos 10 minutos contínuos.
VigHours Tempo em horas por dia, da realização de atividades vigorosas nos dias em que você fez essas atividades por pelo menos 10 minutos por dia.
VigMin Tempo em min por dia, da realização de atividades vigorosas nos dias em que você fez essas atividades por pelo menos 10 minutos por dia.
ModDays Frequência semanal, em dias, de realização de atividades moderadas por pelo menos 10 minutos contínuos.
ModHours Tempo em horas por dia, da realização de atividades moderadas nos dias em que você fez essas atividades por pelo menos 10 minutos por dia.
ModMin Tempo em min por dia, da realização de atividades moderadas nos dias em que você fez essas atividades por pelo menos 10 minutos por dia.
WalkDays Frequência semanal, em dias, de realização de caminhada por pelo menos 10 minutos contínuos.
WalkHours Tempo em horas por dia, da realização de caminhada nos dias em que você fez essas atividades por pelo menos 10 minutos por dia.
WalkMin Tempo em min por dia, da realização de caminhada nos dias em que você fez essas atividades por pelo menos 10 minutos por dia.
SitHweek Tempo em horas, no total, gasto sentado durante um dia de semana (segunda à sexta).
SitMinWeek Tempo em min, no total, gasto sentado durante um dia de semana (segunda à sexta).
SitHwkd Tempo em horas, no total, gasto sentado durante um dia de final de semana (sábado e domingo).
SitMinWkd Tempo em min, no total, gasto sentado durante um dia de final de semana (sábado e domingo).

(a) Página 1

(b) Página 2

Figura 2: International Physical Activity Questionaire - IPAQ (Versão em Português-BR)


Tendo passado todas as informações para sua planilha pessoal. Verifique se não há dados fantando, se não há alguma célula com informação digitada errada. Depois dessa auditoria, se tudo estiver adequado, salve as informações em um local seguro do seu computador.

Importando a planilha com os dados para analisar com o R.

1library(xlsx)

2my_data <- xlsx::read.xlsx(file = "IPAQ_dataset.xlsx", sheetIndex = 1)

3num_elementos <- nrow(my_data)
1
Assegure que o pacote xlsx() será instalado caso você não tenha ainda instalado em sua máquina.
2
Usando a função de importação dos dados de um arquivo de Excel chamada IPAQ_dataset.xlsx, planilha 1. Assegure-se de passar o endereço do arquivo, caso você não esteja trabalhando com o R diretamente do diretório onde o arquivo se encontra.
3
Conferindo a quantidade de partipantes na planilha. Guardar essa informação será importante em códigos futuros neste script.

Verificando a existência de dados ausentes (missing data) com o pacote naniar()

require(naniar)
Carregando pacotes exigidos: naniar
miss_var_summary(my_data)
# A tibble: 18 × 3
   variable   n_miss pct_miss
   <chr>       <int>    <num>
 1 Nomes           0        0
 2 sex             0        0
 3 age             0        0
 4 ID              0        0
 5 weight          0        0
 6 VigDays         0        0
 7 VigHours        0        0
 8 VigMin          0        0
 9 ModDays         0        0
10 ModHours        0        0
11 ModMin          0        0
12 WalkDays        0        0
13 WalkHours       0        0
14 WalkMin         0        0
15 SitHweek        0        0
16 SitMinWeek      0        0
17 SitHwkd         0        0
18 SitMinWkd       0        0

Aqui um certo luxo do pacote naniar() que é a possibilidade de exibir a visualização gráfica dos dados ausentes em função de alguma variável categórica.

require(naniar)

vis_miss(my_data, facet = sex)

Dica

Contudo, há que se ter certeza que não é na própria variável categórica que existe um dado ausente. Por isso, incialmente é melhor passar a função miss_var_summary() para se ter uma visão global e em seguida passar alguma variável categórica como parâmetro da função.

Bem, agora você pode dar uma espiada no seu dataset importado para visualizar mais detalhes.

require(dplyr)
Carregando pacotes exigidos: dplyr

Anexando pacote: 'dplyr'
Os seguintes objetos são mascarados por 'package:stats':

    filter, lag
Os seguintes objetos são mascarados por 'package:base':

    intersect, setdiff, setequal, union
head(my_data)
                   Nomes       sex age  ID weight VigDays VigHours VigMin
1        Agatha Christie  Feminino  43  89     68       3        1     16
2          Aldous Huxley Masculino  38  44     70       6        2      0
3      Aleksandr Pushkin Masculino  33  78     74       6        2      0
4 Aleksandr Solzhenitsyn Masculino  23  72     67       1        2      0
5   Alfred Lord Tennyson Masculino  43  62     77       4        1     12
6            Alice Munro  Feminino  37 130     63       2        2      0
  ModDays ModHours ModMin WalkDays WalkHours WalkMin SitHweek SitMinWeek
1       3        0     17        5         0      12        2         15
2       1        1     20        2         0      12        2         15
3       1        1     25        1         0      17        3         15
4       2        1     13        2         1      22        2         15
5       1        0     15        4         0      28        1         35
6       0        0      0        1         0      10        2         44
  SitHwkd SitMinWkd
1       3        30
2       3        30
3       4        30
4       3        30
5       2        35
6       3        44
glimpse(my_data)
Rows: 150
Columns: 18
$ Nomes      <chr> "Agatha Christie", "Aldous Huxley", "Aleksandr Pushkin", "A…
$ sex        <chr> "Feminino", "Masculino", "Masculino", "Masculino", "Masculi…
$ age        <dbl> 43, 38, 33, 23, 43, 37, 49, 38, 40, 39, 48, 33, 27, 42, 49,…
$ ID         <dbl> 89, 44, 78, 72, 62, 130, 114, 113, 127, 147, 34, 69, 38, 12…
$ weight     <dbl> 68, 70, 74, 67, 77, 63, 72, 71, 64, 77, 64, 71, 70, 71, 76,…
$ VigDays    <dbl> 3, 6, 6, 1, 4, 2, 5, 1, 4, 5, 5, 2, 4, 6, 6, 3, 0, 0, 4, 2,…
$ VigHours   <dbl> 1, 2, 2, 2, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 0, 0, 1, 2,…
$ VigMin     <dbl> 16, 0, 0, 0, 12, 0, 17, 20, 13, 0, 10, 0, 12, 16, 16, 14, 0…
$ ModDays    <dbl> 3, 1, 1, 2, 1, 0, 3, 2, 0, 0, 2, 3, 0, 1, 1, 3, 1, 0, 2, 2,…
$ ModHours   <dbl> 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0,…
$ ModMin     <dbl> 17, 20, 25, 13, 15, 0, 28, 21, 0, 0, 25, 23, 0, 14, 20, 28,…
$ WalkDays   <dbl> 5, 2, 1, 2, 4, 1, 1, 5, 1, 1, 3, 3, 2, 0, 1, 3, 2, 0, 2, 4,…
$ WalkHours  <dbl> 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,…
$ WalkMin    <dbl> 12, 12, 17, 22, 28, 10, 25, 30, 26, 30, 21, 29, 15, 0, 23, …
$ SitHweek   <dbl> 2, 2, 3, 2, 1, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 2,…
$ SitMinWeek <dbl> 15, 15, 15, 15, 35, 44, 48, 23, 50, 50, 19, 17, 21, 48, 39,…
$ SitHwkd    <dbl> 3, 3, 4, 3, 2, 3, 3, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3,…
$ SitMinWkd  <dbl> 30, 30, 30, 30, 35, 44, 48, 46, 50, 50, 38, 34, 42, 48, 39,…

Processamento dos dados

Os dados precisam ser preparados para a análise. Esse processo envolve a limpeza, transformação e organização dos dados para que possam ser utilizados de forma eficiente. Neste estágio, é fundamental garantir a:

  • Consistência dos dados: assegure que os dados sejam uniformes e coerentes.
  • Organização das Informações: estruture os dados de maneira lógica para facilitar as etapas seguintes.
  • Inexistência de informações duplicadas, faltantes ou desnecessárias: elimine duplicações, preencha lacunas e remova dados irrelevantes.

Uma preparação adequada dos dados é crucial para assegurar a precisão e eficácia das análises subsequentes.

Conforme pode ser viso na saída da função glimpse() anteriormente, Algumas variáveis estão em formato chr ou seja, estão como caracteres. A variável nomes poderá permanecer assim, pois raramente precisaremos manipular este tipo de variável. Contudo, a variável sex precisa de atenção. Vamos alterá-la para FATOR e modificar os labels.

require(forcats)
4
Passando a variável para factor (FATOR).
5
O label da variável sexo que estava Masculino e Feminino foi modificado para Homens e Mulheres.
Carregando pacotes exigidos: forcats
4my_data$sex <- factor(my_data$sex)

5my_data$sex <- fct_recode(my_data$sex, "Homens" = "Masculino", "Mulheres" = "Feminino")

levels(my_data$sex)
[1] "Mulheres" "Homens"  

Modificar os labels é uma decisão muito pessoal. Contudo, modificar a variável para fator é extremaente importante dado a estrutura da variável que é verdadeiramente categórica.

Agora vamos classificar o Nível de Atividade Física - NAF com base nos direcionamentos do IPAQ divulgados pelo CELAFISCS (Matsudo et al. 2001).

Figura 3: Estrutura de classificação dos escores do IPAQ - Versão Curta

Com base nestas informações e na literatura internacional dedica ao instrumento, usamos a função abaixo para realizar a classificação de todos os participantes (CRAIG et al. 2003).

# Função para classificar o nível de atividade física

classificar_ipaq <- function(VigDays, VigHours, VigMin,
                             ModDays, ModHours, ModMin,
                             WalkDays, WalkHours, WalkMin) {
  
  # Corrigindo Erros de Entrada (possíveis inconsistências)
  VigHours <- ifelse(VigDays == 0, 0, VigHours)
  VigMin <- ifelse(VigDays == 0, 0, VigMin)
  ModHours <- ifelse(ModDays == 0, 0, ModHours)
  ModMin <- ifelse(ModDays == 0, 0, ModMin)
  WalkHours <- ifelse(WalkDays == 0, 0, WalkHours)
  WalkMin <- ifelse(WalkDays == 0, 0, WalkMin)

  # Cálculo da duração total das atividades físicas
  VigTime <- (VigHours * 60) + VigMin
  total_vig <- VigDays * VigTime
  ModTime <- (ModHours * 60) + ModMin
  total_mod <- ModDays * ModTime
  WalkTime <- (WalkHours * 60) + WalkMin
  total_walk <- WalkDays * WalkTime
  total_ativ <- total_vig + total_mod + total_walk

  # Classificação de acordo com os critérios do IPAQ
  if (VigDays >= 5 && VigTime >= 30) {
    return("Muito Ativo")
  } else if (VigDays >= 3 && VigTime >= 20 && 
             (ModDays + WalkDays) >= 5 && 
             (ModMin + WalkTime) >= 30) {
    return("Muito Ativo")
  } else if (VigDays >= 3 && VigTime >= 20) {
    return("Ativo")
  } else if (ModDays >= 5 && ModTime >= 30) {
    return("Ativo")
  } else if (WalkDays >= 5 && WalkTime >= 30) {
    return("Ativo")
  } else if ((VigDays + ModDays + WalkDays) >= 5 && total_ativ >= 150) {
    return("Ativo")
  } else if ((VigDays + ModDays + WalkDays) >= 5 || total_ativ >= 150) {
    return("Irregularmente Ativo A")
  } else if ((VigDays + ModDays + WalkDays) > 0) {
    return("Irregularmente Ativo B")
  } else {
    return("Sedentário")
  }
}

Com a função criada, agora podemos passar a função em todo o data frame para classificar todas a entradas e adiconar uma variável ao data frame que chamaremos de classif contendo todas as classficações conforme o código abaixo.

require(dplyr)

my_data$classif <- mapply(classificar_ipaq,
                          my_data$VigDays, my_data$VigHours, my_data$VigMin,
                          my_data$ModDays, my_data$ModHours, my_data$ModMin,
                          my_data$WalkDays, my_data$WalkHours, my_data$WalkMin)

Vamos também criar uma função para aplicar os valores adequados de MET para cada minuto declarado em todas as atividades (Caminhada = 3.3 METs, Atividades Moderadas = 4 METs e Atividades Vigorosas = 8 METs) com base em (CRAIG et al. 2003).

# Função para calcular os METS

MET_calc <- function(VigDays, VigHours, VigMin,
                     ModDays, ModHours, ModMin,
                     WalkDays, WalkHours, WalkMin) {
  Vig_Met <- (VigDays * ((VigHours * 60) + VigMin)) * 8
  Mod_Met <- (ModDays * ((ModHours * 60) + ModMin)) * 4
  Walk_Met <- (WalkDays * ((WalkHours * 60) + WalkMin)) * 3.3
  MET <- Vig_Met + Mod_Met + Walk_Met
}

Do mesmo modo que fizemos com a primeira função (para classificar o NAF), agora podemos passar a função MET_calc em todo o data frame para classificar todas a entradas e adiconar uma variável ao data frame que chamaremos de MET contendo os valores de METs máximos gastos no período de uma semana (período informado pelos participantes) (Jetté, Sidney, e Blümchen 1990; Gaydos et al. 2011).

require(dplyr)

# Aplicando a função MET_calc

my_data$MET <- mapply(MET_calc,
                      my_data$VigDays, my_data$VigHours, my_data$VigMin,
                      my_data$ModDays, my_data$ModHours, my_data$ModMin,
                      my_data$WalkDays, my_data$WalkHours, my_data$WalkMin)

Agora nós dispomos da quantidade de METs estimados em uma semana, considerando as informações dos participantes. Baseado nisso, podemos estimar o dispêndio calórico no mesmo período (Arem et al. 2015; AINSWORTH et al. 2011, 2000; Westerterp 2013). Não será necessário uma função para isso, apenas iremos passar a equação de transformação direto na criação da variável.

# Adicionando as kilocalorias por semana baseada no MET
6my_data$kilocalories <- ((my_data$MET * 3.5 * my_data$weight)/1000) * 5
6
1 MET/min = 3.5 ml.\(kg^{-1}\).\(min^{-1}\); 1 Litro de \(O_2\)/min = 5 kcal/min

Agora temos que lidar com o tempo sentado que foi informado pelos participantes em dois momentos distintos (dias de semane e final de semana).

# Tempo total sentado em horas

my_data$sittotal <- ((((my_data$SitHweek*60) + my_data$SitMinWeek)*5) +
  (((my_data$SitHwkd*60) + my_data$SitMinWkd)*2))/60

Podemos ainda fazer uma média do tempo total sentado em uma semana pelo número de dias da semana(Committee et al. 2005).

# Média do tempo sentado por dia em horas

my_data$sittingAverage <- my_data$sittotal/7

Se dermos uma olhada no data frame, perceberemos que algumas variáveis que foram importantes para o processamento dos dados, agora não são mais relevantes. Observe abaixo.

# Visualizando o data frame atual
head(my_data)
                   Nomes      sex age  ID weight VigDays VigHours VigMin
1        Agatha Christie Mulheres  43  89     68       3        1     16
2          Aldous Huxley   Homens  38  44     70       6        2      0
3      Aleksandr Pushkin   Homens  33  78     74       6        2      0
4 Aleksandr Solzhenitsyn   Homens  23  72     67       1        2      0
5   Alfred Lord Tennyson   Homens  43  62     77       4        1     12
6            Alice Munro Mulheres  37 130     63       2        2      0
  ModDays ModHours ModMin WalkDays WalkHours WalkMin SitHweek SitMinWeek
1       3        0     17        5         0      12        2         15
2       1        1     20        2         0      12        2         15
3       1        1     25        1         0      17        3         15
4       2        1     13        2         1      22        2         15
5       1        0     15        4         0      28        1         35
6       0        0      0        1         0      10        2         44
  SitHwkd SitMinWkd                classif    MET kilocalories sittotal
1       3        30                  Ativo 2226.0     2648.940 18.25000
2       3        30            Muito Ativo 6159.2     7545.020 18.25000
3       4        30            Muito Ativo 6156.1     7972.150 25.25000
4       3        30                  Ativo 2085.2     2444.897 18.25000
5       2        35            Muito Ativo 2733.6     3683.526 13.08333
6       3        44 Irregularmente Ativo A 1953.0     2153.182 21.13333
  sittingAverage
1       2.607143
2       2.607143
3       3.607143
4       2.607143
5       1.869048
6       3.019048
glimpse(my_data)
Rows: 150
Columns: 23
$ Nomes          <chr> "Agatha Christie", "Aldous Huxley", "Aleksandr Pushkin"…
$ sex            <fct> Mulheres, Homens, Homens, Homens, Homens, Mulheres, Mul…
$ age            <dbl> 43, 38, 33, 23, 43, 37, 49, 38, 40, 39, 48, 33, 27, 42,…
$ ID             <dbl> 89, 44, 78, 72, 62, 130, 114, 113, 127, 147, 34, 69, 38…
$ weight         <dbl> 68, 70, 74, 67, 77, 63, 72, 71, 64, 77, 64, 71, 70, 71,…
$ VigDays        <dbl> 3, 6, 6, 1, 4, 2, 5, 1, 4, 5, 5, 2, 4, 6, 6, 3, 0, 0, 4…
$ VigHours       <dbl> 1, 2, 2, 2, 1, 2, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 0, 0, 1…
$ VigMin         <dbl> 16, 0, 0, 0, 12, 0, 17, 20, 13, 0, 10, 0, 12, 16, 16, 1…
$ ModDays        <dbl> 3, 1, 1, 2, 1, 0, 3, 2, 0, 0, 2, 3, 0, 1, 1, 3, 1, 0, 2…
$ ModHours       <dbl> 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0…
$ ModMin         <dbl> 17, 20, 25, 13, 15, 0, 28, 21, 0, 0, 25, 23, 0, 14, 20,…
$ WalkDays       <dbl> 5, 2, 1, 2, 4, 1, 1, 5, 1, 1, 3, 3, 2, 0, 1, 3, 2, 0, 2…
$ WalkHours      <dbl> 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0…
$ WalkMin        <dbl> 12, 12, 17, 22, 28, 10, 25, 30, 26, 30, 21, 29, 15, 0, …
$ SitHweek       <dbl> 2, 2, 3, 2, 1, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1…
$ SitMinWeek     <dbl> 15, 15, 15, 15, 35, 44, 48, 23, 50, 50, 19, 17, 21, 48,…
$ SitHwkd        <dbl> 3, 3, 4, 3, 2, 3, 3, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2…
$ SitMinWkd      <dbl> 30, 30, 30, 30, 35, 44, 48, 46, 50, 50, 38, 34, 42, 48,…
$ classif        <chr> "Ativo", "Muito Ativo", "Muito Ativo", "Ativo", "Muito …
$ MET            <dbl> 2226.0, 6159.2, 6156.1, 2085.2, 2733.6, 1953.0, 3498.5,…
$ kilocalories   <dbl> 2648.940, 7545.020, 7972.150, 2444.897, 3683.526, 2153.…
$ sittotal       <dbl> 18.25000, 18.25000, 25.25000, 18.25000, 13.08333, 21.13…
$ sittingAverage <dbl> 2.607143, 2.607143, 3.607143, 2.607143, 1.869048, 3.019…

Desse modo, vamos selecionar apenas as variáveis de interesse para a análise estatística e posterior representação dos dados.

require(dplyr)

# Criando um data frame com a saída dos dados relevantes para análise

output_ipaq <- my_data |> select(sex, age, weight,
                                 classif, MET, kilocalories,
7                                 sittotal, sittingAverage)


# Visualizando o novo data frame com a saída dos resultados
head(output_ipaq)

glimpse(output_ipaq)
7
Chamaremos esse data frame de output_ipaq.
       sex age weight                classif    MET kilocalories sittotal
1 Mulheres  43     68                  Ativo 2226.0     2648.940 18.25000
2   Homens  38     70            Muito Ativo 6159.2     7545.020 18.25000
3   Homens  33     74            Muito Ativo 6156.1     7972.150 25.25000
4   Homens  23     67                  Ativo 2085.2     2444.897 18.25000
5   Homens  43     77            Muito Ativo 2733.6     3683.526 13.08333
6 Mulheres  37     63 Irregularmente Ativo A 1953.0     2153.182 21.13333
  sittingAverage
1       2.607143
2       2.607143
3       3.607143
4       2.607143
5       1.869048
6       3.019048
Rows: 150
Columns: 8
$ sex            <fct> Mulheres, Homens, Homens, Homens, Homens, Mulheres, Mul…
$ age            <dbl> 43, 38, 33, 23, 43, 37, 49, 38, 40, 39, 48, 33, 27, 42,…
$ weight         <dbl> 68, 70, 74, 67, 77, 63, 72, 71, 64, 77, 64, 71, 70, 71,…
$ classif        <chr> "Ativo", "Muito Ativo", "Muito Ativo", "Ativo", "Muito …
$ MET            <dbl> 2226.0, 6159.2, 6156.1, 2085.2, 2733.6, 1953.0, 3498.5,…
$ kilocalories   <dbl> 2648.940, 7545.020, 7972.150, 2444.897, 3683.526, 2153.…
$ sittotal       <dbl> 18.25000, 18.25000, 25.25000, 18.25000, 13.08333, 21.13…
$ sittingAverage <dbl> 2.607143, 2.607143, 3.607143, 2.607143, 1.869048, 3.019…

Repare que na variável classif. Teremos que fazer com ela, o mesmo que fizemos anteriormente com a variável sex, ou seja, vamos passar de character para factor.

# Aplicando fator na Classificação (variável "classif")

output_ipaq$classif <- factor(output_ipaq$classif,
                              levels = c("Muito Ativo",
                                         "Ativo",
                                         "Irregularmente Ativo A",
                                         "Irregularmente Ativo B",
                                         "Sedentário"))

Análise dos dados

Vamos iniciar a visualização analítica das informações que foram computadas anteriormente.

Variáveis Categóricas

Temos apenas 2 variáveis categóricas para serem analisadas. Contudo, uma delas será tratada como independente (sex) e a outra como dependente (classif). Desse modo, vamos fazer algumas considerações iniciais sobre alguns teste estatísticos para variáveis categóricas.

Teste Qui-Quadrado de Independência

O teste qui-quadrado é amplamente utilizado para avaliar a associação entre duas variáveis categóricas em uma tabela de contingência. Este teste compara as frequências observadas com as frequências esperadas sob a hipótese nula de que as variáveis são independentes. Se a diferença entre as frequências observadas e esperadas for grande o suficiente, a hipótese nula é rejeitada, sugerindo uma associação entre as variáveis.

Quando usar:

  • Tabelas de contingência grandes (geralmente com mais de 5 observações esperadas em cada célula).
  • Amostras grandes, onde a aproximação da distribuição qui-quadrado é válida.
  • Quando as frequências esperadas são maiores que 5 em pelo menos 80% das células da tabela de contingência.

Limitações:

  • Não deve ser usado quando as frequências esperadas são muito baixas, pois a aproximação da distribuição qui-quadrado não será precisa.

Teste Exato de Fisher

O teste exato de Fisher é uma alternativa ao teste qui-quadrado quando as amostras são pequenas. Ele calcula a probabilidade exata de observar as frequências atuais nas categorias, assumindo que a hipótese nula é verdadeira. Ao contrário do qui-quadrado, que usa uma aproximação, o teste exato de Fisher fornece um valor exato de p.

Quando usar:

  • Tabelas de contingência pequenas (geralmente 2x2), especialmente quando uma ou mais células têm frequências esperadas menores que 5.
  • Amostras pequenas, onde a precisão é crucial.
  • Quando as condições para o teste qui-quadrado não são atendidas.

Teste G (Teste da Razão de Verossimilhança)

O teste G, ou teste da razão de verossimilhança, é uma alternativa ao teste qui-quadrado, mas ao invés de comparar as frequências observadas e esperadas diretamente, ele utiliza a razão de verossimilhança. O teste G tende a ser mais preciso em algumas situações, especialmente quando as frequências observadas são baixas. Como o qui-quadrado, ele também avalia a independência entre variáveis categóricas.

Quando usar:

  • Pode ser usado em vez do teste qui-quadrado, especialmente quando se deseja utilizar a razão de verossimilhança como uma medida da discrepância entre o modelo e os dados.
  • É uma boa alternativa quando há frequências baixas, pois pode ser mais preciso que o qui-quadrado tradicional.
  • Tabelas de contingência grandes e/ou quando há interesse específico na interpretação da razão de verossimilhança.

Limitações:

  • Como o qui-quadrado, depende de amostras relativamente grandes para que a aproximação à distribuição G seja válida.
  • Pode ser menos familiar e menos utilizado do que o qui-quadrado, o que pode limitar sua aplicação em alguns contextos.

Resumo de Aplicações

  • Qui-quadrado: Amostras grandes com frequências esperadas adequadas.
  • Exato de Fisher: Amostras pequenas ou frequências esperadas muito baixas (especialmente para tabelas 2x2).
  • G-test: Amostras grandes, especialmente quando se deseja utilizar a razão de verossimilhança ou quando as frequências observadas são baixas.

Esses testes são ferramentas importantes na análise de dados categóricos, cada um com suas próprias vantagens e desvantagens. A escolha do teste apropriado depende das características dos seus dados e do contexto da pesquisa.

A função add_p() do pacote gtsummary já identifica que a tabela se trata de uma distribuição de frequências e, portanto, aplicará um teste estatístico adequado para comparar as distribuições.

# Tabela dos resultados do NAF em função do sexo

gtsummary::theme_gtsummary_language("pt")
gtsummary::theme_gtsummary_mean_sd()

output_ipaq |> select(sex, classif) |> 
  gtsummary::tbl_summary(by = sex, label = list(classif = "Classificação IPAQ")) |> 
  gtsummary::add_overall(last = T) |> 
  gtsummary::add_p() |> 
  gtsummary::modify_header(label = "") |> 
  gtsummary::as_gt() |> 
  gt::tab_header(title = "Tabela 01:Distribuição de frequências e análise inferencial (Teste Exato de Fisher) das classifcações do IPAQ em função do Sexo",
                 subtitle = "Universidade do Estado do Rio Grande do Norte - UERN") |> gt::tab_options(
    heading.align = "left")
Tabela 01:Distribuição de frequências e análise inferencial (Teste Exato de Fisher) das classifcações do IPAQ em função do Sexo
Universidade do Estado do Rio Grande do Norte - UERN
Mulheres, N = 681 Homens, N = 821 Total, N = 1501 Valor p2
Classificação IPAQ


0.8
    Muito Ativo 22 (32%) 32 (39%) 54 (36%)
    Ativo 29 (43%) 33 (40%) 62 (41%)
    Irregularmente Ativo A 10 (15%) 10 (12%) 20 (13%)
    Irregularmente Ativo B 2 (2.9%) 4 (4.9%) 6 (4.0%)
    Sedentário 5 (7.4%) 3 (3.7%) 8 (5.3%)
1 n (%)
2 Teste exato de Fisher

A tabela está pronta para ser exportada para um editor de texto (usualmente o Microsoft Word). Apesar disso, temos algumas perguntas que podem emergir à partir da exibição dos dados na tabele acima. Há alguma associação entre as distribuições nas classificações do IPAQ em um mesmo sexo? Desse modo, podemos responder isso aplicando o teste do qui-quadrado em cada sexo. Para isso, vamos precisar apenas criar uma tabela de contingência e em seguida selecionar apenas os dados de um dos sexos por vez.

# Criando uma tabela de contingência

tabela_contingencia <- table(output_ipaq$sex, output_ipaq$classif)

8print(tabela_contingencia)
8
A exibição de saída da função print() no seu console, deve ser diferente da que será exibida aqui, pelo fato de que eu renderizei para uma saída em HTML. Mas as informações são as mesmas.
          
           Muito Ativo Ativo Irregularmente Ativo A Irregularmente Ativo B
  Mulheres          22    29                     10                      2
  Homens            32    33                     10                      4
          
           Sedentário
  Mulheres          5
  Homens            3
Muito Ativo Ativo Irregularmente Ativo A Irregularmente Ativo B Sedentário
Mulheres 22 29 10 2 5
Homens 32 33 10 4 3

Agora vamos analisar a distribuição das classificações em cada sexo. Continuarei utilizando o qui-quadrado, mas lembrem-se de que o teste pode ser modificado caso o volume de dados de sua amostra não seja adequado.

# Somente o grupo de mulheres
mulheres <- tabela_contingencia[1, ]

# Aplicando o teste qui-quadrado.
chi_mulher <- chisq.test(mulheres)

print(chi_mulher)

    Chi-squared test for given probabilities

data:  mulheres
X-squared = 38.912, df = 4, p-value = 7.265e-08
# Somente o grupo de homens
homens <- tabela_contingencia[2, ]

# Aplicando o teste qui-quadrado.
chi_homens <- chisq.test(homens)

print(chi_homens)

    Chi-squared test for given probabilities

data:  homens
X-squared = 54.463, df = 4, p-value = 4.209e-11

Nesta última análise, vamos desconsiderar o sexo e unir todas as classificações independente do sexo para verificar se existe diferenças entre as proporções.

total <- table(output_ipaq$classif)

chi_total <- chisq.test(total)

print(chi_total)

    Chi-squared test for given probabilities

data:  total
X-squared = 92, df = 4, p-value < 2.2e-16

As interpretações dos resultados dos testes não são o foco deste documento.Uma vez de posse dos resultados, é hora de ter trabalho junto do seu orientador!

Variáveis Contínuas

Repetiremos basicamente a mesma estrutura anterior, aplicando agora as funções do pacote gtsummary e gt, nas variáveis contínuas (numéricas).

# Tabela dos resuldas das numéricas
gtsummary::theme_gtsummary_language("pt", decimal.mark = ",", big.mark = ".")
Setting theme `language: pt`
gtsummary::theme_gtsummary_mean_sd()

output_ipaq |> select(sex, weight, MET, kilocalories,
                      sittotal, sittingAverage) |> 
  gtsummary::tbl_summary(by = sex,
                         label = list(weight = "Peso Corporal (kg)",
                                      MET = "Equivalente Metabólico Estimado (MET)",
                                      kilocalories = "Gasto Calórico Estimado (kcal)",
                                      sittotal = "Tempo Total Sentado/Semana (h)",
                                      sittingAverage = "Tempo Médio Sentado/dia (h)"
                                      ),
                         digits = ~1) |>
  gtsummary::add_overall(last = T) |> 
  gtsummary::add_p() |> 
  gtsummary::as_gt() |> 
  gt::fmt_number(n_sigfig = 3)
Características Mulheres, N = 681 Homens, N = 821 Total, N = 1501 Valor p2
Peso Corporal (kg) 69,4 (6,5) 70,2 (6,2) 69,8 (6,3) 0.428
Equivalente Metabólico Estimado (MET) 2.656,6 (1.598,0) 2.782,1 (1.712,3) 2.725,2 (1.657,1) 0.644
Gasto Calórico Estimado (kcal) 3.227,4 (1.967,0) 3.411,9 (2.152,4) 3.328,3 (2.065,6) 0.585
Tempo Total Sentado/Semana (h) 19,4 (4,1) 19,1 (4,4) 19,2 (4,2) 0.733
Tempo Médio Sentado/dia (h) 2,8 (0,6) 2,7 (0,6) 2,7 (0,6) 0.733
1 Média (Desvio Padrão)
2 Teste t com correção de Welch

Apresentação dos Resultados (DataViz)

Para representação gráfica dos resultados do IPAQ iremos fazer uma adaptação de um gráfico de barras do tipo lollipop.

Os passos iniciais para um gráfico de barras incluem montar tabelas com contagens absolutas ou de frequências. Então mãos à obra.

# Contagens da amostra total
n_total <- output_ipaq |> 
9  count(classif) |>
10  mutate(percent = prop.table(n) *100, sex = "Total")  |>
  select(sex, everything())

print(n_total)
9
Contando as ocorrencias dos fatores na variável classif
10
Acrescentando uma variável no objeto n_total com os valores percentuais.
    sex                classif  n   percent
1 Total            Muito Ativo 54 36.000000
2 Total                  Ativo 62 41.333333
3 Total Irregularmente Ativo A 20 13.333333
4 Total Irregularmente Ativo B  6  4.000000
5 Total             Sedentário  8  5.333333

Vamos repetir o processo para ambos os sexos.

n_by_sex <- output_ipaq |>
  group_by(sex) |> 
  count(classif) |> 
  mutate(percent = prop.table(n) *100)

Agora vamos unir os dois objetos em um único data frame chamado contagens. Em seguida mudar as variáveis em formato character para fator.

contagens <- rbind(n_total, n_by_sex)

# Verifique a estrutura do resultado final
glimpse(contagens)
Rows: 15
Columns: 4
$ sex     <chr> "Total", "Total", "Total", "Total", "Total", "Mulheres", "Mulh…
$ classif <fct> Muito Ativo, Ativo, Irregularmente Ativo A, Irregularmente Ati…
$ n       <int> 54, 62, 20, 6, 8, 22, 29, 10, 2, 5, 32, 33, 10, 4, 3
$ percent <dbl> 36.000000, 41.333333, 13.333333, 4.000000, 5.333333, 32.352941…
# Passando as variáveis "character" para "factor"
contagens <- contagens |> 
  mutate(sex = factor(sex), classif = factor(classif)) |> 
  glimpse()
Rows: 15
Columns: 4
$ sex     <fct> Total, Total, Total, Total, Total, Mulheres, Mulheres, Mulhere…
$ classif <fct> Muito Ativo, Ativo, Irregularmente Ativo A, Irregularmente Ati…
$ n       <int> 54, 62, 20, 6, 8, 22, 29, 10, 2, 5, 32, 33, 10, 4, 3
$ percent <dbl> 36.000000, 41.333333, 13.333333, 4.000000, 5.333333, 32.352941…
# Diminuindo as casas decimais
contagens$percent <- round(contagens$percent, 1)

print(contagens)
        sex                classif  n percent
1     Total            Muito Ativo 54    36.0
2     Total                  Ativo 62    41.3
3     Total Irregularmente Ativo A 20    13.3
4     Total Irregularmente Ativo B  6     4.0
5     Total             Sedentário  8     5.3
6  Mulheres            Muito Ativo 22    32.4
7  Mulheres                  Ativo 29    42.6
8  Mulheres Irregularmente Ativo A 10    14.7
9  Mulheres Irregularmente Ativo B  2     2.9
10 Mulheres             Sedentário  5     7.4
11   Homens            Muito Ativo 32    39.0
12   Homens                  Ativo 33    40.2
13   Homens Irregularmente Ativo A 10    12.2
14   Homens Irregularmente Ativo B  4     4.9
15   Homens             Sedentário  3     3.7

Como um capricho, vamos inserir os resultados dos testes qui-quadrado nos gráficos. Para isso, teremos que fazer uma manipulação que recolherá os valores das saídas das funções e guardará em um objeto chamado reports.

reports <- data.frame(
  sex = c(levels(output_ipaq$sex), "Total"),
  statistics = c(
    paste0("χ² = ", sprintf("%.2f", chi_mulher$statistic),
           "\ndf = ", chi_mulher$parameter,
           "\np valor = ", sprintf("%.2f", chi_mulher$p.value)),
    paste0("χ² = ", sprintf("%.2f", chi_homens$statistic),
           "\ndf = ", chi_homens$parameter,
           "\np valor = ", sprintf("%.2f", chi_homens$p.value)),
    paste0("χ² = ", sprintf("%.2f", chi_total$statistic),
           "\ndf = ", chi_total$parameter,  # Corrigi o parâmetro aqui também
           "\np valor = ", sprintf("%.2f", chi_total$p.value))
  )
)

Você verá onde o objeto reports será inserido no código do gráfico. Então vamos criar o gráfico.

require(ggplot2)
Carregando pacotes exigidos: ggplot2
ipaq_graph <- 
  ggplot(contagens, aes(x = reorder(classif, n), y = n)) +
  geom_segment(aes(x = reorder(classif, n), xend = reorder(classif, n),
                   y = 0, yend = n), color = "skyblue", linewidth = 12) +
  geom_point(color = "blue", size = 12) +
  geom_text(aes(label = paste0(percent,"%")), color = "white", size = 3, fontface = "bold") +
  scale_y_continuous(limits = c(-5, 75)) +
  theme_minimal() +
  labs(x = "", y = "Valor Absoluto",
       title = "International Physical Active Questionaire - IPAQ",
       subtitle = paste0("Distribuição (valor absoluto e relativo) da classificação em função do sexo e amostra total (n = ", num_elementos,").")) +
  coord_flip() +
  facet_grid(~ sex) +
  theme(axis.title.x = element_text(margin = margin(t = 20), size = 10),
        axis.text.y = element_text(size = 10),
        plot.title = element_text(size = 12),
        plot.title.position = "plot",
        plot.subtitle = element_text(size = 10, margin = margin(b = 20)),
        panel.grid.major.y = element_blank(),
        strip.text.x = element_text(face = "bold", size = 10),
        axis.text = element_text(face = "bold", colour = "Black")) +
  geom_text(
    data = reports, 
    aes(x = 1.2, y = 70, label = statistics),
    hjust = 1, 
    size = 3, fontface = "bold",
    inherit.aes = FALSE
  )

print(ipaq_graph)

Salvando o gráfico em um arquivo png para posterior exibição em qualquer documento (word, pdf, powerpoint, canva).

ggsave("ipaq.png", device = "png", plot = ipaq_graph,
       dpi = 320, width = 15, height = 7, units = "cm", scale = 1.5)

Para as variáveis contínuas, vamos fazer 3 gráficos diferentes esplorando as densidades de distribuição. Cada um vai explorar um aspecto que pode ser importante na hora de exibir as informações. Desse modo, escolha o que melhor se adequar à sua realidade.

# Criando um gráfico de densidades para o tempo sentado
library(ggridges)

plot1 <- ggplot(output_ipaq, aes(x = sittotal,
                                 y = sex, fill = after_stat(x))) +
  stat_density_ridges(quantile_lines = TRUE, alpha = 0.5,
                      quantiles = 2,
                      geom = "density_ridges_gradient") +
  geom_density_ridges_gradient() +
  scale_fill_gradient(low = "green",
                      high = "red",
                      name = "",
                      limits = c(0, 40)) +
  theme(legend.position = "top",
        legend.title.position = "top",
        plot.title.position = "plot") +
  labs(x = "horas", y = "", title = "Tempo gasto na posição sentada ao longo da semana em horas") +
  guides(fill = guide_colorbar(barwidth = unit(10, "cm")))

print(plot1)
Picking joint bandwidth of 0.922
Picking joint bandwidth of 0.922

Agora vamos criar um gráfico de densidades para as kilocalorias com ênfase no destaque das exremidades da distribuição.

plot2 <- ggplot(output_ipaq, aes(x = kilocalories,
                                 y = sex, fill = stat(quantile))) +
  stat_density_ridges(quantile_lines = TRUE,
                      calc_ecdf = TRUE,
                      geom = "density_ridges_gradient",
                      quantiles = c(0.05, 0.95)) +
  scale_fill_manual(name = "Prob.", values = c("#E2FFF2", "white", "#B0E0E6"),
                    labels = c("(0, 5%]", "(5%, 95%]", "(95%, 1]")) +
  labs(x = "kcal", y = "", title = "Gasto calórico estimado em kcal por semana") +
  theme(plot.title.position = "plot")

print(plot2)
Warning: `stat(quantile)` was deprecated in ggplot2 3.4.0.
ℹ Please use `after_stat(quantile)` instead.
Picking joint bandwidth of 744

Por último, vamos fazer mais um gráfico de distribuição com ênfase na exibição dos quartis.

plot3 <- ggplot(output_ipaq, aes(x = MET,
                                 y = sex,
                                 fill = stat(quantile))) +
  stat_density_ridges(quantile_lines = FALSE,
                      calc_ecdf = TRUE,
                      geom = "density_ridges_gradient") +
  scale_fill_manual(name = " Quantil",
                    values = c("#2400D8", "#2857FF", "#56B0FF", "#99EAFF"),
                    labels = c("Q1", "Q2", "Q3", "Q4")) +
  theme(legend.position = "top",
        legend.title.position = "top",
        plot.title.position = "plot") +
  labs(y = "",
       title = "Estimativa de unidade metabólica total despendida em uma semana")

print(plot3)
Picking joint bandwidth of 583

Considerações Finais

A análise do International Physical Activity Questionnaire (IPAQ) é uma etapa crucial para compreender os padrões de atividade física em diferentes populações. Ao trabalhar com dados categóricos derivados do IPAQ, é essencial considerar a adequação do teste estatístico ao tipo de dado e ao objetivo da análise. A correta aplicação dos métodos estatísticos não só reforça a robustez das conclusões, mas também assegura que as inferências feitas reflitam verdadeiramente os padrões de atividade física da amostra estudada. Espero que este script ajude na automação desta tarefa.

Referências

AINSWORTH, BARBARA E., WILLIAM L. HASKELL, STEPHEN D. HERRMANN, NATHANAEL MECKES, DAVID R. BASSETT, CATRINE TUDOR-LOCKE, JENNIFER L. GREER, JESSE VEZINA, MELICIA C. WHITT-GLOVER, e ARTHUR S. LEON. 2011. «2011 Compendium of Physical Activities». Medicine & Science in Sports & Exercise 43 (8): 1575–81. https://doi.org/10.1249/mss.0b013e31821ece12.
AINSWORTH, BARBARA E., WILLIAM L. HASKELL, MELICIA C. WHITT, MELINDA L. IRWIN, ANN M. SWARTZ, SCOTT J. STRATH, WILLIAM L. O???BRIEN, et al. 2000. «Compendium of Physical Activities: An Update of Activity Codes and MET Intensities». Medicine & Science in Sports & Exercise 32 (Supplement): S498–516. https://doi.org/10.1097/00005768-200009001-00009.
Arem, Hannah, Steven C. Moore, Alpa Patel, Patricia Hartge, Amy Berrington de Gonzalez, Kala Visvanathan, Peter T. Campbell, et al. 2015. «Leisure Time Physical Activity and Mortality». JAMA Internal Medicine 175 (6): 959. https://doi.org/10.1001/jamainternmed.2015.0533.
Committee, IPAQ Research et al. 2005. «Guidelines for data processing and analysis of the International Physical Activity Questionnaire (IPAQ)-short and long forms». http://www. ipaq. ki. se/scoring. pdf.
CRAIG, CORA L., ALISON L. MARSHALL, MICHAEL SJ??STR??M, ADRIAN E. BAUMAN, MICHAEL L. BOOTH, BARBARA E. AINSWORTH, MICHAEL PRATT, et al. 2003. «International Physical Activity Questionnaire: 12-Country Reliability and Validity». Medicine & Science in Sports & Exercise 35 (8): 1381–95. https://doi.org/10.1249/01.mss.0000078924.61453.fb.
Gaydos, Laura M., Paula R. Pullen, Carol J. R. Hogue, Vanessa Elliott, e Cheryl Goffney Franklin. 2011. «Calculated Metabolic Equivalents: A Tool for Exercise Prescription Among African American Women». Journal of Women’s Health 20 (8): 1151–55. https://doi.org/10.1089/jwh.2010.2715.
Jetté, M., K. Sidney, e G. Blümchen. 1990. «Metabolic Equivalents (METS) in Exercise Testing, Exercise Prescription, and Evaluation of Functional Capacity». Clinical Cardiology 13 (8): 555–65. https://doi.org/10.1002/clc.4960130809.
Matsudo, Sandra, Timóteo Araújo, Victor Marsudo, Douglas Andrade, Erinaldo Andrade, Glaucia Braggion, et al. 2001. «Questinário internacional de atividade f1sica (IPAQ): estudo de validade e reprodutibilidade no Brasil». Rev. bras. ativ. fı́s. saúde, 05–18.
Westerterp, Klass R. 2013. «Physical activity and physical activity induced energy expenditure in humans: measurement, determinants, and effects». Frontiers in Physiology 4. https://doi.org/10.3389/fphys.2013.00090.