Aula 3 – Importação, integração, teste t e visualização de dados no R

Fluxo didático com tidyverse, joins e comparação de médias

Autor

FIP 606

1 Introdução

Nesta aula vamos construir um fluxo completo de trabalho para dados experimentais salvos em múltiplos arquivos. Em uma situação real de pesquisa, é comum receber bases produzidas por pessoas diferentes, em anos diferentes e com pequenas inconsistências de nomes, categorias e formatos. Por isso, antes de ajustar modelos ou produzir gráficos, precisamos organizar a base de dados de forma coerente.

Ao longo desta aula, vamos:

  • importar arquivos de anos distintos;
  • inspecionar a estrutura de cada tabela;
  • padronizar nomes de colunas;
  • harmonizar categorias;
  • unir tabelas por linhas;
  • adicionar informações auxiliares com join;
  • comparar médias de produtividade entre tratamentos com o teste t;
  • visualizar o valor da estatística t e o p-valor;
  • construir um gráfico final anotado com o resultado do teste.

2 Objetivos

Ao final da aula, você deverá ser capaz de:

  • importar dados de múltiplos arquivos .csv;
  • reconhecer inconsistências entre tabelas;
  • padronizar variáveis com rename(), mutate() e select();
  • empilhar tabelas com bind_rows();
  • enriquecer tabelas com left_join();
  • executar e interpretar um teste t para comparar duas médias;
  • relacionar o teste t com sua representação gráfica;
  • construir gráficos informativos com ggplot2.

3 Arquivos utilizados

Nesta aula serão usados os seguintes arquivos:

  • experiment_2022.csv
  • experiment_2023.csv
  • experiment_2024.csv
  • location_info.csv

Todos os arquivos devem estar salvos na mesma pasta do documento Quarto, ou em uma pasta cujo caminho seja informado corretamente no código.

4 1. Carregar os pacotes

Começamos carregando os pacotes que serão usados ao longo da análise. O tidyverse reúne funções importantes para importação, transformação e visualização de dados. O pacote broom será útil para organizar a saída do teste estatístico em formato de tabela.

library(tidyverse)
library(broom)

5 2. Importar os arquivos anuais

Cada arquivo representa um ano de experimento. A primeira etapa é importar cada um separadamente e armazená-los em objetos com nomes claros e sequenciais.

dados_2022_bruto <- read_csv("experiment_2022.csv")
dados_2023_bruto <- read_csv("experiment_2023.csv")
dados_2024_bruto <- read_csv("experiment_2024.csv")

6 3. Inspecionar a estrutura das tabelas

Antes de unir arquivos, precisamos entender como eles estão organizados. A função glimpse() mostra os nomes das colunas, os tipos de variáveis e uma prévia dos valores.

glimpse(dados_2022_bruto)
Rows: 8
Columns: 7
$ year        <dbl> 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022
$ location    <chr> "Vicosa", "Vicosa", "Vicosa", "Vicosa", "Uberlandia", "Ube…
$ cultivar    <chr> "A", "A", "B", "B", "A", "A", "B", "B"
$ block       <dbl> 1, 2, 1, 2, 1, 2, 1, 2
$ treatment   <chr> "Control", "Fungicide", "Control", "Fungicide", "Control",…
$ severity    <dbl> 42, 18, 36, 14, 38, 16, 31, 12
$ yield_kg_ha <dbl> 3200, 3950, 3400, 4100, 3300, 4050, 3500, 4200
glimpse(dados_2023_bruto)
Rows: 8
Columns: 7
$ Year  <dbl> 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023
$ site  <chr> "Vicosa", "Vicosa", "Vicosa", "Vicosa", "Uberlândia", "Uberlândi…
$ cult  <chr> "A", "A", "B", "B", "A", "A", "B", "B"
$ rep   <dbl> 1, 2, 1, 2, 1, 2, 1, 2
$ trt   <chr> "ctrl", "fung", "ctrl", "fung", "ctrl", "fung", "ctrl", "fung"
$ sev   <dbl> 45, 20, 37, 15, 40, 17, 33, 13
$ yield <dbl> 3150, 3900, 3350, 4050, 3250, 4000, 3450, 4150
glimpse(dados_2024_bruto)
Rows: 8
Columns: 6
$ location     <chr> "Vicosa", "Vicosa", "Vicosa", "Vicosa", "Uberlandia", "Ub…
$ cultivar     <chr> "A", "A", "B", "B", "A", "A", "B", "B"
$ block        <dbl> 1, 2, 1, 2, 1, 2, 1, 2
$ treatment    <chr> "Control", "Fungicide", "Control", "Fungicide", "Control"…
$ severity_pct <dbl> 41, NA, 34, 14, 39, 18, NA, 12
$ yield_kg_ha  <dbl> 3220, 3980, 3420, 4120, 3340, NA, 3520, 4190

Ao observar a estrutura das tabelas, note que algumas colunas equivalentes têm nomes diferentes entre anos. Esse é um dos problemas mais comuns em dados reais. Por exemplo, a mesma informação pode aparecer como:

  • year em um arquivo e Year em outro;
  • location em um arquivo e site em outro;
  • yield_kg_ha em um arquivo e yield em outro.

Além disso, as categorias de tratamento também podem variar. Em um ano, o tratamento pode aparecer como "Control" e "Fungicide", enquanto em outro aparece abreviado como "ctrl" e "fung".

7 4. Padronizar o arquivo de 2022

O arquivo de 2022 já está próximo do formato final desejado, mas vamos manter uma convenção única de nomes para que os três anos possam ser combinados sem dificuldade.

dados_2022 <- dados_2022_bruto |>
  rename(
    Year = year,
    site = location,
    cult = cultivar,
    rep = block,
    trt = treatment,
    sev = severity,
    yld = yield_kg_ha
  )

Vamos conferir o resultado.

glimpse(dados_2022)
Rows: 8
Columns: 7
$ Year <dbl> 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022
$ site <chr> "Vicosa", "Vicosa", "Vicosa", "Vicosa", "Uberlandia", "Uberlandia…
$ cult <chr> "A", "A", "B", "B", "A", "A", "B", "B"
$ rep  <dbl> 1, 2, 1, 2, 1, 2, 1, 2
$ trt  <chr> "Control", "Fungicide", "Control", "Fungicide", "Control", "Fungi…
$ sev  <dbl> 42, 18, 36, 14, 38, 16, 31, 12
$ yld  <dbl> 3200, 3950, 3400, 4100, 3300, 4050, 3500, 4200

8 5. Padronizar o arquivo de 2023

No arquivo de 2023, alguns nomes já estão próximos do padrão que queremos, mas ainda precisamos harmonizar as categorias de tratamento e os nomes dos locais.

dados_2023 <- dados_2023_bruto |>
  rename(
    yld = yield
  ) |>
  mutate(
    trt = case_match(
      trt,
      "ctrl" ~ "Control",
      "fung" ~ "Fungicide",
      .default = trt
    ),
    site = case_match(
      site,
      "Uberlândia" ~ "Uberlandia",
      .default = site
    )
  )
glimpse(dados_2023)
Rows: 8
Columns: 7
$ Year <dbl> 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023
$ site <chr> "Vicosa", "Vicosa", "Vicosa", "Vicosa", "Uberlandia", "Uberlandia…
$ cult <chr> "A", "A", "B", "B", "A", "A", "B", "B"
$ rep  <dbl> 1, 2, 1, 2, 1, 2, 1, 2
$ trt  <chr> "Control", "Fungicide", "Control", "Fungicide", "Control", "Fungi…
$ sev  <dbl> 45, 20, 37, 15, 40, 17, 33, 13
$ yld  <dbl> 3150, 3900, 3350, 4050, 3250, 4000, 3450, 4150

9 6. Padronizar o arquivo de 2024

O arquivo de 2024 apresenta dois problemas adicionais: o ano precisa ser criado como coluna, e a variável de severidade aparece com o nome severity_pct. Também existem espaços extras em algumas categorias de tratamento, o que pode causar problemas posteriores.

dados_2024 <- dados_2024_bruto |>
  mutate(Year = 2024) |>
  rename(
    site = location,
    cult = cultivar,
    rep = block,
    trt = treatment,
    sev = severity_pct,
    yld = yield_kg_ha
  ) |>
  mutate(
    trt = str_trim(trt),
    site = case_match(
      site,
      "Viçosa" ~ "Vicosa",
      "Uberlândia" ~ "Uberlandia",
      .default = site
    )
  ) |>
  select(Year, site, cult, rep, trt, sev, yld)
glimpse(dados_2024)
Rows: 8
Columns: 7
$ Year <dbl> 2024, 2024, 2024, 2024, 2024, 2024, 2024, 2024
$ site <chr> "Vicosa", "Vicosa", "Vicosa", "Vicosa", "Uberlandia", "Uberlandia…
$ cult <chr> "A", "A", "B", "B", "A", "A", "B", "B"
$ rep  <dbl> 1, 2, 1, 2, 1, 2, 1, 2
$ trt  <chr> "Control", "Fungicide", "Control", "Fungicide", "Control", "Fungi…
$ sev  <dbl> 41, NA, 34, 14, 39, 18, NA, 12
$ yld  <dbl> 3220, 3980, 3420, 4120, 3340, NA, 3520, 4190

10 7. Conferir se os nomes das colunas agora coincidem

Antes de empilhar os arquivos, é importante verificar se os três objetos têm exatamente a mesma estrutura.

names(dados_2022)
[1] "Year" "site" "cult" "rep"  "trt"  "sev"  "yld" 
names(dados_2023)
[1] "Year" "site" "cult" "rep"  "trt"  "sev"  "yld" 
names(dados_2024)
[1] "Year" "site" "cult" "rep"  "trt"  "sev"  "yld" 

Se os nomes coincidirem e estiverem na mesma ordem, podemos unir as tabelas com segurança.

11 8. Unir os três anos em uma única tabela

A função bind_rows() empilha tabelas por linhas. Ela é usada quando queremos juntar observações de anos, locais ou experimentos diferentes, desde que as colunas representem as mesmas variáveis.

dados_empilhados <- bind_rows(dados_2022, dados_2023, dados_2024)
glimpse(dados_empilhados)
Rows: 24
Columns: 7
$ Year <dbl> 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2023, 2023, 2023,…
$ site <chr> "Vicosa", "Vicosa", "Vicosa", "Vicosa", "Uberlandia", "Uberlandia…
$ cult <chr> "A", "A", "B", "B", "A", "A", "B", "B", "A", "A", "B", "B", "A", …
$ rep  <dbl> 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,…
$ trt  <chr> "Control", "Fungicide", "Control", "Fungicide", "Control", "Fungi…
$ sev  <dbl> 42, 18, 36, 14, 38, 16, 31, 12, 45, 20, 37, 15, 40, 17, 33, 13, 4…
$ yld  <dbl> 3200, 3950, 3400, 4100, 3300, 4050, 3500, 4200, 3150, 3900, 3350,…

12 9. Padronizar a tabela empilhada em nomes mais descritivos

Até aqui usamos nomes curtos para facilitar a padronização entre anos. Agora que os dados já estão unidos, podemos renomear as colunas para uma forma mais clara e didática.

dados_experimento <- dados_empilhados |>
  rename(
    year = Year,
    location = site,
    cultivar = cult,
    block = rep,
    treatment = trt,
    severity = sev,
    yield_kg_ha = yld
  )
glimpse(dados_experimento)
Rows: 24
Columns: 7
$ year        <dbl> 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2023, 2023…
$ location    <chr> "Vicosa", "Vicosa", "Vicosa", "Vicosa", "Uberlandia", "Ube…
$ cultivar    <chr> "A", "A", "B", "B", "A", "A", "B", "B", "A", "A", "B", "B"…
$ block       <dbl> 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2…
$ treatment   <chr> "Control", "Fungicide", "Control", "Fungicide", "Control",…
$ severity    <dbl> 42, 18, 36, 14, 38, 16, 31, 12, 45, 20, 37, 15, 40, 17, 33…
$ yield_kg_ha <dbl> 3200, 3950, 3400, 4100, 3300, 4050, 3500, 4200, 3150, 3900…

13 10. Adicionar coordenadas geográficas com left_join()

Em muitas análises, precisamos enriquecer uma base principal com informações auxiliares. Isso é feito com a família join. Neste exemplo, vamos acrescentar coordenadas geográficas aos locais do experimento.

Primeiro, importamos a tabela auxiliar.

coordenadas_locais <- read_csv("location_info.csv")
coordenadas_locais
# A tibble: 3 × 3
  location   state altitude_m
  <chr>      <chr>      <dbl>
1 Vicosa     MG           648
2 Uberlandia MG           863
3 PassoFundo RS           687

Agora usamos left_join(). Essa função mantém todas as linhas da tabela principal e acrescenta colunas da tabela auxiliar quando existe correspondência entre as chaves informadas.

dados_experimento_geo <- dados_experimento |>
  left_join(coordenadas_locais, by = c("location" = "location"))
glimpse(dados_experimento_geo)
Rows: 24
Columns: 9
$ year        <dbl> 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2023, 2023…
$ location    <chr> "Vicosa", "Vicosa", "Vicosa", "Vicosa", "Uberlandia", "Ube…
$ cultivar    <chr> "A", "A", "B", "B", "A", "A", "B", "B", "A", "A", "B", "B"…
$ block       <dbl> 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2…
$ treatment   <chr> "Control", "Fungicide", "Control", "Fungicide", "Control",…
$ severity    <dbl> 42, 18, 36, 14, 38, 16, 31, 12, 45, 20, 37, 15, 40, 17, 33…
$ yield_kg_ha <dbl> 3200, 3950, 3400, 4100, 3300, 4050, 3500, 4200, 3150, 3900…
$ state       <chr> "MG", "MG", "MG", "MG", "MG", "MG", "MG", "MG", "MG", "MG"…
$ altitude_m  <dbl> 648, 648, 648, 648, 863, 863, 863, 863, 648, 648, 648, 648…

14 11. Conferir valores ausentes

Após unir tabelas, é sempre bom verificar se ainda existem valores ausentes nas variáveis principais. Isso ajuda a decidir como resumir e analisar os dados.

dados_experimento_geo |>
  summarise(
    n_na_severity = sum(is.na(severity)),
    n_na_yield = sum(is.na(yield_kg_ha)),
    n_na_state = sum(is.na(state)),
    n_na_altitude = sum(is.na(altitude_m))
  )
# A tibble: 1 × 4
  n_na_severity n_na_yield n_na_state n_na_altitude
          <int>      <int>      <int>         <int>
1             2          1          0             0

15 12. Resumos descritivos iniciais

Antes de qualquer teste inferencial, é recomendável resumir os dados. Vamos calcular as médias de severidade e produtividade por tratamento e por ano.

resumo_tratamento_ano <- dados_experimento_geo |>
  group_by(year, treatment) |>
  summarise(
    media_severity = mean(severity, na.rm = TRUE),
    media_yield = mean(yield_kg_ha, na.rm = TRUE),
    n = n(),
    .groups = "drop"
  )

resumo_tratamento_ano
# A tibble: 6 × 5
   year treatment media_severity media_yield     n
  <dbl> <chr>              <dbl>       <dbl> <int>
1  2022 Control             36.8       3350      4
2  2022 Fungicide           15         4075      4
3  2023 Control             38.8       3300      4
4  2023 Fungicide           16.2       4025      4
5  2024 Control             38         3375      4
6  2024 Fungicide           14.7       4097.     4

Também podemos resumir apenas por tratamento, considerando todos os anos em conjunto.

resumo_tratamento <- dados_experimento_geo |>
  group_by(treatment) |>
  summarise(
    media_severity = mean(severity, na.rm = TRUE),
    dp_severity = sd(severity, na.rm = TRUE),
    media_yield = mean(yield_kg_ha, na.rm = TRUE),
    dp_yield = sd(yield_kg_ha, na.rm = TRUE),
    n = n(),
    .groups = "drop"
  )

resumo_tratamento
# A tibble: 2 × 6
  treatment media_severity dp_severity media_yield dp_yield     n
  <chr>              <dbl>       <dbl>       <dbl>    <dbl> <int>
1 Control             37.8        4.17       3342.    121.     12
2 Fungicide           15.4        2.66       4063.     98.8    12

16 13. Comparação de médias com o teste t

Agora vamos comparar as médias de produtividade entre os dois tratamentos: Control e Fungicide.

O teste t para duas amostras independentes é um procedimento inferencial usado para avaliar se a diferença entre duas médias amostrais é grande o suficiente para sugerir que as médias populacionais também diferem.

16.1 13.1 Hipóteses do teste

Ao aplicar o teste t, formulamos duas hipóteses:

  • Hipótese nula (\(H_0\)): as médias populacionais são iguais
    \[H_0 : \mu_1 = \mu_2\]

  • Hipótese alternativa (\(H_1\)): as médias populacionais são diferentes
    \[H_1 : \mu_1 \neq \mu_2\]

No nosso exemplo, queremos comparar a produtividade média entre os tratamentos Control e Fungicide.

16.2 13.2 Estatística do teste

A estatística t compara a diferença observada entre médias com a variabilidade dessa diferença.

Na forma clássica do teste com variâncias assumidas como iguais, a estatística é dada por:

\[ t = \frac{\bar{x}_1 - \bar{x}_2}{s_p\sqrt{\frac{1}{n_1} + \frac{1}{n_2}}} \]

em que:

  • \(\bar{x}_1\) e \(\bar{x}_2\) são as médias amostrais;
  • \(n_1\) e \(n_2\) são os tamanhos das amostras;
  • \(s_p\) é o desvio-padrão combinado (pooled standard deviation), calculado por:

\[ s_p = \sqrt{\frac{(n_1 - 1)s_1^2 + (n_2 - 1)s_2^2}{n_1 + n_2 - 2}} \]

em que:

  • \(s_1^2\) e \(s_2^2\) são as variâncias amostrais dos dois grupos.

Na prática, o R calcula automaticamente a estatística t e o p-valor quando usamos t.test(). O mais importante neste momento é entender a lógica: quanto maior a diferença entre médias em relação à variabilidade dos dados, mais extremo tende a ser o valor de t.

16.3 13.3 Ajustar o teste no R

Vamos aplicar o teste t à produtividade.

teste_t_yield <- t.test(yield_kg_ha ~ treatment, data = dados_experimento_geo)
teste_t_yield

    Welch Two Sample t-test

data:  yield_kg_ha by treatment
t = -15.737, df = 20.762, p-value = 5.186e-13
alternative hypothesis: true difference in means between group Control and group Fungicide is not equal to 0
95 percent confidence interval:
 -816.4113 -625.7099
sample estimates:
  mean in group Control mean in group Fungicide 
               3341.667                4062.727 

A saída mostra, entre outras informações:

  • o valor da estatística t;
  • os graus de liberdade;
  • o p-valor;
  • as médias estimadas dos dois grupos.

Também podemos organizar essa saída em formato de tabela com broom::tidy().

resultado_tidy <- tidy(teste_t_yield)
resultado_tidy
# A tibble: 1 × 10
  estimate estimate1 estimate2 statistic  p.value parameter conf.low conf.high
     <dbl>     <dbl>     <dbl>     <dbl>    <dbl>     <dbl>    <dbl>     <dbl>
1    -721.     3342.     4063.     -15.7 5.19e-13      20.8    -816.     -626.
# ℹ 2 more variables: method <chr>, alternative <chr>

17 14. Interpretar o valor de t e o p-valor

O valor de t indica quantos “erros-padrão” separam a diferença observada entre médias do valor esperado sob a hipótese nula. Quanto mais distante de zero estiver esse valor, maior a evidência contra \(H_0\).

O p-valor representa a probabilidade de observar um valor de t tão extremo quanto o obtido, ou mais extremo, caso a hipótese nula seja verdadeira.

Se o p-valor for pequeno, consideramos que os dados fornecem evidência para rejeitar a hipótese nula.

Vamos extrair os valores de interesse para usar nos gráficos seguintes.

t_observado <- unname(teste_t_yield$statistic)
gl_observado <- unname(teste_t_yield$parameter)
p_observado <- unname(teste_t_yield$p.value)

t_observado
[1] -15.73743
gl_observado
[1] 20.7621
p_observado
[1] 5.186022e-13

18 15. Visualizar a estatística t na distribuição do teste

Uma forma didática de entender o teste é visualizar onde o valor observado de t cai na distribuição t de Student sob a hipótese nula.

No gráfico abaixo:

  • a curva representa a distribuição t;
  • a linha vertical mostra o valor observado de t;
  • a área sombreada representa a região associada ao p-valor.
limite_x <- max(4, abs(t_observado) + 1)

ggplot(data.frame(x = c(-limite_x, limite_x)), aes(x)) +
  stat_function(
    fun = dt,
    args = list(df = gl_observado),
    linewidth = 1
  ) +
  geom_vline(
    xintercept = c(-abs(t_observado), abs(t_observado)),
    colour = "red",
    linetype = "dashed",
    linewidth = 0.8
  ) +
  stat_function(
    fun = dt,
    args = list(df = gl_observado),
    xlim = c(-limite_x, -abs(t_observado)),
    geom = "area",
    fill = "red",
    alpha = 0.25
  ) +
  stat_function(
    fun = dt,
    args = list(df = gl_observado),
    xlim = c(abs(t_observado), limite_x),
    geom = "area",
    fill = "red",
    alpha = 0.25
  ) +
  annotate(
    "text",
    x = 0,
    y = 0.35,
    label = "Distribuição t sob H0",
    fontface = "italic"
  ) +
  annotate(
    "text",
    x = 0,
    y = 0.30,
    label = paste0("t = ", round(t_observado, 2),
                   "   |   p = ", signif(p_observado, 3))
  ) +
  labs(
    title = "Visualização da estatística t e do p-valor",
    x = "Valores de t",
    y = "Densidade"
  ) +
  theme_minimal()

19 16. Construir um gráfico de produtividade anotado com o teste t

Agora que já ajustamos e interpretamos o teste, podemos construir um gráfico de produtividade por tratamento e acrescentar o resultado estatístico ao painel.

A ordem importa: primeiro fazemos a análise, depois usamos seu resultado para enriquecer a visualização.

rotulo_teste <- paste0(
  "t = ", round(t_observado, 2), "\n",
  "p = ", signif(p_observado, 3)
)

grafico_yield <- dados_experimento_geo |>
  ggplot(aes(x = treatment, y = yield_kg_ha, color = treatment)) +
  geom_boxplot(outlier.shape = NA, linewidth = 0.6) +
  geom_jitter(width = 0.08, alpha = 0.6, size = 2) +
  annotate(
    geom = "text",
    x = 1.5,
    y = max(dados_experimento_geo$yield_kg_ha, na.rm = TRUE) + 80,
    label = rotulo_teste
  ) +
  labs(
    x = "Tratamento",
    y = "Produtividade (kg/ha)",
    title = "Produtividade por tratamento"
  ) +
  theme_classic() +
  theme(legend.position = "none")

grafico_yield

Se desejado, o gráfico pode ser salvo em arquivo.

ggsave(
  "grafico_produtividade_tratamento.png",
  grafico_yield,
  width = 6,
  height = 5,
  bg = "white"
)

20 17. Considerações finais

Esta aula mostrou um fluxo muito comum em análise de dados experimentais:

  1. importar múltiplos arquivos;
  2. inspecionar a estrutura das tabelas;
  3. padronizar nomes e categorias;
  4. unir arquivos anuais;
  5. adicionar informações auxiliares com join;
  6. resumir os dados de forma descritiva;
  7. comparar tratamentos com um teste inferencial;
  8. representar a análise em um gráfico final.

Esse fluxo reforça uma ideia importante: uma boa análise não começa no teste estatístico. Ela começa na organização da base e no entendimento claro do que cada variável representa.

21 18. Exercícios sugeridos

  1. Calcule a severidade média por local e por tratamento.
  2. Construa um gráfico de severidade por tratamento.
  3. Aplique um teste t para comparar a severidade média entre os tratamentos.
  4. Verifique se o resultado do teste para severidade é consistente com o gráfico.
  5. Modifique o código do gráfico final para anotar o teste da severidade em vez do teste da produtividade.