Autor

Marco Antônio e Matheus Villela

Data de Publicação

07/09/2026, 19:25

1 📌 Introdução

No controle tecnológico do concreto, a qualidade das decisões técnicas depende diretamente da confiabilidade dos dados obtidos em campo e em laboratório. Em situações reais, essas informações podem apresentar valores ausentes, erros de digitação, inconsistências de preenchimento, diferentes formas de representação dos mesmos dados e valores aparentemente incompatíveis com o fenômeno analisado. Quando esses problemas não são identificados e tratados adequadamente, podem comprometer os resultados estatísticos e conduzir a interpretações equivocadas.

Dessa forma, o processamento e a organização dos dados constituem etapas fundamentais antes da realização de análises estatísticas. O engenheiro deve ser capaz de inspecionar, diagnosticar, limpar, transformar e explorar os dados, garantindo que as informações utilizadas nas análises sejam consistentes e adequadas ao contexto da Engenharia Civil.

Nesta atividade, é utilizada a mesma base de dados relacionada ao controle tecnológico do concreto, composta por 100 observações e 10 variáveis. Cada registro representa um corpo de prova ou informação de controle, enquanto as variáveis descrevem características como obra, tipo de concreto, idade, resistência à compressão, consumo de cimento, relação água/cimento, abatimento, densidade e absorção do agregado.

Diferentemente do relatório anterior, que priorizou as ferramentas do Base R, este trabalho utiliza prioritariamente a família tidyverse, explorando recursos para manipulação, transformação, organização, tratamento de textos, processamento e visualização dos dados.

Assim, busca-se demonstrar como ferramentas como dplyr, tidyr, stringr, readr, purrr e ggplot2 podem ser utilizadas para transformar uma base de dados inicialmente bruta em informações organizadas, interpretáveis e úteis para a tomada de decisão na Engenharia Civil.

2 🎯 Objetivo geral

Desenvolver um fluxo de inspeção, diagnóstico, limpeza, transformação e exploração de uma base de dados do controle tecnológico do concreto, utilizando prioritariamente ferramentas da família tidyverse no R, de modo a transformar dados brutos em informações confiáveis para auxiliar na tomada de decisão técnica na Engenharia Civil.

2.1 Objetivos específicos

  • Conhecer a estrutura da base, identificando suas observações, variáveis, tipos de dados e valores ausentes.

  • Identificar inconsistências nos dados, como erros de digitação, valores inadequados, problemas de padronização e registros incompatíveis com o contexto da Engenharia Civil.

  • Limpar e padronizar a base, corrigindo variáveis qualitativas e quantitativas e tratando os valores ausentes de maneira tecnicamente justificável.

  • Utilizar ferramentas do dplyr para filtrar, selecionar, transformar, agrupar e resumir os dados.

  • Criar novas variáveis por meio de mutate() e case_when(), permitindo análises complementares do desempenho do concreto.

  • Aplicar ferramentas de stringr e readr para o tratamento de textos e a conversão adequada de valores numéricos.

  • Utilizar across() e outras ferramentas do tidyverse para realizar operações de forma sistemática sobre diferentes variáveis.

  • Explorar relações entre as características do concreto, incluindo resistência, consumo de cimento, relação água/cimento e idade dos corpos de prova.

  • Produzir representações gráficas utilizando ggplot2, auxiliando na identificação de padrões e na interpretação dos resultados.

  • Gerar informações estatísticas relevantes para o engenheiro responsável, relacionando os resultados obtidos ao contexto do controle tecnológico do concreto.

  • Desenvolver um script organizado e reprodutível, permitindo que outro profissional compreenda e reproduza as etapas de processamento e análise realizadas.

3 ⚙️ Metodologia

A metodologia adotada neste trabalho consiste no processamento, organização, limpeza, transformação e exploração de uma base de dados relacionada ao controle tecnológico do concreto, utilizando a linguagem R, com ênfase nas ferramentas da família tidyverse.

O fluxo de trabalho mantém a estrutura desenvolvida no Relatório 02, porém substitui progressivamente as funções do Base R por ferramentas voltadas à manipulação e análise organizada dos dados, como dplyr, tidyr, stringr, readr e ggplot2.

O desenvolvimento foi organizado em uma sequência lógica composta pelas etapas de:

  1. Importação e inspeção inicial dos dados;
  2. Verificação das dimensões e estrutura da base;
  3. Identificação de valores ausentes e inconsistências;
  4. Investigação de possíveis erros nos dados;
  5. Limpeza e padronização das variáveis;
  6. Conversão dos tipos de dados;
  7. Exploração dos dados com dplyr;
  8. Criação e transformação de variáveis com mutate();
  9. Análise de dados agrupados;
  10. Seleção e reorganização de variáveis;
  11. Tratamento de textos e categorias com stringr;
  12. Visualização dos dados com ggplot2;
  13. Investigação de relações relevantes para a Engenharia Civil;
  14. Elaboração de informações para apoio à tomada de decisão do engenheiro.

As atividades foram desenvolvidas progressivamente ao longo das 38 questões propostas, além do desafio final, permitindo aplicar as ferramentas do tidyverse em diferentes etapas do tratamento e da análise da base de dados.

3.1 📋 Etapas de desenvolvimento

Questão 01 — Importação dos dados

Importe a base de dados para o R e armazene-a no objeto dados. Em seguida, utilize funções da família tidyverse para verificar a correta importação e visualizar as primeiras e últimas observações da base.

Questão 02 — Dimensões da base

Determine as dimensões da base, identificando a quantidade de observações e variáveis existentes. Para isso, utilize funções compatíveis com o fluxo de trabalho do tidyverse.

Questão 03 — Estrutura da base

Analise a estrutura da base utilizando a função glimpse(), verificando os nomes das variáveis, seus tipos e uma amostra dos valores armazenados.

Questão 04 — Resumo das variáveis

Realize um resumo das variáveis da base, buscando identificar características relevantes, como valores mínimos e máximos, distribuição dos dados, categorias existentes e possíveis inconsistências.

Questão 05 — Classificação das variáveis

Analise as variáveis quanto aos seus tipos, diferenciando aquelas de natureza quantitativa das qualitativas, com base na estrutura identificada pelo R.

Questão 06 — Valores ausentes

Investigue a existência de valores ausentes na base, identificando sua quantidade, as variáveis afetadas e as respectivas observações. Para tornar a verificação sistemática, utilize a função across().

Questão 07 — Valores incompatíveis

Investigue valores potencialmente incompatíveis com o contexto da Engenharia Civil, considerando variáveis como idade, resistência, abatimento, densidade, relação água/cimento e absorção. Utilize a função filter() para localizar os registros suspeitos.

Questão 08 — Possíveis erros de digitação

Identifique registros que apresentem características de possíveis erros de digitação. Para isso, utilize funções como filter() e select(), permitindo localizar e visualizar os registros completos.

Questão 09 — Padronização da variável obra

Verifique as categorias da variável obra utilizando count() e distinct(), buscando identificar diferenças de grafia, espaços ou outras inconsistências entre categorias que deveriam representar o mesmo bloco.

Questão 10 — Padronização da variável tipo_concreto

Analise as categorias da variável tipo_concreto para verificar se existem diferentes formas de representar uma mesma classe de concreto.

Questão 11 — Verificação dos tipos após o diagnóstico

Após identificar os problemas, verifique novamente a estrutura da base utilizando glimpse() e outras funções apropriadas, avaliando como os erros encontrados podem influenciar a interpretação dos tipos das variáveis.

Questão 12 — Criação da base limpa

Crie uma cópia da base original denominada dados_limpos, preservando a base dados para garantir a possibilidade de comparação e recuperação das informações originais durante o processo de tratamento.

Questão 13 — Limpeza das variáveis qualitativas

Padronize as variáveis qualitativas utilizando funções do pacote stringr, como str_trim(), str_to_upper(), str_replace() e str_replace_all(). Elimine espaços indevidos e uniformize as categorias.

Questão 14 — Conversão das variáveis quantitativas

Converta as variáveis que deveriam ser quantitativas para seus tipos adequados. Considere problemas relacionados à utilização de vírgula decimal, caracteres indevidos e registros armazenados como texto, utilizando recursos do pacote readr quando apropriado.

Questão 15 — Tratamento dos valores ausentes

Identifique e analise individualmente os valores ausentes. Considere as possibilidades de exclusão da observação, substituição do valor, manutenção do NA ou consulta à fonte original, e adote a alternativa considerada mais adequada diante das informações disponíveis.

Questão 16 — Verificação após a limpeza

Após realizar o processo de limpeza, verifique novamente a estrutura e o resumo da base. Confirme as alterações realizadas e quais inconsistências foram corrigidas.

Questão 17 — Resistência média

Calcule a resistência média à compressão dos corpos de prova e, posteriormente, determine as médias considerando diferentes agrupamentos, como bloco da obra, tipo de concreto e idade do corpo de prova.

Questão 18 — Comparação entre obras

Compare as resistências médias entre os diferentes blocos da obra. Organize os resultados em ordem crescente ou decrescente utilizando arrange(), permitindo identificar os blocos com maior e menor resistência média.

Questão 19 — Resistência por classe de concreto

Calcule a resistência média para cada classe de concreto, considerando C25, C30, C35 e C40. Organize os resultados da maior para a menor resistência média.

Questão 20 — Estatísticas por grupo

Calcule, para cada tipo de concreto, as médias da resistência, consumo de cimento, relação água/cimento, abatimento e densidade. Utilize a combinação group_by() e summarise() para realizar as análises agrupadas.

Questão 21 — Resistência relativa

Crie a variável resistencia_relativa, representando a razão entre a resistência observada e uma resistência de referência associada à classe do concreto. Para estabelecer os valores de referência e realizar a classificação, utilize as funções mutate() e case_when().

Questão 22 — Classificação dos corpos de prova

Crie a variável classificacao, destinada a classificar os corpos de prova segundo critérios relacionados à resistência. Defina e justifique os limites adotados considerando o objetivo da análise.

Questão 23 — Resistência acima da média

Crie a variável acima_media, assumindo os valores TRUE ou FALSE, indicando se a resistência de cada corpo de prova está acima da média de seu respectivo tipo de concreto. Utilize group_by() em conjunto com mutate().

Questão 24 — Quantidade de observações por grupo

Determine a quantidade de observações existente em cada categoria de tipo_concreto, utilizando group_by() e summarise() para produzir uma tabela organizada.

Questão 25 — Média por tipo de concreto

Calcule a resistência média para cada tipo de concreto e, posteriormente, ordene os resultados utilizando arrange(), facilitando a comparação entre os grupos.

Questão 26 — Estatísticas descritivas por grupo

Calcule diferentes estatísticas da resistência à compressão para cada tipo de concreto, incluindo número de observações, média, mediana, desvio-padrão, mínimo e máximo. Utilize essas medidas para realizar uma análise mais completa do comportamento dos dados.

Questão 27 — Seleção das variáveis quantitativas

Selecione as variáveis quantitativas relacionadas às propriedades do concreto utilizando select(), podendo combiná-la com where() ou all_of(). Crie uma tabela contendo somente as informações relevantes para as análises quantitativas.

Questão 28 — Cálculo de médias com across()

Utilize a função across() para calcular simultaneamente as médias das variáveis quantitativas selecionadas. Compare o resultado com a realização individual das mesmas operações, avaliando a facilidade de manutenção do código.

Questão 29 — Transformação simultânea de variáveis

Realize uma transformação simultânea em um conjunto de variáveis quantitativas utilizando mutate() e across(). Escolha a transformação de acordo com o objetivo da análise e sua utilidade no tratamento dos dados.

Questão 30 — Estatísticas múltiplas com across()

Utilize a combinação de across() e summarise() para calcular diferentes estatísticas das variáveis quantitativas, agrupadas por tipo de concreto. Reduza a repetição de comandos e organize o código.

Questão 31 — Padronização de textos

Investigue e padronize a variável obra utilizando funções do pacote stringr. Verifique situações envolvendo espaços, diferenças entre letras maiúsculas e minúsculas e diferentes grafias para uma mesma categoria.

Questão 32 — Identificação de padrões textuais

Utilize a função str_detect() para localizar registros contendo determinados padrões textuais nas variáveis tipo_concreto ou obra. Utilize essa abordagem como ferramenta auxiliar para identificar inconsistências na base.

Questão 33 — Distribuição da resistência

Elabore um gráfico utilizando ggplot2 e geom_boxplot() para comparar a distribuição da resistência à compressão entre os diferentes tipos de concreto. Avalie diferenças de tendência central, dispersão e possíveis valores discrepantes.

Questão 34 — Consumo de cimento e resistência

Elabore um gráfico de dispersão utilizando geom_point() para investigar a relação entre o consumo de cimento e a resistência à compressão. Quando apropriado, adicione uma linha de tendência para auxiliar na identificação do comportamento dos dados.

Questão 35 — Relação água/cimento e resistência

Elabore um gráfico utilizando ggplot2 para investigar a relação entre a relação água/cimento e a resistência à compressão. Analise o comportamento observado, buscando identificar tendências relevantes para o controle tecnológico do concreto.

Questão 36 — Comparação entre obras

Investigue, de forma descritiva, a afirmação de que os concretos utilizados no Bloco C apresentam desempenho superior aos demais blocos. Combine ferramentas do dplyr e ggplot2 para comparar os resultados entre as obras.

Questão 37 — Idade e resistência

Analise a resistência média dos corpos de prova em diferentes idades utilizando group_by() e summarise(). Em seguida, represente os resultados graficamente para investigar o comportamento da resistência em função do aumento da idade.

Questão 38 — Resumo para o engenheiro

Elabore uma tabela-resumo contendo informações estatísticas consideradas relevantes para o acompanhamento da qualidade do concreto. Justifique as informações selecionadas de acordo com sua utilidade para a interpretação dos resultados e apoio à tomada de decisão do engenheiro.

3.2 🏗️ Desafio final — O engenheiro responsável pelos dados

Como etapa final, desenvolva um script organizado em R, utilizando prioritariamente ferramentas da família tidyverse, capaz de reproduzir as principais etapas realizadas ao longo do relatório.

O script deverá contemplar:

  1. Inspeção inicial da base;
  2. Identificação de possíveis problemas;
  3. Verificação de valores ausentes;
  4. Identificação de inconsistências;
  5. Produção de uma versão limpa dos dados;
  6. Geração de estatísticas descritivas;
  7. Criação de variáveis derivadas;
  8. Produção de representações gráficas;
  9. Geração de informações úteis ao engenheiro responsável pela obra.

O código deverá ser organizado de maneira sequencial e documentada, permitindo que outro profissional consiga compreender as etapas realizadas, as transformações aplicadas e as decisões tomadas durante o tratamento da base.

4 📚 Fundamentação teórica

A Estatística Descritiva compreende métodos utilizados para resumir e interpretar dados por meio de medidas de posição, dispersão e representação gráfica (BATISTA, 2024). Esses recursos permitem identificar padrões, variações e diferenças entre os dados analisados.

Na análise de dados da Engenharia Civil, essas ferramentas contribuem para a interpretação de resultados experimentais e para a identificação de comportamentos que possam auxiliar na avaliação dos materiais e processos construtivos.

O R, por meio de ferramentas do tidyverse, possibilita organizar, tratar, transformar e analisar os dados de forma sistemática (BATISTA e ARTHUR, 2023). Sua aplicação facilita a realização das análises estatísticas e a representação dos resultados.

Assim, os conceitos estatísticos e as ferramentas computacionais empregados neste relatório fornecem suporte para a análise e interpretação dos dados de controle tecnológico do concreto.

5 🔍 Resultados e Discussão

5.1 Questão 1

A base de dados foi importada para o R utilizando a função read_csv2(), que é adequada ao arquivo por utilizar o ponto e vírgula (;) como separador. Optou-se por importar inicialmente todas as variáveis como texto, preservando os valores originais e evitando conversões automáticas antes da etapa de limpeza. O argumento trim_ws = FALSE foi mantido para preservar os espaços presentes nos dados.

Código
library(tidyverse)

dados <- read_csv2(
  "base_de_dados.csv",
  col_types = cols(.default = col_character()),
  trim_ws = FALSE
)

print(head(dados), width = Inf)
# A tibble: 6 × 10
  id_corpo_prova obra    tipo_concreto idade_dias resistencia_mpa cimento_kg_m3
  <chr>          <chr>   <chr>         <chr>      <chr>           <chr>        
1 CP-001         Bloco A C35           28         36.3            395          
2 CP-002         Bloco A C30           7          28.4            340          
3 CP-003         Bloco C C30           56         36.1            338          
4 CP-004         Bloco A C40           28         47.2            407          
5 CP-005         Bloco B C25           28         27.9            316          
6 CP-006         Bloco B C40           28         41.5            398          
  relacao_a_c abatimento_mm densidade_kg_m3 absorção_agregado_pct
  <chr>       <chr>         <chr>           <chr>                
1 0.5         111.0         2332.0          2.3                  
2 0.54        114.0         2389.0          1.85                 
3 0.56        106.0         2427.0          1.89                 
4 0.47        142.0         2345.0          1.97                 
5 0.61        133.0         2448.0          2.31                 
6 0.43        98.0          2324.0          0.8                  
Código
print(tail(dados), width = Inf)
# A tibble: 6 × 10
  id_corpo_prova obra    tipo_concreto idade_dias resistencia_mpa cimento_kg_m3
  <chr>          <chr>   <chr>         <chr>      <chr>           <chr>        
1 CP-095         Bloco A C25           28         30.3            327          
2 CP-096         Bloco D C25           7          21.3            295          
3 CP-097         Bloco A C25           28         26.7            356          
4 CP-098         Bloco A C35           14         37.0            375          
5 CP-099         Bloco C C25           56         31.1            332          
6 CP-100         Bloco A C30           56         30.9            377          
  relacao_a_c abatimento_mm densidade_kg_m3 absorção_agregado_pct
  <chr>       <chr>         <chr>           <chr>                
1 0.63        124.0         2334.0          1.55                 
2 0.59        117.0         2349.0          1.72                 
3 0.64        122.0         2440.0          <NA>                 
4 0.46        137.0         2387.0          2.04                 
5 0.62        81.0          2414.0          1.88                 
6 0.55        109.0         2346.0          1.13                 

As funções head() e tail() foram utilizadas para verificar as primeiras e últimas observações da base. A importação como texto permite identificar e corrigir as inconsistências existentes antes da conversão das variáveis para seus respectivos tipos.

5.2 Questão 2

As dimensões da base foram verificadas por meio das funções nrow() e ncol(). A função nrow() retorna o número de linhas, correspondente às observações, enquanto ncol() retorna o número de colunas, correspondente às variáveis.

Código
nrow(dados)
[1] 100
Código
ncol(dados)
[1] 10

A base apresentou 100 observações e 10 variáveis. Dessa forma, cada linha representa uma observação e cada coluna corresponde a uma variável utilizada na análise.

5.3 Questão 3

A estrutura da base foi apresentada por meio da função glimpse(), pertencente ao tidyverse. Essa função permite visualizar de forma resumida o número de observações, as variáveis existentes, os tipos atribuídos pelo R e alguns dos valores armazenados.

Código
glimpse(dados)
Rows: 100
Columns: 10
$ id_corpo_prova        <chr> "CP-001", "CP-002", "CP-003", "CP-004", "CP-005"…
$ obra                  <chr> "Bloco A", "Bloco A", "Bloco C", "Bloco A", "Blo…
$ tipo_concreto         <chr> "C35", "C30", "C30", "C40", "C25", "C40", "C25",…
$ idade_dias            <chr> "28", "7", "56", "28", "28", "28", "56", "28", "…
$ resistencia_mpa       <chr> "36.3", "28.4", "36.1", "47.2", "27.9", "41.5", …
$ cimento_kg_m3         <chr> "395", "340", "338", "407", "316", "398", "351",…
$ relacao_a_c           <chr> "0.5", "0.54", "0.56", "0.47", "0.61", "0.43", "…
$ abatimento_mm         <chr> "111.0", "114.0", "106.0", "142.0", "133.0", "98…
$ densidade_kg_m3       <chr> "2332.0", "2389.0", "2427.0", "2345.0", "2448.0"…
$ absorção_agregado_pct <chr> "2.3", "1.85", "1.89", "1.97", "2.31", "0.8", "1…

A análise da estrutura permitiu verificar que a base possui 100 observações e 10 variáveis. Como todas as colunas foram importadas inicialmente como texto, as variáveis foram apresentadas pelo R com o tipo <chr>.

Essa escolha foi realizada para preservar os valores originais da base e evitar conversões automáticas antes da identificação dos problemas existentes. Dessa forma, a classificação das variáveis quanto à sua natureza será realizada considerando o significado das informações armazenadas.

5.4 Questão 4

Para apresentar um resumo inicial das variáveis, foi verificada a quantidade de valores distintos presentes em cada coluna. Como todas as variáveis foram importadas como texto, essa abordagem permite investigar a diversidade dos valores sem realizar conversões antecipadas.

Código
dados %>%
  summarise(
    across(
      everything(),
      ~n_distinct(.x)
    )
  ) %>%
  print(width = Inf)
# A tibble: 1 × 10
  id_corpo_prova  obra tipo_concreto idade_dias resistencia_mpa cimento_kg_m3
           <int> <int>         <int>      <int>           <int>         <int>
1            100     5             5          5              84            68
  relacao_a_c abatimento_mm densidade_kg_m3 absorção_agregado_pct
        <int>         <int>           <int>                 <int>
1          25            57              65                    82

A função across() permite aplicar a mesma operação a todas as variáveis da base, enquanto n_distinct() contabiliza a quantidade de valores diferentes presentes em cada coluna.

O resultado permite identificar características iniciais da base, como a existência de diferentes categorias nas variáveis qualitativas e a quantidade de valores distintos nas variáveis que possuem natureza quantitativa.

Algumas variáveis apresentam valores com diferentes formas de preenchimento, como o uso de vírgula decimal, espaços adicionais e caracteres indevidos. Essas situações serão investigadas nas etapas seguintes.

Em comparação com o Relatório 02, a função summary() apresenta um resumo mais direto dos dados. Neste relatório, os recursos do tidyverse permitem realizar uma investigação mais direcionada, selecionando e transformando as informações conforme a necessidade da análise.

5.5 Questão 5

Como todas as variáveis foram importadas inicialmente como texto, o tipo atribuído pelo R foi verificado utilizando across() em conjunto com class().

Código
dados %>%
  summarise(
    across(
      everything(),
      ~class(.x)[1]
    )
  ) %>%
  print(width = Inf)
# A tibble: 1 × 10
  id_corpo_prova obra      tipo_concreto idade_dias resistencia_mpa
  <chr>          <chr>     <chr>         <chr>      <chr>          
1 character      character character     character  character      
  cimento_kg_m3 relacao_a_c abatimento_mm densidade_kg_m3 absorção_agregado_pct
  <chr>         <chr>       <chr>         <chr>           <chr>                
1 character     character   character     character       character            

A função everything() seleciona todas as colunas da base, enquanto across() aplica a função class() a cada variável.

Como resultado, todas as variáveis foram reconhecidas inicialmente pelo R como character. Entretanto, o tipo de armazenamento não determina, por si só, a natureza estatística da variável.

Considerando a natureza das informações, as variáveis podem ser classificadas da seguinte forma:

Natureza Variáveis
Qualitativas id_corpo_prova, obra, tipo_concreto
Quantitativas idade_dias, resistencia_mpa, cimento_kg_m3, relacao_a_c, abatimento_mm, densidade_kg_m3, absorção_agregado_pct

Assim, as sete últimas variáveis possuem natureza quantitativa, embora estejam temporariamente armazenadas como texto. Essa conversão será realizada após a identificação e correção das inconsistências presentes na base.

5.6 Questão 6

A existência de valores ausentes na base foi investigada utilizando across() em conjunto com is.na(). Essa abordagem permite realizar uma verificação sistemática de todas as variáveis.

Inicialmente, foi calculada a quantidade de valores ausentes em cada variável:

Código
ausentes_variaveis <- dados %>%
  summarise(
    across(
      everything(),
      ~sum(is.na(.x))
    )
  ) %>%
  pivot_longer(
    cols = everything(),
    names_to = "variavel",
    values_to = "quantidade_ausentes"
  ) %>%
  filter(quantidade_ausentes > 0)

knitr::kable(
  ausentes_variaveis,
  col.names = c(
    "Variável",
    "Quantidade de valores ausentes"
  ),
  caption = "Variáveis que apresentam valores ausentes"
)
Variáveis que apresentam valores ausentes
Variável Quantidade de valores ausentes
resistencia_mpa 1
relacao_a_c 1
abatimento_mm 1
densidade_kg_m3 1
absorção_agregado_pct 1

Foram identificados 5 valores ausentes, distribuídos entre as variáveis resistencia_mpa, relacao_a_c, abatimento_mm, densidade_kg_m3 e absorção_agregado_pct.

Para localizar as respectivas observações, foi utilizado:

Código
dados %>%
  mutate(observacao = row_number()) %>%
  pivot_longer(
    cols = -c(observacao, id_corpo_prova),
    names_to = "variavel",
    values_to = "valor"
  ) %>%
  filter(is.na(valor)) %>%
  select(observacao, id_corpo_prova, variavel)
# A tibble: 5 × 3
  observacao id_corpo_prova variavel             
       <int> <chr>          <chr>                
1         15 CP-015         abatimento_mm        
2         38 CP-038         relacao_a_c          
3         77 CP-077         densidade_kg_m3      
4         92 CP-092         resistencia_mpa      
5         97 CP-097         absorção_agregado_pct

Os valores ausentes foram localizados nas observações 15, 38, 77, 92 e 97, correspondentes aos corpos de prova CP-015, CP-038, CP-077, CP-092 e CP-097, respectivamente.

5.7 Questão 7

A verificação dos valores potencialmente incompatíveis com o contexto da Engenharia Civil será realizada após a etapa de limpeza e conversão dos tipos das variáveis. Essa ordem permite que as variáveis inicialmente armazenadas como character sejam transformadas em valores numéricos antes da aplicação dos critérios de intervalo.

Dessa forma, após a correção das inconsistências de preenchimento e a conversão das variáveis quantitativas, será possível avaliar os valores de forma adequada, utilizando intervalos de referência para identificar observações que merecem investigação.

5.8 Questão 8

Os registros foram investigados em busca de possíveis erros de digitação ou problemas de preenchimento. Para isso, foram utilizadas as funções filter(), select() e recursos do stringr.

Código
dados %>%
  filter(
    str_detect(resistencia_mpa, "[^0-9.]") |
    str_detect(cimento_kg_m3, "[^0-9.]") |
    str_detect(relacao_a_c, ",")
  ) %>%
  select(
    id_corpo_prova,
    obra,
    tipo_concreto,
    resistencia_mpa,
    cimento_kg_m3,
    relacao_a_c
  ) %>%
  print(width = Inf)
# A tibble: 4 × 6
  id_corpo_prova obra    tipo_concreto resistencia_mpa cimento_kg_m3 relacao_a_c
  <chr>          <chr>   <chr>         <chr>           <chr>         <chr>      
1 CP-008         Bloco D C30           38,7            347           0.54       
2 CP-019         Bloco B C30           3O,4            356           0.59       
3 CP-045         Bloco C C40           42.9            407           0,55       
4 CP-064         Bloco A C30           25.6            390O          0.59       

A investigação permitiu identificar registros que apresentam caracteres ou formatos diferentes do padrão predominante da base. Entre eles, destacam-se 38,7, 3O,4, 0,55 e 390O.

Os registros que apresentam a letra O no lugar do algarismo 0, como 3O,4 e 390O, caracterizam possíveis erros de digitação. Já os valores 38,7 e 0,55 apresentam apenas uma diferença no separador decimal em relação ao padrão utilizado na maior parte da base.

Essas inconsistências devem ser corrigidas antes da conversão das variáveis para o tipo numérico.

5.9 Questão 9

As categorias da variável obra foram verificadas utilizando count() e distinct(), buscando identificar diferenças de grafia, espaços ou outras inconsistências.

Código
dados %>%
  count(obra)
# A tibble: 5 × 2
  obra           n
  <chr>      <int>
1 "Bloco A"     28
2 "Bloco B"     28
3 "Bloco B "     1
4 "Bloco C"     28
5 "Bloco D"     15

Em seguida, foram apresentadas as categorias existentes:

Código
dados %>%
  distinct(obra)
# A tibble: 5 × 1
  obra      
  <chr>     
1 "Bloco A" 
2 "Bloco C" 
3 "Bloco B" 
4 "Bloco D" 
5 "Bloco B "

A análise permitiu identificar as categorias utilizadas na variável obra e verificar possíveis diferenças de preenchimento. Foi identificada uma ocorrência de Bloco B com espaço adicional ao final do texto, que representa a mesma categoria das demais ocorrências de Bloco B.

Essa inconsistência de preenchimento deverá ser corrigida durante a etapa de padronização das variáveis qualitativas.

5.10 Questão 10

As categorias da variável tipo_concreto foram verificadas utilizando count() e distinct().

Código
dados %>%
  count(tipo_concreto)
# A tibble: 5 × 2
  tipo_concreto     n
  <chr>         <int>
1 C25              29
2 C30              31
3 C35              23
4 C40              16
5 c30               1
Código
dados %>%
  distinct(tipo_concreto)
# A tibble: 5 × 1
  tipo_concreto
  <chr>        
1 C35          
2 C30          
3 C40          
4 C25          
5 c30          

A análise das categorias permitiu identificar as diferentes formas de preenchimento da variável. Foi encontrada a categoria c30, que representa o mesmo tipo de concreto que C30, mas apresenta diferença entre letras maiúsculas e minúsculas.

Dessa forma, a categoria c30 deverá ser padronizada para C30 durante a etapa de limpeza dos dados.

5.11 Questão 11

Após a identificação dos problemas presentes na base, os tipos das variáveis foram novamente verificados por meio da função glimpse().

Código
glimpse(dados)
Rows: 100
Columns: 10
$ id_corpo_prova        <chr> "CP-001", "CP-002", "CP-003", "CP-004", "CP-005"…
$ obra                  <chr> "Bloco A", "Bloco A", "Bloco C", "Bloco A", "Blo…
$ tipo_concreto         <chr> "C35", "C30", "C30", "C40", "C25", "C40", "C25",…
$ idade_dias            <chr> "28", "7", "56", "28", "28", "28", "56", "28", "…
$ resistencia_mpa       <chr> "36.3", "28.4", "36.1", "47.2", "27.9", "41.5", …
$ cimento_kg_m3         <chr> "395", "340", "338", "407", "316", "398", "351",…
$ relacao_a_c           <chr> "0.5", "0.54", "0.56", "0.47", "0.61", "0.43", "…
$ abatimento_mm         <chr> "111.0", "114.0", "106.0", "142.0", "133.0", "98…
$ densidade_kg_m3       <chr> "2332.0", "2389.0", "2427.0", "2345.0", "2448.0"…
$ absorção_agregado_pct <chr> "2.3", "1.85", "1.89", "1.97", "2.31", "0.8", "1…

Como todas as variáveis foram importadas inicialmente como texto, elas permanecem classificadas como <chr> neste momento. Entretanto, a análise realizada nas questões anteriores mostrou que várias dessas variáveis possuem natureza quantitativa.

Um dos motivos para uma variável quantitativa ser armazenada como texto é a presença de valores que fogem ao padrão esperado, como vírgulas decimais, caracteres indevidos ou diferentes formas de preenchimento.

Um único valor digitado incorretamente pode alterar a maneira como o R interpreta uma variável inteira quando a importação depende da identificação automática dos tipos. Por esse motivo, a importação inicial como texto permite preservar os registros originais e realizar o tratamento dos problemas antes da conversão.

5.12 Questão 12

Foi criada uma cópia da base original chamada dados_limpos.

Código
dados_limpos <- dados

A preservação da base original é importante porque permite comparar os dados antes e depois das alterações, além de possibilitar a recuperação das informações originais caso alguma transformação seja realizada de forma inadequada.

Dessa forma, as alterações necessárias serão realizadas somente no objeto dados_limpos, mantendo dados como referência da base originalmente importada.

5.13 Questão 13

As variáveis qualitativas foram padronizadas utilizando funções do pacote stringr. Inicialmente, foram removidos espaços adicionais e uniformizadas as letras das categorias.

Código
dados_limpos <- dados_limpos %>%
  mutate(
    obra = str_trim(obra),
    obra = str_squish(obra),
    tipo_concreto = str_to_upper(str_trim(tipo_concreto))
  )

Após a transformação, as categorias podem ser verificadas novamente:

Código
dados_limpos %>%
  count(obra)
# A tibble: 4 × 2
  obra        n
  <chr>   <int>
1 Bloco A    28
2 Bloco B    29
3 Bloco C    28
4 Bloco D    15
Código
dados_limpos %>%
  count(tipo_concreto)
# A tibble: 4 × 2
  tipo_concreto     n
  <chr>         <int>
1 C25              29
2 C30              32
3 C35              23
4 C40              16

A utilização de str_trim() permite remover espaços no início e no final dos textos, enquanto str_squish() elimina espaços adicionais entre as palavras. A função str_to_upper() foi utilizada para uniformizar as letras da variável tipo_concreto.

Com essas transformações, categorias que representavam a mesma informação, mas apresentavam diferenças de preenchimento, passam a seguir um padrão único.

5.14 Questão 14

Após a identificação e correção das inconsistências, as variáveis que possuem natureza quantitativa foram convertidas para o tipo numérico. Para isso, foram utilizados recursos do pacote readr.

Antes da conversão, os valores que apresentam vírgula decimal ou caracteres indevidos foram corrigidos:

Código
dados_limpos <- dados_limpos %>%
  mutate(
    resistencia_mpa = str_replace_all(resistencia_mpa, "O", "0"),
    resistencia_mpa = str_replace_all(resistencia_mpa, ",", "."),
    cimento_kg_m3 = str_replace_all(cimento_kg_m3, "O", "0"),
    relacao_a_c = str_replace_all(relacao_a_c, ",", ".")
  )

Em seguida, as variáveis foram convertidas para o tipo numérico:

Código
dados_limpos <- dados_limpos %>%
  mutate(
    idade_dias = parse_integer(idade_dias),
    resistencia_mpa = parse_double(resistencia_mpa),
    cimento_kg_m3 = parse_double(cimento_kg_m3),
    relacao_a_c = parse_double(relacao_a_c),
    abatimento_mm = parse_double(abatimento_mm),
    densidade_kg_m3 = parse_double(densidade_kg_m3),
    absorção_agregado_pct = parse_double(absorção_agregado_pct)
  )

A estrutura da base foi verificada novamente para confirmar a conversão:

Código
glimpse(dados_limpos)
Rows: 100
Columns: 10
$ id_corpo_prova        <chr> "CP-001", "CP-002", "CP-003", "CP-004", "CP-005"…
$ obra                  <chr> "Bloco A", "Bloco A", "Bloco C", "Bloco A", "Blo…
$ tipo_concreto         <chr> "C35", "C30", "C30", "C40", "C25", "C40", "C25",…
$ idade_dias            <int> 28, 7, 56, 28, 28, 28, 56, 28, 14, 7, 7, 28, 28,…
$ resistencia_mpa       <dbl> 36.3, 28.4, 36.1, 47.2, 27.9, 41.5, 23.7, 38.7, …
$ cimento_kg_m3         <dbl> 395, 340, 338, 407, 316, 398, 351, 347, 346, 315…
$ relacao_a_c           <dbl> 0.50, 0.54, 0.56, 0.47, 0.61, 0.43, 0.65, 0.54, …
$ abatimento_mm         <dbl> 111, 114, 106, 142, 133, 98, 99, 116, 125, 127, …
$ densidade_kg_m3       <dbl> 2332, 2389, 2427, 2345, 2448, 2324, 2385, 2387, …
$ absorção_agregado_pct <dbl> 2.30, 1.85, 1.89, 1.97, 2.31, 0.80, 1.18, 1.33, …

A conversão permitiu que as variáveis quantitativas passassem a ser armazenadas como valores numéricos, possibilitando a realização das análises estatísticas nas etapas seguintes. Os valores ausentes permaneceram como NA, sendo tratados posteriormente de acordo com a estratégia definida para a base.

5.14.1 Verificação dos intervalos dos valores

Após a padronização e conversão das variáveis quantitativas, foram verificados valores potencialmente incompatíveis com o contexto do controle tecnológico do concreto.

Para essa análise, foram utilizados como referência os intervalos adotados no Relatório 02. Esses limites representam uma triagem inicial dos dados, permitindo identificar observações que merecem investigação, mas não determinam, isoladamente, que um valor esteja incorreto.

Os intervalos considerados foram:

Variável Intervalo de referência
idade_dias 1 a 56 dias
resistencia_mpa 20 a 60 MPa
abatimento_mm 10 a 220 mm
densidade_kg_m3 2000 a 2600 kg/m³
relacao_a_c 0,40 a 0,70
absorção_agregado_pct 0 a 10%

A verificação foi realizada utilizando filter():

Código
dados_limpos %>%
  filter(
    idade_dias <= 0 | idade_dias > 56 |
    resistencia_mpa < 20 | resistencia_mpa > 60 |
    abatimento_mm < 10 | abatimento_mm > 220 |
    densidade_kg_m3 < 2000 | densidade_kg_m3 > 2600 |
    relacao_a_c < 0.40 | relacao_a_c > 0.70 |
    absorção_agregado_pct < 0 | absorção_agregado_pct > 10
  ) %>%
  print(width = Inf)
# A tibble: 5 × 10
  id_corpo_prova obra    tipo_concreto idade_dias resistencia_mpa cimento_kg_m3
  <chr>          <chr>   <chr>              <int>           <dbl>         <dbl>
1 CP-032         Bloco D C35                   14            36.6           370
2 CP-053         Bloco D C30                   28            27.4           349
3 CP-072         Bloco B C40                   14            37.3           403
4 CP-077         Bloco D C25                   14            19             307
5 CP-085         Bloco A C30                  280            38.3           342
  relacao_a_c abatimento_mm densidade_kg_m3 absorção_agregado_pct
        <dbl>         <dbl>           <dbl>                 <dbl>
1        0.53          1250            2383                  2.13
2        0.61            97             238                  1.79
3        0.48            98            2414                 18.4 
4        0.63           119              NA                  1.38
5        0.6            141            2377                  1.86

O código permite localizar as observações que apresentam pelo menos uma variável fora dos intervalos estabelecidos. Entre os valores identificados na base estão a idade de 280 dias, o abatimento de 1250 mm, a densidade de 238 kg/m³ e a absorção de 18,4%, que apresentam grande afastamento em relação aos demais registros.

Esses valores devem ser investigados antes da utilização da base nas análises estatísticas. Entretanto, sua identificação como valores fora do intervalo não implica que sejam automaticamente erros, sendo necessário considerar o contexto do ensaio e as características da base.

5.15 Questão 15

Após a conversão das variáveis quantitativas, foi realizada uma investigação dos valores ausentes. Além dos valores NA, foram considerados registros como N/A, NULL, null, - e células vazias.

Para identificar esses registros sem alterar os tipos das variáveis em dados_limpos, foi criada uma base auxiliar:

Código
dados_ausentes <- dados_limpos %>%
  mutate(
    across(
      everything(),
      ~str_trim(as.character(.x))
    )
  ) %>%
  mutate(
    across(
      everything(),
      ~na_if(.x, "")
    )
  ) %>%
  mutate(
    across(
      everything(),
      ~ifelse(.x %in% c("NA", "N/A", "NULL", "null", "-"), NA, .x)
    )
  )

A quantidade de valores ausentes por variável foi verificada por:

Código
dados_ausentes %>%
  summarise(across(everything(), ~sum(is.na(.x)))) %>%
  pivot_longer(
    cols = everything(),
    names_to = "variavel",
    values_to = "quantidade_NA"
  ) %>%
  filter(quantidade_NA > 0)
# A tibble: 5 × 2
  variavel              quantidade_NA
  <chr>                         <int>
1 resistencia_mpa                   1
2 relacao_a_c                       1
3 abatimento_mm                     1
4 densidade_kg_m3                   1
5 absorção_agregado_pct             1

Também foram identificadas as observações que apresentam pelo menos um valor ausente:

Código
dados_ausentes %>%
  filter(if_any(everything(), is.na)) %>%
  summarise(observacoes_com_ausentes = n())
# A tibble: 1 × 1
  observacoes_com_ausentes
                     <int>
1                        5

Após a identificação, foram separadas as observações que apresentam valores ausentes:

Código
dados_excluidos <- dados_limpos %>%
  filter(if_any(everything(), is.na)) %>%
  print(width = Inf)
# A tibble: 5 × 10
  id_corpo_prova obra    tipo_concreto idade_dias resistencia_mpa cimento_kg_m3
  <chr>          <chr>   <chr>              <int>           <dbl>         <dbl>
1 CP-015         Bloco B C35                   14            36.3           363
2 CP-038         Bloco C C25                   28            25.7           309
3 CP-077         Bloco D C25                   14            19             307
4 CP-092         Bloco B C35                   14            NA             370
5 CP-097         Bloco A C25                   28            26.7           356
  relacao_a_c abatimento_mm densidade_kg_m3 absorção_agregado_pct
        <dbl>         <dbl>           <dbl>                 <dbl>
1        0.49            NA            2359                  1.93
2       NA              146            2334                  2.12
3        0.63           119              NA                  1.38
4        0.47           111            2380                  2.38
5        0.64           122            2440                 NA   
Código
dados_limpos <- dados_limpos %>%
  filter(if_all(everything(), ~!is.na(.x)))

A base dados_excluidos preserva os registros retirados da análise, enquanto dados_limpos contém somente as observações completas.

5.15.1 Justificativa

Optou-se pela exclusão das observações que apresentam pelo menos um valor ausente, evitando a criação de informações que não foram efetivamente medidas. Essa decisão é adequada à quantidade de dados disponíveis e mantém apenas observações completas para as análises posteriores.

Os registros excluídos foram preservados em dados_excluidos, garantindo a rastreabilidade do tratamento realizado. A base original dados também permanece preservada.

A utilização de uma base auxiliar para identificar os diferentes formatos de ausência evita que as variáveis numéricas de dados_limpos sejam novamente convertidas para character.

5.16 Questão 16

Após a realização das etapas de limpeza e transformação, foi verificada novamente a estrutura da base dados_limpos. Essa etapa permite confirmar se as variáveis foram convertidas para os tipos adequados e se as principais inconsistências identificadas anteriormente foram tratadas.

Código
glimpse(dados_limpos)
Rows: 95
Columns: 10
$ id_corpo_prova        <chr> "CP-001", "CP-002", "CP-003", "CP-004", "CP-005"…
$ obra                  <chr> "Bloco A", "Bloco A", "Bloco C", "Bloco A", "Blo…
$ tipo_concreto         <chr> "C35", "C30", "C30", "C40", "C25", "C40", "C25",…
$ idade_dias            <int> 28, 7, 56, 28, 28, 28, 56, 28, 14, 7, 7, 28, 28,…
$ resistencia_mpa       <dbl> 36.3, 28.4, 36.1, 47.2, 27.9, 41.5, 23.7, 38.7, …
$ cimento_kg_m3         <dbl> 395, 340, 338, 407, 316, 398, 351, 347, 346, 315…
$ relacao_a_c           <dbl> 0.50, 0.54, 0.56, 0.47, 0.61, 0.43, 0.65, 0.54, …
$ abatimento_mm         <dbl> 111, 114, 106, 142, 133, 98, 99, 116, 125, 127, …
$ densidade_kg_m3       <dbl> 2332, 2389, 2427, 2345, 2448, 2324, 2385, 2387, …
$ absorção_agregado_pct <dbl> 2.30, 1.85, 1.89, 1.97, 2.31, 0.80, 1.18, 1.33, …

A análise da estrutura permite verificar que as variáveis qualitativas permanecem como texto, enquanto as variáveis quantitativas passaram a ser reconhecidas pelo R como numéricas. Dessa forma, a base apresenta uma estrutura adequada para a realização das análises estatísticas posteriores.

Entre os principais tratamentos realizados estão:

  • padronização das variáveis qualitativas;
  • correção de diferenças de preenchimento;
  • substituição de caracteres indevidos nos valores numéricos;
  • padronização dos separadores decimais;
  • conversão das variáveis quantitativas para o tipo numérico;
  • manutenção dos valores ausentes como NA, para que sejam tratados de acordo com a estratégia definida para a análise.

A base original dados permanece preservada, enquanto dados_limpos contém as transformações realizadas durante o processo de tratamento. Essa separação permite manter a rastreabilidade das alterações e comparar os dados antes e depois da limpeza.

Portanto, após as etapas realizadas, dados_limpos apresenta uma estrutura mais consistente e adequada para as análises estatísticas seguintes.

5.17 Questão 17

A resistência média à compressão dos corpos de prova foi calculada inicialmente considerando toda a base de dados. Em seguida, a média foi calculada separadamente de acordo com o bloco da obra, o tipo de concreto e a idade do corpo de prova.

Código
# Resistência média de todos os corpos de prova
dados_limpos |>
  summarise(
    resistencia_media = mean(resistencia_mpa)
  )
# A tibble: 1 × 1
  resistencia_media
              <dbl>
1              33.8

A resistência média também foi calculada para cada bloco da obra:

Código
# Resistência média por bloco da obra
dados_limpos |>
  group_by(obra) |>
  summarise(
    resistencia_media = mean(resistencia_mpa)
  )
# A tibble: 4 × 2
  obra    resistencia_media
  <chr>               <dbl>
1 Bloco A              33.4
2 Bloco B              35.7
3 Bloco C              32.6
4 Bloco D              33.4

Em seguida, foi calculada a resistência média para cada tipo de concreto:

Código
# Resistência média por tipo de concreto
dados_limpos |>
  group_by(tipo_concreto) |>
  summarise(
    resistencia_media = mean(resistencia_mpa)
  )
# A tibble: 4 × 2
  tipo_concreto resistencia_media
  <chr>                     <dbl>
1 C25                        27.4
2 C30                        32.1
3 C35                        37.1
4 C40                        43.3

Por fim, foi calculada a resistência média para cada idade dos corpos de prova:

Código
# Resistência média por idade do corpo de prova
dados_limpos |>
  group_by(idade_dias) |>
  summarise(
    resistencia_media = mean(resistencia_mpa)
  )
# A tibble: 5 × 2
  idade_dias resistencia_media
       <int>             <dbl>
1          7              28.8
2         14              35.8
3         28              34.9
4         56              33.1
5        280              38.3

A função group_by() foi utilizada para dividir os dados de acordo com a variável de interesse, enquanto summarise() calculou a média da resistência à compressão em cada grupo. Dessa forma, é possível comparar o comportamento da resistência entre diferentes blocos da obra, tipos de concreto e idades dos corpos de prova.

Os resultados permitem observar como a resistência média varia conforme as características dos corpos de prova, possibilitando uma análise mais detalhada do comportamento do concreto na base estudada.

5.18 Questão 18

Para comparar os blocos da obra, foi calculada a resistência média à compressão para cada bloco. Em seguida, os resultados foram ordenados de forma crescente, permitindo identificar diretamente o bloco com menor e maior resistência média.

Código
comparacao_obras <- dados_limpos |>
  group_by(obra) |>
  summarise(
    resistencia_media = mean(resistencia_mpa)
  ) |>
  arrange(resistencia_media)

comparacao_obras
# A tibble: 4 × 2
  obra    resistencia_media
  <chr>               <dbl>
1 Bloco C              32.6
2 Bloco D              33.4
3 Bloco A              33.4
4 Bloco B              35.7

O resultado apresenta os blocos organizados da menor para a maior resistência média. Assim, o primeiro bloco da tabela corresponde ao bloco que apresentou a menor resistência média, enquanto o último corresponde ao bloco que apresentou a maior resistência média.

Dessa forma, a utilização conjunta de group_by(), summarise() e arrange() permite realizar a comparação entre as obras de maneira simples e objetiva, facilitando a identificação dos blocos com os maiores e menores valores médios de resistência à compressão.

5.19 Questão 19

Para comparar as classes de concreto, foram consideradas as classes C25, C30, C35 e C40. A resistência média foi calculada para cada classe e os resultados foram organizados em ordem decrescente.

Código
resultado_tipo <- dados_limpos |>
  filter(tipo_concreto %in% c("C25", "C30", "C35", "C40")) |>
  group_by(tipo_concreto) |>
  summarise(
    resistencia_media = mean(resistencia_mpa),
    .groups = "drop"
  ) |>
  arrange(desc(resistencia_media))

resultado_tipo
# A tibble: 4 × 2
  tipo_concreto resistencia_media
  <chr>                     <dbl>
1 C40                        43.3
2 C35                        37.1
3 C30                        32.1
4 C25                        27.4

A função filter() seleciona apenas as quatro classes solicitadas. Em seguida, group_by() agrupa os corpos de prova de acordo com a classe do concreto, enquanto summarise() calcula a resistência média de cada grupo. Por fim, arrange(desc()) organiza os resultados da maior para a menor resistência média.

A primeira linha do resultado corresponde à classe que apresentou a maior resistência média, permitindo identificar diretamente a classe de concreto com melhor desempenho médio entre as classes analisadas.

5.20 Questão 20

Para comparar as diferentes classes de concreto, foram calculadas as médias da resistência à compressão, do consumo de cimento, da relação água/cimento, do abatimento e da densidade para cada tipo de concreto.

Código
estatisticas_concreto <- dados_limpos |>
  group_by(tipo_concreto) |>
  summarise(
    resistencia_media = mean(resistencia_mpa),
    cimento_medio = mean(cimento_kg_m3),
    relacao_a_c_media = mean(relacao_a_c),
    abatimento_medio = mean(abatimento_mm),
    densidade_media = mean(densidade_kg_m3),
    .groups = "drop"
  ) %>%
  print(width = Inf)
# A tibble: 4 × 6
  tipo_concreto resistencia_media cimento_medio relacao_a_c_media
  <chr>                     <dbl>         <dbl>             <dbl>
1 C25                        27.4          322.             0.619
2 C30                        32.1          461.             0.568
3 C35                        37.1          379.             0.509
4 C40                        43.3          404.             0.478
  abatimento_medio densidade_media
             <dbl>           <dbl>
1             114.           2374 
2             111.           2317.
3             161.           2363.
4             105.           2362.

A utilização de group_by() permite separar os corpos de prova de acordo com o tipo de concreto. Em seguida, summarise() calcula a média de cada variável dentro de cada grupo. O argumento .groups = "drop" é utilizado para que o resultado final não permaneça agrupado.

Os resultados permitem comparar o comportamento médio das principais características do concreto entre as diferentes classes. De modo geral, espera-se que as classes de maior resistência apresentem valores médios de resistência à compressão superiores. A relação água/cimento também é uma variável importante, pois relações menores tendem a estar associadas a maiores resistências, desde que os demais fatores de dosagem e cura sejam adequados.

O consumo médio de cimento, o abatimento e a densidade permitem complementar essa avaliação. Diferenças no abatimento podem indicar diferentes características de trabalhabilidade das misturas, enquanto a densidade permite verificar se existem diferenças significativas entre os concretos analisados.

Assim, a tabela obtida possibilita avaliar conjuntamente as principais características dos diferentes tipos de concreto, identificando diferenças entre as classes e permitindo relacioná-las com o desempenho mecânico observado.

5.21 Questão 21

Foi criada a variável resistencia_relativa, representando a razão entre a resistência observada e a resistência de referência correspondente à classe do concreto.

Como critério, foi considerada a resistência nominal indicada pela classe do concreto: 25 MPa para C25, 30 MPa para C30, 35 MPa para C35 e 40 MPa para C40.

Código
dados_limpos <- dados_limpos |>
  mutate(
    resistencia_relativa = resistencia_mpa /
      case_when(
        tipo_concreto == "C25" ~ 25,
        tipo_concreto == "C30" ~ 30,
        tipo_concreto == "C35" ~ 35,
        tipo_concreto == "C40" ~ 40,
        TRUE ~ NA_real_
      )
  )

# Apresentação de apenas algumas observações para facilitar a visualização
dados_limpos |>
  select(
    id_corpo_prova,
    tipo_concreto,
    resistencia_mpa,
    resistencia_relativa
  ) |>
  slice_head(n = 10)
# A tibble: 10 × 4
   id_corpo_prova tipo_concreto resistencia_mpa resistencia_relativa
   <chr>          <chr>                   <dbl>                <dbl>
 1 CP-001         C35                      36.3                1.04 
 2 CP-002         C30                      28.4                0.947
 3 CP-003         C30                      36.1                1.20 
 4 CP-004         C40                      47.2                1.18 
 5 CP-005         C25                      27.9                1.12 
 6 CP-006         C40                      41.5                1.04 
 7 CP-007         C25                      23.7                0.948
 8 CP-008         C30                      38.7                1.29 
 9 CP-009         C30                      30.3                1.01 
10 CP-010         C25                      25.3                1.01 

Foi apresentada somente uma amostra das observações no relatório para evitar excesso de informações e poluição visual, facilitando a compreensão do procedimento e da nova variável criada. Entretanto, o cálculo de resistencia_relativa foi realizado para todas as observações da base dados_limpos.

A função case_when() associa cada classe de concreto ao seu respectivo valor de referência. Em seguida, mutate() calcula a razão entre a resistência observada e a resistência de referência.

A interpretação é feita da seguinte forma: um valor de resistencia_relativa igual a 1,00 indica que a resistência observada corresponde à resistência de referência da classe. Valores maiores que 1,00 indicam resistência observada superior à referência, enquanto valores menores que 1,00 indicam resistência inferior à referência.

Por exemplo, um corpo de prova C35 com resistência de 36,3 MPa apresenta resistência relativa de aproximadamente 1,04, indicando que sua resistência corresponde a aproximadamente 104% da resistência de referência de 35 MPa.

A resistência nominal da classe foi utilizada como referência por representar o valor associado à classificação do concreto, permitindo avaliar o desempenho observado de cada corpo de prova em relação à sua própria classe.

5.22 Questão 22

[Para classificar os corpos de prova, foi utilizada a variável resistencia_relativa, criada na questão anterior. Dessa forma, cada resistência observada é comparada com a resistência de referência correspondente à sua classe de concreto.

Foram adotados os seguintes critérios:

  • Igual ou superior à referência: resistencia_relativa >= 1,00;
  • Próxima da referência: 0,90 <= resistencia_relativa < 1,00;
  • Abaixo da referência: resistencia_relativa < 0,90.
Código
dados_limpos <- dados_limpos |>
  mutate(
    classificacao = case_when(
      resistencia_relativa >= 1.00 ~ "Igual ou superior à referência",
      resistencia_relativa >= 0.90 ~ "Próxima da referência",
      resistencia_relativa < 0.90 ~ "Abaixo da referência",
      TRUE ~ NA_character_
    )
  )

# Tabela para apresentação dos resultados
tabela_classificacao <- dados_limpos |>
  select(
    id_corpo_prova,
    tipo_concreto,
    resistencia_mpa,
    resistencia_relativa,
    classificacao
  )

knitr::kable(
  head(tabela_classificacao, 95),
  digits = 3,
  col.names = c(
    "Corpo de prova",
    "Tipo de concreto",
    "Resistência (MPa)",
    "Resistência relativa",
    "Classificação"
  ),
  caption = "Classificação dos corpos de prova segundo a resistência relativa."
)
Classificação dos corpos de prova segundo a resistência relativa.
Corpo de prova Tipo de concreto Resistência (MPa) Resistência relativa Classificação
CP-001 C35 36.3 1.037 Igual ou superior à referência
CP-002 C30 28.4 0.947 Próxima da referência
CP-003 C30 36.1 1.203 Igual ou superior à referência
CP-004 C40 47.2 1.180 Igual ou superior à referência
CP-005 C25 27.9 1.116 Igual ou superior à referência
CP-006 C40 41.5 1.038 Igual ou superior à referência
CP-007 C25 23.7 0.948 Próxima da referência
CP-008 C30 38.7 1.290 Igual ou superior à referência
CP-009 C30 30.3 1.010 Igual ou superior à referência
CP-010 C25 25.3 1.012 Igual ou superior à referência
CP-011 C30 31.8 1.060 Igual ou superior à referência
CP-012 C40 39.4 0.985 Próxima da referência
CP-013 C35 35.6 1.017 Igual ou superior à referência
CP-014 C35 39.4 1.126 Igual ou superior à referência
CP-016 C25 28.7 1.148 Igual ou superior à referência
CP-017 C35 38.4 1.097 Igual ou superior à referência
CP-018 C30 34.7 1.157 Igual ou superior à referência
CP-019 C30 30.4 1.013 Igual ou superior à referência
CP-020 C40 41.7 1.042 Igual ou superior à referência
CP-021 C30 28.8 0.960 Próxima da referência
CP-022 C40 45.2 1.130 Igual ou superior à referência
CP-023 C30 35.5 1.183 Igual ou superior à referência
CP-024 C40 44.7 1.118 Igual ou superior à referência
CP-025 C25 27.2 1.088 Igual ou superior à referência
CP-026 C25 24.4 0.976 Próxima da referência
CP-027 C30 39.4 1.313 Igual ou superior à referência
CP-028 C30 33.6 1.120 Igual ou superior à referência
CP-029 C25 23.7 0.948 Próxima da referência
CP-030 C35 44.6 1.274 Igual ou superior à referência
CP-031 C35 40.7 1.163 Igual ou superior à referência
CP-032 C35 36.6 1.046 Igual ou superior à referência
CP-033 C30 31.5 1.050 Igual ou superior à referência
CP-034 C30 28.7 0.957 Próxima da referência
CP-035 C35 41.1 1.174 Igual ou superior à referência
CP-036 C30 24.5 0.817 Abaixo da referência
CP-037 C30 36.6 1.220 Igual ou superior à referência
CP-039 C40 44.9 1.122 Igual ou superior à referência
CP-040 C25 29.4 1.176 Igual ou superior à referência
CP-041 C25 31.4 1.256 Igual ou superior à referência
CP-042 C30 32.3 1.077 Igual ou superior à referência
CP-043 C35 33.9 0.969 Próxima da referência
CP-044 C25 23.6 0.944 Próxima da referência
CP-045 C40 42.9 1.072 Igual ou superior à referência
CP-046 C30 31.8 1.060 Igual ou superior à referência
CP-047 C25 26.2 1.048 Igual ou superior à referência
CP-048 C30 32.1 1.070 Igual ou superior à referência
CP-049 C40 38.8 0.970 Próxima da referência
CP-050 C30 32.7 1.090 Igual ou superior à referência
CP-051 C30 33.1 1.103 Igual ou superior à referência
CP-052 C25 31.6 1.264 Igual ou superior à referência
CP-053 C30 27.4 0.913 Próxima da referência
CP-054 C40 42.5 1.062 Igual ou superior à referência
CP-055 C25 28.2 1.128 Igual ou superior à referência
CP-056 C35 37.9 1.083 Igual ou superior à referência
CP-057 C30 33.5 1.117 Igual ou superior à referência
CP-058 C35 33.7 0.963 Próxima da referência
CP-059 C30 29.9 0.997 Próxima da referência
CP-060 C25 29.3 1.172 Igual ou superior à referência
CP-061 C25 29.3 1.172 Igual ou superior à referência
CP-062 C25 29.5 1.180 Igual ou superior à referência
CP-063 C35 36.2 1.034 Igual ou superior à referência
CP-064 C30 25.6 0.853 Abaixo da referência
CP-065 C30 35.6 1.187 Igual ou superior à referência
CP-066 C35 41.6 1.189 Igual ou superior à referência
CP-067 C30 29.6 0.987 Próxima da referência
CP-068 C30 30.7 1.023 Igual ou superior à referência
CP-069 C35 33.6 0.960 Próxima da referência
CP-070 C25 29.8 1.192 Igual ou superior à referência
CP-071 C30 31.0 1.033 Igual ou superior à referência
CP-072 C40 37.3 0.932 Próxima da referência
CP-073 C40 46.5 1.163 Igual ou superior à referência
CP-074 C25 27.8 1.112 Igual ou superior à referência
CP-075 C35 41.8 1.194 Igual ou superior à referência
CP-076 C25 26.6 1.064 Igual ou superior à referência
CP-078 C40 46.9 1.172 Igual ou superior à referência
CP-079 C30 29.9 0.997 Próxima da referência
CP-080 C35 35.1 1.003 Igual ou superior à referência
CP-081 C40 47.5 1.188 Igual ou superior à referência
CP-082 C40 43.4 1.085 Igual ou superior à referência
CP-083 C25 28.0 1.120 Igual ou superior à referência
CP-084 C25 23.3 0.932 Próxima da referência
CP-085 C30 38.3 1.277 Igual ou superior à referência
CP-086 C35 30.1 0.860 Abaixo da referência
CP-087 C25 27.8 1.112 Igual ou superior à referência
CP-088 C35 36.9 1.054 Igual ou superior à referência
CP-089 C25 28.3 1.132 Igual ou superior à referência
CP-090 C30 33.1 1.103 Igual ou superior à referência
CP-091 C35 39.6 1.131 Igual ou superior à referência
CP-093 C40 42.9 1.072 Igual ou superior à referência
CP-094 C35 29.9 0.854 Abaixo da referência
CP-095 C25 30.3 1.212 Igual ou superior à referência
CP-096 C25 21.3 0.852 Abaixo da referência
CP-098 C35 37.0 1.057 Igual ou superior à referência
CP-099 C25 31.1 1.244 Igual ou superior à referência
CP-100 C30 30.9 1.030 Igual ou superior à referência

A função mutate() foi utilizada para criar a variável classificacao, enquanto case_when() permite aplicar diferentes critérios de acordo com o valor de resistencia_relativa.

O valor 1,00 representa 100% da resistência de referência da classe. Portanto, valores iguais ou superiores a 1,00 indicam resistência observada igual ou superior à referência. Valores entre 0,90 e 1,00 foram considerados próximos da referência, enquanto valores inferiores a 0,90 foram classificados como abaixo da referência.

O limite de 10% foi adotado como critério analítico para esta atividade, permitindo diferenciar resultados próximos da referência daqueles que apresentam uma redução mais significativa. Esse critério não deve ser interpretado como um critério normativo de aceitação do concreto, mas como uma forma de organizar e interpretar os resultados da base de dados.

5.23 Questão 23

Foi criada a variável acima_media, indicando se a resistência à compressão de cada corpo de prova está acima da resistência média de seu respectivo tipo de concreto.

Para isso, os dados foram agrupados por tipo_concreto e a média de resistência foi calculada automaticamente dentro de cada grupo.

Código
dados_limpos <- dados_limpos |>
  group_by(tipo_concreto) |>
  mutate(
    acima_media = resistencia_mpa > mean(resistencia_mpa)
  ) |>
  ungroup()

# Apresentação dos resultados
dados_limpos |>
  select(
    id_corpo_prova,
    tipo_concreto,
    resistencia_mpa,
    acima_media
  ) |>
  head(95) |>
  knitr::kable(
    digits = 2,
    col.names = c(
      "Corpo de prova",
      "Tipo de concreto",
      "Resistência (MPa)",
      "Acima da média"
    ),
    caption = "Classificação da resistência em relação à média do tipo de concreto."
  )
Classificação da resistência em relação à média do tipo de concreto.
Corpo de prova Tipo de concreto Resistência (MPa) Acima da média
CP-001 C35 36.3 FALSE
CP-002 C30 28.4 FALSE
CP-003 C30 36.1 TRUE
CP-004 C40 47.2 TRUE
CP-005 C25 27.9 TRUE
CP-006 C40 41.5 FALSE
CP-007 C25 23.7 FALSE
CP-008 C30 38.7 TRUE
CP-009 C30 30.3 FALSE
CP-010 C25 25.3 FALSE
CP-011 C30 31.8 FALSE
CP-012 C40 39.4 FALSE
CP-013 C35 35.6 FALSE
CP-014 C35 39.4 TRUE
CP-016 C25 28.7 TRUE
CP-017 C35 38.4 TRUE
CP-018 C30 34.7 TRUE
CP-019 C30 30.4 FALSE
CP-020 C40 41.7 FALSE
CP-021 C30 28.8 FALSE
CP-022 C40 45.2 TRUE
CP-023 C30 35.5 TRUE
CP-024 C40 44.7 TRUE
CP-025 C25 27.2 FALSE
CP-026 C25 24.4 FALSE
CP-027 C30 39.4 TRUE
CP-028 C30 33.6 TRUE
CP-029 C25 23.7 FALSE
CP-030 C35 44.6 TRUE
CP-031 C35 40.7 TRUE
CP-032 C35 36.6 FALSE
CP-033 C30 31.5 FALSE
CP-034 C30 28.7 FALSE
CP-035 C35 41.1 TRUE
CP-036 C30 24.5 FALSE
CP-037 C30 36.6 TRUE
CP-039 C40 44.9 TRUE
CP-040 C25 29.4 TRUE
CP-041 C25 31.4 TRUE
CP-042 C30 32.3 TRUE
CP-043 C35 33.9 FALSE
CP-044 C25 23.6 FALSE
CP-045 C40 42.9 FALSE
CP-046 C30 31.8 FALSE
CP-047 C25 26.2 FALSE
CP-048 C30 32.1 TRUE
CP-049 C40 38.8 FALSE
CP-050 C30 32.7 TRUE
CP-051 C30 33.1 TRUE
CP-052 C25 31.6 TRUE
CP-053 C30 27.4 FALSE
CP-054 C40 42.5 FALSE
CP-055 C25 28.2 TRUE
CP-056 C35 37.9 TRUE
CP-057 C30 33.5 TRUE
CP-058 C35 33.7 FALSE
CP-059 C30 29.9 FALSE
CP-060 C25 29.3 TRUE
CP-061 C25 29.3 TRUE
CP-062 C25 29.5 TRUE
CP-063 C35 36.2 FALSE
CP-064 C30 25.6 FALSE
CP-065 C30 35.6 TRUE
CP-066 C35 41.6 TRUE
CP-067 C30 29.6 FALSE
CP-068 C30 30.7 FALSE
CP-069 C35 33.6 FALSE
CP-070 C25 29.8 TRUE
CP-071 C30 31.0 FALSE
CP-072 C40 37.3 FALSE
CP-073 C40 46.5 TRUE
CP-074 C25 27.8 TRUE
CP-075 C35 41.8 TRUE
CP-076 C25 26.6 FALSE
CP-078 C40 46.9 TRUE
CP-079 C30 29.9 FALSE
CP-080 C35 35.1 FALSE
CP-081 C40 47.5 TRUE
CP-082 C40 43.4 TRUE
CP-083 C25 28.0 TRUE
CP-084 C25 23.3 FALSE
CP-085 C30 38.3 TRUE
CP-086 C35 30.1 FALSE
CP-087 C25 27.8 TRUE
CP-088 C35 36.9 FALSE
CP-089 C25 28.3 TRUE
CP-090 C30 33.1 TRUE
CP-091 C35 39.6 TRUE
CP-093 C40 42.9 FALSE
CP-094 C35 29.9 FALSE
CP-095 C25 30.3 TRUE
CP-096 C25 21.3 FALSE
CP-098 C35 37.0 FALSE
CP-099 C25 31.1 TRUE
CP-100 C30 30.9 FALSE

A função group_by() foi utilizada para separar os corpos de prova de acordo com o tipo_concreto. Em seguida, mutate() calcula a média da resistência dentro de cada grupo e compara cada valor observado com essa média.

A expressão resistencia_mpa > mean(resistencia_mpa) retorna diretamente um valor lógico: TRUE quando a resistência do corpo de prova está acima da média de seu tipo de concreto e FALSE quando está igual ou abaixo da média.

O procedimento atende ao desafio proposto, pois as médias de cada classe não foram calculadas manualmente. O próprio group_by() faz a separação dos grupos e mean() calcula automaticamente a média correspondente a cada tipo de concreto.

5.24 Questão 24

Para determinar a quantidade de corpos de prova em cada tipo de concreto, os dados foram agrupados pela variável tipo_concreto. Em seguida, foi utilizada a função summarise() com n() para contar o número de observações pertencentes a cada grupo.

Código
observacoes_tipo <- dados_limpos |>
  group_by(tipo_concreto) |>
  summarise(
    quantidade = n(),
    .groups = "drop"
  )

knitr::kable(
  observacoes_tipo,
  col.names = c("Tipo de concreto", "Quantidade de observações"),
  caption = "Quantidade de observações por tipo de concreto."
)
Quantidade de observações por tipo de concreto.
Tipo de concreto Quantidade de observações
C25 26
C30 32
C35 21
C40 16

A função group_by() organiza as observações de acordo com o tipo de concreto, enquanto summarise() permite calcular a quantidade de registros de cada grupo. A função n() realiza a contagem das observações.

O resultado é apresentado em uma tabela para facilitar a visualização e comparação da quantidade de corpos de prova existentes em cada classe de concreto.

5.25 Questão 25

Calculando a resistência média de cada tipo de concreto. Group_by() agrupa as observações de acordo com o tipo de concreto. Summarise() calcula a resistência média de cada grupo. Arrange() ordena os resultados da menor para a maior resistência média.

Código
resistencia_media_tipo <- dados_limpos |>
  group_by(tipo_concreto) |>
  summarise(
    resistencia_media = mean(resistencia_mpa),
    .groups = "drop"
  ) |>
  arrange(resistencia_media)

# Apresentando os resultados em uma tabela organizada.
knitr::kable(
  resistencia_media_tipo,
  digits = 2,
  col.names = c(
    "Tipo de concreto",
    "Resistência média (MPa)"
  ),
  caption = "Resistência média por tipo de concreto."
)
Resistência média por tipo de concreto.
Tipo de concreto Resistência média (MPa)
C25 27.45
C30 32.08
C35 37.14
C40 43.33

O resultado apresenta a resistência média de cada tipo de concreto. A função arrange() organiza os tipos de concreto em ordem crescente, permitindo identificar aquele que apresenta a menor e a maior resistência média na base analisada.

5.26 Questão 26

Para cada tipo de concreto, foram calculadas simultaneamente diferentes estatísticas da variável resistencia_mpa, utilizando group_by() para separar os grupos e summarise() para obter o número de observações, a média, a mediana, o desvio-padrão, o valor mínimo e o valor máximo.

Código
estatisticas_resistencia <- dados_limpos |>
  group_by(tipo_concreto) |>
  summarise(
    quantidade = n(),
    media = mean(resistencia_mpa),
    mediana = median(resistencia_mpa),
    desvio_padrao = sd(resistencia_mpa),
    minimo = min(resistencia_mpa),
    maximo = max(resistencia_mpa),
    .groups = "drop"
  )

knitr::kable(
  estatisticas_resistencia,
  digits = 2,
  col.names = c(
    "Tipo de concreto",
    "Nº de observações",
    "Média (MPa)",
    "Mediana (MPa)",
    "Desvio-padrão (MPa)",
    "Mínimo (MPa)",
    "Máximo (MPa)"
  ),
  caption = "Estatísticas da resistência à compressão por tipo de concreto."
)
Estatísticas da resistência à compressão por tipo de concreto.
Tipo de concreto Nº de observações Média (MPa) Mediana (MPa) Desvio-padrão (MPa) Mínimo (MPa) Máximo (MPa)
C25 26 27.45 27.95 2.77 21.3 31.6
C30 32 32.08 31.80 3.57 24.5 39.4
C35 21 37.14 36.90 3.77 29.9 44.6
C40 16 43.33 43.15 3.08 37.3 47.5

A tabela permite uma análise mais completa da resistência à compressão, pois a média representa o valor central dos resultados, enquanto a mediana permite verificar o comportamento do valor central sem sofrer tanta influência de valores extremos. O desvio-padrão informa a variabilidade dos resultados, e os valores mínimo e máximo mostram a amplitude das resistências observadas. Além disso, o número de observações indica a quantidade de dados utilizada em cada grupo.

Assim, apresentar várias estatísticas é mais informativo do que utilizar apenas a média, pois permite avaliar simultaneamente tendência central, dispersão e amplitude dos resultados, proporcionando uma caracterização mais adequada da resistência de cada tipo de concreto.

5.27 Questão 27

Selecionando somente as variáveis quantitativas relacionadas às propriedades do concreto. A função select() permite escolher as variáveis que serão mantidas na tabela.

Código
# Selecionando somente as variáveis quantitativas.
# select() seleciona as variáveis que serão mantidas.
# where(is.numeric) seleciona automaticamente as variáveis numéricas.

propriedades_concreto <- dados_limpos |>
  select(where(is.numeric))

# Apresentando a nova tabela.
knitr::kable(
  propriedades_concreto,
  digits = 2,
  caption = "Variáveis quantitativas relacionadas às propriedades do concreto."
)
Variáveis quantitativas relacionadas às propriedades do concreto.
idade_dias resistencia_mpa cimento_kg_m3 relacao_a_c abatimento_mm densidade_kg_m3 absorção_agregado_pct resistencia_relativa
28 36.3 395 0.50 111 2332 2.30 1.04
7 28.4 340 0.54 114 2389 1.85 0.95
56 36.1 338 0.56 106 2427 1.89 1.20
28 47.2 407 0.47 142 2345 1.97 1.18
28 27.9 316 0.61 133 2448 2.31 1.12
28 41.5 398 0.43 98 2324 0.80 1.04
56 23.7 351 0.65 99 2385 1.18 0.95
28 38.7 347 0.54 116 2387 1.33 1.29
14 30.3 346 0.54 125 2328 2.92 1.01
7 25.3 315 0.60 127 2413 1.94 1.01
7 31.8 340 0.58 95 2374 1.01 1.06
28 39.4 396 0.44 114 2374 1.96 0.98
28 35.6 379 0.50 123 2339 1.79 1.02
28 39.4 394 0.52 121 2372 1.19 1.13
28 28.7 325 0.60 175 2326 1.53 1.15
14 38.4 363 0.52 109 2348 1.40 1.10
28 34.7 344 0.56 118 2414 1.62 1.16
28 30.4 356 0.59 83 2360 0.89 1.01
14 41.7 412 0.48 107 2378 1.66 1.04
28 28.8 361 0.58 116 2451 1.36 0.96
28 45.2 409 0.48 113 2360 1.92 1.13
28 35.5 343 0.54 101 2363 1.83 1.18
28 44.7 418 0.45 124 2363 1.94 1.12
28 27.2 302 0.62 107 2381 2.54 1.09
7 24.4 307 0.63 112 2364 1.99 0.98
28 39.4 365 0.57 102 2413 2.10 1.31
28 33.6 343 0.58 104 2324 2.13 1.12
7 23.7 330 0.63 100 2347 2.09 0.95
56 44.6 378 0.56 122 2386 1.93 1.27
28 40.7 381 0.54 103 2387 1.75 1.16
14 36.6 370 0.53 1250 2383 2.13 1.05
28 31.5 344 0.54 132 2374 2.06 1.05
7 28.7 345 0.58 110 2345 0.91 0.96
56 41.1 381 0.50 103 2324 2.03 1.17
7 24.5 355 0.56 93 2373 2.39 0.82
56 36.6 369 0.55 118 2380 2.41 1.22
28 44.9 404 0.46 120 2385 2.57 1.12
28 29.4 345 0.62 89 2401 2.08 1.18
28 31.4 317 0.61 100 2390 2.33 1.26
56 32.3 351 0.56 108 2385 1.34 1.08
14 33.9 356 0.51 107 2293 1.31 0.97
28 23.6 327 0.61 127 2396 2.62 0.94
14 42.9 407 0.55 76 2381 2.12 1.07
28 31.8 342 0.59 131 2434 1.42 1.06
28 26.2 325 0.65 83 2325 2.02 1.05
7 32.1 351 0.59 127 2390 2.35 1.07
28 38.8 414 0.48 103 2376 1.48 0.97
14 32.7 355 0.57 142 2344 1.99 1.09
28 33.1 352 0.55 82 2316 0.94 1.10
7 31.6 318 0.64 93 2354 1.47 1.26
28 27.4 349 0.61 97 238 1.79 0.91
7 42.5 395 0.51 71 2391 1.11 1.06
28 28.2 320 0.59 143 2405 1.80 1.13
28 37.9 368 0.50 108 2376 2.31 1.08
56 33.5 341 0.59 85 2402 1.02 1.12
14 33.7 389 0.53 70 2387 1.76 0.96
7 29.9 340 0.58 95 2388 1.10 1.00
28 29.3 340 0.63 100 2363 1.83 1.17
28 29.3 301 0.62 103 2357 2.10 1.17
28 29.5 344 0.63 97 2350 2.01 1.18
28 36.2 385 0.51 99 2358 1.60 1.03
7 25.6 3900 0.59 114 2427 1.26 0.85
28 35.6 353 0.57 111 2334 1.18 1.19
28 41.6 372 0.51 110 2378 2.12 1.19
14 29.6 337 0.57 136 2362 1.56 0.99
7 30.7 346 0.56 126 2460 1.27 1.02
28 33.6 390 0.46 123 2360 1.71 0.96
28 29.8 345 0.63 117 2381 1.66 1.19
28 31.0 352 0.59 103 2383 1.35 1.03
14 37.3 403 0.48 98 2414 18.40 0.93
28 46.5 399 0.44 81 2315 2.06 1.16
28 27.8 300 0.62 114 2378 1.73 1.11
28 41.8 362 0.46 64 2397 2.20 1.19
56 26.6 325 0.64 147 2390 1.69 1.06
28 46.9 403 0.52 83 2310 1.50 1.17
28 29.9 365 0.54 86 2377 2.14 1.00
28 35.1 386 0.52 119 2444 2.38 1.00
28 47.5 397 0.49 146 2368 1.74 1.19
14 43.4 402 0.46 101 2354 1.80 1.08
28 28.0 315 0.64 107 2346 1.97 1.12
28 23.3 312 0.57 138 2336 1.41 0.93
280 38.3 342 0.60 141 2377 1.86 1.28
7 30.1 385 0.50 68 2334 1.48 0.86
56 27.8 324 0.65 118 2424 2.17 1.11
28 36.9 405 0.54 107 2321 2.13 1.05
14 28.3 323 0.56 102 2367 2.24 1.13
28 33.1 367 0.55 117 2464 1.87 1.10
28 39.6 365 0.49 86 2372 0.82 1.13
28 42.9 402 0.50 102 2362 1.57 1.07
7 29.9 385 0.53 135 2351 2.47 0.85
28 30.3 327 0.63 124 2334 1.55 1.21
7 21.3 295 0.59 117 2349 1.72 0.85
14 37.0 375 0.46 137 2387 2.04 1.06
56 31.1 332 0.62 81 2414 1.88 1.24
56 30.9 377 0.55 109 2346 1.13 1.03

A nova tabela contém somente as variáveis quantitativas relacionadas às propriedades do concreto, excluindo as variáveis de identificação e classificação, como id_corpo_prova, obra e tipo_concreto. Dessa forma, os dados ficam organizados para as próximas análises quantitativas.

5.28 Questão 28

Para calcular simultaneamente a média das variáveis quantitativas da base, foi utilizada a função across() em conjunto com summarise(). Dessa forma, a mesma operação é aplicada automaticamente a todas as variáveis reconhecidas pelo R como numéricas.

Código
# Calculando a média das variáveis quantitativas utilizando across().
# where(is.numeric) seleciona automaticamente as variáveis numéricas.
# mean() calcula a média de cada variável selecionada.

medias_across <- dados_limpos |>
  summarise(
    across(
      where(is.numeric),
      ~mean(.x, na.rm = TRUE)
    )
  )

# Apresentando os resultados.

knitr::kable(
  medias_across,
  digits = 2,
  caption = "Média das variáveis quantitativas utilizando across()."
)
Média das variáveis quantitativas utilizando across().
idade_dias resistencia_mpa cimento_kg_m3 relacao_a_c abatimento_mm densidade_kg_m3 absorção_agregado_pct resistencia_relativa
28.44 33.83 395.44 0.55 121.58 2350.34 1.95 1.08

Para comparação, as médias também podem ser calculadas individualmente com summarise(), sendo necessário indicar cada variável separadamente:

Código
medias_individuais <- dados_limpos |>
  summarise(
    idade_dias = mean(idade_dias, na.rm = TRUE),
    resistencia_mpa = mean(resistencia_mpa, na.rm = TRUE),
    cimento_kg_m3 = mean(cimento_kg_m3, na.rm = TRUE),
    relacao_a_c = mean(relacao_a_c, na.rm = TRUE),
    abatimento_mm = mean(abatimento_mm, na.rm = TRUE),
    densidade_kg_m3 = mean(densidade_kg_m3, na.rm = TRUE),
    absorção_agregado_pct = mean(absorção_agregado_pct, na.rm = TRUE),
    resistencia_relativa = mean(resistencia_relativa, na.rm = TRUE)
  )

knitr::kable(
  medias_individuais,
  digits = 2,
  caption = "Média das variáveis quantitativas utilizando summarise()."
)
Média das variáveis quantitativas utilizando summarise().
idade_dias resistencia_mpa cimento_kg_m3 relacao_a_c abatimento_mm densidade_kg_m3 absorção_agregado_pct resistencia_relativa
28.44 33.83 395.44 0.55 121.58 2350.34 1.95 1.08

Os dois procedimentos permitem obter as médias das variáveis quantitativas. Entretanto, across() torna o código mais prático e reduz a repetição, pois aplica automaticamente a mesma função a todas as variáveis numéricas da base. Dessa forma, caso novas variáveis quantitativas sejam adicionadas, elas também poderão ser incluídas no cálculo sem a necessidade de especificá-las individualmente.

5.29 Questão 29

Para realizar uma transformação simultânea nas variáveis quantitativas, foi utilizada a combinação das funções mutate() e across(). Nesse caso, foi realizada a padronização dos valores, subtraindo a média da variável e dividindo o resultado pelo seu desvio-padrão.

Código
# Padronizando simultaneamente as variáveis quantitativas.
# mutate() cria ou modifica variáveis na base de dados.
# across() aplica a mesma transformação a todas as variáveis numéricas.
# A padronização transforma os valores para uma escala comum.

dados_padronizados <- dados_limpos |>
  mutate(
    across(
      where(is.numeric),
      ~(.x - mean(.x, na.rm = TRUE)) / sd(.x, na.rm = TRUE)
    )
  )

# Apresentando os primeiros registros após a transformação.

knitr::kable(
  head(dados_padronizados),
  digits = 2,
  caption = "Variáveis quantitativas após a padronização."
)
Variáveis quantitativas após a padronização.
id_corpo_prova obra tipo_concreto idade_dias resistencia_mpa cimento_kg_m3 relacao_a_c abatimento_mm densidade_kg_m3 absorção_agregado_pct resistencia_relativa classificacao acima_media
CP-001 Bloco A C35 -0.01 0.39 0.00 -0.94 -0.09 -0.08 0.20 -0.38 Igual ou superior à referência FALSE
CP-002 Bloco A C30 -0.73 -0.85 -0.15 -0.24 -0.06 0.17 -0.06 -1.22 Próxima da referência FALSE
CP-003 Bloco C C30 0.93 0.36 -0.16 0.11 -0.13 0.35 -0.04 1.17 Igual ou superior à referência TRUE
CP-004 Bloco A C40 -0.01 2.09 0.03 -1.46 0.17 -0.02 0.01 0.95 Igual ou superior à referência TRUE
CP-005 Bloco B C25 -0.01 -0.93 -0.22 0.99 0.10 0.44 0.20 0.36 Igual ou superior à referência TRUE
CP-006 Bloco B C40 -0.01 1.20 0.01 -2.16 -0.20 -0.12 -0.65 -0.37 Igual ou superior à referência FALSE

A padronização transforma as variáveis para uma escala comum, na qual a média passa a ser aproximadamente 0 e o desvio-padrão aproximadamente 1. Assim, os valores indicam quantos desvios-padrão cada observação está acima ou abaixo da média.

Essa transformação é útil para comparar variáveis que apresentam unidades e escalas diferentes, evitando que uma variável com valores numericamente maiores tenha maior influência apenas por sua escala. O uso conjunto de mutate() e across() torna o procedimento mais prático, pois permite aplicar a mesma transformação simultaneamente a todas as variáveis quantitativas.

5.30 Questão 30

Para comparar as variáveis quantitativas entre os diferentes tipos de concreto, foram calculadas a média e o desvio-padrão de cada variável dentro de cada grupo. Para isso, foi utilizada a combinação das funções group_by(), summarise() e across().

Código
# Calculando a média e o desvio-padrão das variáveis quantitativas
# para cada tipo de concreto.
# group_by() separa as observações por tipo de concreto.
# summarise() calcula as estatísticas para cada grupo.
# across() aplica as mesmas funções a todas as variáveis numéricas.

estatisticas_tipo <- dados_limpos |>
  group_by(tipo_concreto) |>
  summarise(
    across(
      where(is.numeric),
      list(
        media = ~mean(.x, na.rm = TRUE),
        desvio_padrao = ~sd(.x, na.rm = TRUE)
      )
    ),
    .groups = "drop"
  )

# Apresentando os resultados em uma tabela.

knitr::kable(
  estatisticas_tipo,
  digits = 2,
  caption = "Média e desvio-padrão das variáveis quantitativas por tipo de concreto."
)
Média e desvio-padrão das variáveis quantitativas por tipo de concreto.
tipo_concreto idade_dias_media idade_dias_desvio_padrao resistencia_mpa_media resistencia_mpa_desvio_padrao cimento_kg_m3_media cimento_kg_m3_desvio_padrao relacao_a_c_media relacao_a_c_desvio_padrao abatimento_mm_media abatimento_mm_desvio_padrao densidade_kg_m3_media densidade_kg_m3_desvio_padrao absorção_agregado_pct_media absorção_agregado_pct_desvio_padrao resistencia_relativa_media resistencia_relativa_desvio_padrao
C25 27.73 14.88 27.45 2.77 322.35 14.84 0.62 0.02 113.58 21.58 2374.00 31.90 1.92 0.35 1.10 0.11
C30 33.69 47.69 32.08 3.57 461.12 627.60 0.57 0.02 110.72 16.55 2316.53 381.21 1.63 0.52 1.07 0.12
C35 25.33 12.81 37.14 3.77 379.24 12.41 0.51 0.03 160.71 250.39 2363.29 33.09 1.85 0.43 1.06 0.11
C40 23.19 7.55 43.33 3.08 404.12 6.67 0.48 0.03 104.94 21.55 2362.50 28.02 2.79 4.18 1.08 0.08

A utilização de across() permite aplicar simultaneamente as funções de média e desvio-padrão a todas as variáveis quantitativas, enquanto group_by() possibilita realizar os cálculos separadamente para cada tipo de concreto. Dessa forma, é possível comparar tanto os valores médios quanto a variabilidade das variáveis entre os diferentes grupos.

Essa abordagem torna o código mais compacto e facilita sua manutenção, principalmente quando a base possui um número maior de variáveis quantitativas.

5.31 Questão 31

Para verificar e padronizar os valores da variável obra, foram utilizados os dados originais da base, antes da etapa de limpeza. Essa análise permite identificar possíveis diferenças de preenchimento, como espaços adicionais e variações entre letras maiúsculas e minúsculas.

Inicialmente, foram apresentadas as categorias distintas e o comprimento de cada texto. Em seguida, foram aplicadas as funções str_trim() e str_to_upper() para padronizar os valores.

Código
# Verificando os valores originais da variável obra.
# distinct() apresenta as categorias diferentes existentes.
# str_length() permite verificar o comprimento dos textos.

obra_antes <- dados |>
  distinct(obra) |>
  mutate(
    comprimento = str_length(obra)
  )

knitr::kable(
  obra_antes,
  caption = "Valores da variável obra antes da padronização."
)
Valores da variável obra antes da padronização.
obra comprimento
Bloco A 7
Bloco C 7
Bloco B 7
Bloco D 7
Bloco B 8

Após a identificação dos valores originais, foi realizada a padronização da variável:

Código
# Padronizando os valores da variável obra.
# str_trim() remove espaços no início e no final dos textos.
# str_to_upper() converte todos os caracteres para letras maiúsculas.

dados_padronizados <- dados |>
  mutate(
    obra = obra |>
      str_trim() |>
      str_to_upper()
  )

# Verificando as categorias após a padronização.

obra_depois <- dados_padronizados |>
  distinct(obra) |>
  mutate(
    comprimento = str_length(obra)
  )

knitr::kable(
  obra_depois,
  caption = "Valores da variável obra após a padronização."
)
Valores da variável obra após a padronização.
obra comprimento
BLOCO A 7
BLOCO C 7
BLOCO B 7
BLOCO D 7

A utilização dos dados originais permite identificar as inconsistências de preenchimento antes que elas sejam alteradas durante a limpeza. As funções str_trim() e str_to_upper() uniformizam a apresentação dos valores, evitando que diferenças de espaços ou de capitalização façam com que uma mesma categoria seja interpretada como categorias distintas.

Dessa forma, a padronização contribui para melhorar a consistência da variável obra e torna sua utilização nas análises posteriores mais adequada.

5.32 Questão 32

Para localizar registros que contenham determinados padrões textuais nas variáveis tipo_concreto e obra, foi utilizada a função str_detect() do pacote stringr. A busca foi realizada para identificar ocorrências de C30 em tipo_concreto ou de Bloco B em obra.

Código
# Localizando registros que contenham os padrões textuais especificados.
# str_detect() verifica a presença de determinado padrão no texto.
# regex() permite realizar a busca sem diferenciar letras maiúsculas
# e minúsculas.
# filter() seleciona os registros que atendem a pelo menos uma condição.

registros_padrao <- dados_limpos |>
  filter(
    str_detect(tipo_concreto, regex("C30", ignore_case = TRUE)) |
    str_detect(obra, regex("Bloco B", ignore_case = TRUE))
  ) |>
  select(
    id_corpo_prova,
    obra,
    tipo_concreto
  )

# Apresentando os registros encontrados.

knitr::kable(
  registros_padrao,
  caption = "Registros contendo os padrões textuais pesquisados."
)
Registros contendo os padrões textuais pesquisados.
id_corpo_prova obra tipo_concreto
CP-002 Bloco A C30
CP-003 Bloco C C30
CP-005 Bloco B C25
CP-006 Bloco B C40
CP-008 Bloco D C30
CP-009 Bloco B C30
CP-011 Bloco C C30
CP-013 Bloco B C35
CP-014 Bloco B C35
CP-017 Bloco B C35
CP-018 Bloco B C30
CP-019 Bloco B C30
CP-020 Bloco B C40
CP-021 Bloco A C30
CP-023 Bloco C C30
CP-027 Bloco B C30
CP-028 Bloco D C30
CP-030 Bloco B C35
CP-033 Bloco C C30
CP-034 Bloco C C30
CP-035 Bloco B C35
CP-036 Bloco C C30
CP-037 Bloco B C30
CP-040 Bloco B C25
CP-042 Bloco B C30
CP-046 Bloco D C30
CP-047 Bloco B C25
CP-048 Bloco B C30
CP-050 Bloco C C30
CP-051 Bloco C C30
CP-053 Bloco D C30
CP-056 Bloco B C35
CP-057 Bloco B C30
CP-059 Bloco B C30
CP-063 Bloco B C35
CP-064 Bloco A C30
CP-065 Bloco C C30
CP-067 Bloco C C30
CP-068 Bloco A C30
CP-071 Bloco A C30
CP-072 Bloco B C40
CP-074 Bloco B C25
CP-079 Bloco D C30
CP-080 Bloco B C35
CP-081 Bloco B C40
CP-085 Bloco A C30
CP-088 Bloco B C35
CP-090 Bloco C C30
CP-091 Bloco B C35
CP-100 Bloco A C30

A função str_detect() permite localizar registros a partir de padrões específicos dentro de variáveis textuais. Nesse caso, a utilização de ignore_case = TRUE faz com que a busca não seja afetada por diferenças entre letras maiúsculas e minúsculas. Esse recurso facilita a identificação de categorias específicas e possíveis variações no preenchimento, contribuindo para o diagnóstico e a padronização da base de dados.

5.33 Questão 33

Para comparar a distribuição da resistência à compressão entre os diferentes tipos de concreto, foi utilizado um gráfico de caixa com a função geom_boxplot().

Código
ggplot(
  dados_limpos,
  aes(
    x = tipo_concreto,
    y = resistencia_mpa,
    fill = tipo_concreto
  )
) +
  geom_boxplot(alpha = 0.8) +
  scale_fill_brewer(palette = "Set1") +
  labs(
    title = "Distribuição da resistência à compressão por tipo de concreto",
    x = "Tipo de concreto",
    y = "Resistência à compressão (MPa)",
    fill = "Tipo de concreto"
  ) +
  theme_minimal() +
  theme(
    legend.position = "none",
    plot.title = element_text(face = "bold"),
    axis.title = element_text(face = "bold")
  )

O gráfico permite comparar a mediana, a dispersão e possíveis valores discrepantes da resistência entre os diferentes tipos de concreto. A linha central representa a mediana, enquanto a caixa representa a distribuição dos valores centrais.

Observa-se que as classes apresentam diferentes distribuições de resistência, sendo esperado que concretos de maior classe apresentem valores mais elevados. A variação no tamanho das caixas também permite comparar a dispersão dos resultados entre as classes.

Dessa forma, o boxplot complementa a análise das médias, permitindo avaliar conjuntamente a tendência central e a variabilidade da resistência à compressão.

5.34 Questão 34

Para investigar a relação entre o consumo de cimento e a resistência à compressão, foi elaborado um gráfico de dispersão. Como foi identificado um valor de consumo de cimento próximo de 4000 kg/m³, muito distante dos demais valores, esse registro foi desconsiderado apenas na representação gráfica, pois prejudicava a visualização da relação entre as variáveis.

Código
dados_grafico <- dados_limpos %>%
  filter(cimento_kg_m3 < 1000)

ggplot(
  dados_grafico,
  aes(
    x = cimento_kg_m3,
    y = resistencia_mpa
  )
) +
  geom_point(alpha = 0.8) +
  geom_smooth(method = "lm", se = FALSE) +
  labs(
    title = "Relação entre consumo de cimento e resistência à compressão",
    x = "Consumo de cimento (kg/m³)",
    y = "Resistência à compressão (MPa)"
  ) +
  theme_minimal()

Com a retirada do valor discrepante apenas para fins de visualização, o gráfico permite observar melhor a relação entre as duas variáveis. A linha de tendência apresenta a direção geral dos dados, permitindo avaliar se maiores consumos de cimento tendem a estar associados a maiores resistências.

A tendência observada fornece evidência visual de uma relação positiva, embora a dispersão dos pontos indique que a resistência não depende exclusivamente do consumo de cimento.

5.35 Questão 35

Para investigar a relação entre a relação água/cimento e a resistência à compressão, foi elaborado um gráfico de dispersão utilizando ggplot2, com uma linha de tendência para facilitar a identificação do comportamento dos dados.

Código
ggplot(
  dados_limpos,
  aes(
    x = relacao_a_c,
    y = resistencia_mpa
  )
) +
  geom_point(alpha = 0.8) +
  geom_smooth(method = "lm", se = FALSE) +
  labs(
    title = "Relação entre água/cimento e resistência à compressão",
    x = "Relação água/cimento",
    y = "Resistência à compressão (MPa)"
  ) +
  theme_minimal()

O gráfico permite observar a relação entre a quantidade de água em relação ao cimento e a resistência à compressão. A linha de tendência auxilia na identificação da direção geral dos dados.

Observa-se uma tendência negativa, indicando que maiores valores da relação água/cimento tendem a estar associados a menores valores de resistência à compressão. Esse comportamento é coerente com o esperado para o concreto, embora a dispersão dos pontos mostre que outros fatores também influenciam a resistência.

A presença de pontos que se afastam do padrão geral merece investigação, pois pode indicar valores discrepantes, variações nas características dos materiais ou diferenças nas condições de produção e ensaio.

5.36 Questão 36

Para verificar, em termos descritivos, a afirmação de que os concretos utilizados no Bloco C apresentam desempenho superior aos demais blocos, foram comparadas as medidas de resistência à compressão entre as obras.

Inicialmente, foram calculadas a média, a mediana e o desvio-padrão da resistência para cada obra:

Código
resistencia_obras <- dados_limpos %>%
  group_by(obra) %>%
  summarise(
    n = n(),
    média = mean(resistencia_mpa, na.rm = TRUE),
    mediana = median(resistencia_mpa, na.rm = TRUE),
    desvio_padrao = sd(resistencia_mpa, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  arrange(desc(média))

resistencia_obras
# A tibble: 4 × 5
  obra        n média mediana desvio_padrao
  <chr>   <int> <dbl>   <dbl>         <dbl>
1 Bloco B    27  35.7    36.2          5.38
2 Bloco A    27  33.4    30.7          6.41
3 Bloco D    14  33.4    32.7          7.26
4 Bloco C    27  32.6    31.6          6.79

A distribuição dos resultados foi complementada por meio de um gráfico de caixa:

Código
ggplot(
  dados_limpos,
  aes(
    x = obra,
    y = resistencia_mpa,
    fill = obra
  )
) +
  geom_boxplot(alpha = 0.8) +
  labs(
    title = "Distribuição da resistência à compressão por obra",
    x = "Obra",
    y = "Resistência à compressão (MPa)"
  ) +
  theme_minimal() +
  theme(
    legend.position = "none",
    plot.title = element_text(face = "bold"),
    axis.title = element_text(face = "bold")
  )

A comparação dos resultados mostra que o Bloco C não apresenta o maior desempenho em resistência à compressão. Sua mediana é inferior às observadas nos Blocos B e D, enquanto sua distribuição apresenta também considerável variabilidade.

Portanto, os dados analisados não dão suporte, em termos descritivos, à afirmação de que os concretos do Bloco C apresentam desempenho superior aos demais blocos. Essa conclusão se restringe aos resultados observados na base e não envolve teste de hipótese.

5.37 Questão 37

Para analisar a relação entre a idade dos corpos de prova e a resistência à compressão, foram calculadas as médias de resistência para cada idade. O valor de 280 dias foi desconsiderado por apresentar comportamento discrepante em relação às demais observações.

Código
resistencia_idade <- dados_limpos %>%
  filter(idade_dias != 280) %>%
  group_by(idade_dias) %>%
  summarise(
    média_resistencia = mean(resistencia_mpa, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  arrange(idade_dias)

resistencia_idade
# A tibble: 4 × 2
  idade_dias média_resistencia
       <int>             <dbl>
1          7              28.8
2         14              35.8
3         28              34.9
4         56              33.1

A relação entre idade e resistência média foi representada por meio de um gráfico de linhas:

Código
ggplot(
  resistencia_idade,
  aes(
    x = idade_dias,
    y = média_resistencia
  )
) +
  geom_line() +
  geom_point(size = 3) +
  scale_y_continuous(
    limits = c(20, 50),
    breaks = seq(20, 50, by = 5)
  ) +
  labs(
    title = "Resistência média à compressão em função da idade",
    x = "Idade do corpo de prova (dias)",
    y = "Resistência média (MPa)"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold"),
    axis.title = element_text(face = "bold")
  )

Observa-se que a resistência média não apresenta crescimento contínuo com o aumento da idade. Há um aumento entre 7 e 14 dias, seguido de redução nas idades posteriores.

Esse comportamento pode ser explicado pelo fato de que a resistência do concreto é influenciada conjuntamente por diversos fatores, como a relação água/cimento, o consumo de cimento, as características dos materiais e as condições de produção e cura. Dessa forma, a idade, isoladamente, não explica toda a variação observada.

Assim, os dados indicam um ganho inicial de resistência, mas não permitem estabelecer uma relação crescente contínua entre idade e resistência para esta base.

5.38 Questão 38

Para auxiliar o engenheiro no acompanhamento da qualidade do concreto, foi construída uma tabela-resumo com a quantidade de corpos de prova, média, mediana, desvio-padrão, resistência mínima e máxima para cada tipo de concreto.

Código
resumo_engenheiro <- dados_limpos |>
  group_by(tipo_concreto) |>
  summarise(
    quantidade = n(),
    média = mean(resistencia_mpa),
    mediana = median(resistencia_mpa),
    desvio_padrao = sd(resistencia_mpa),
    mínimo = min(resistencia_mpa),
    máximo = max(resistencia_mpa),
    .groups = "drop"
  )

knitr::kable(
  resumo_engenheiro,
  digits = 2,
  col.names = c(
    "Tipo de concreto",
    "Nº de observações",
    "Média (MPa)",
    "Mediana (MPa)",
    "Desvio-padrão (MPa)",
    "Mínimo (MPa)",
    "Máximo (MPa)"
  ),
  caption = "Resumo estatístico da resistência à compressão por tipo de concreto."
)
Resumo estatístico da resistência à compressão por tipo de concreto.
Tipo de concreto Nº de observações Média (MPa) Mediana (MPa) Desvio-padrão (MPa) Mínimo (MPa) Máximo (MPa)
C25 26 27.45 27.95 2.77 21.3 31.6
C30 32 32.08 31.80 3.57 24.5 39.4
C35 21 37.14 36.90 3.77 29.9 44.6
C40 16 43.33 43.15 3.08 37.3 47.5

A quantidade de observações indica o número de corpos de prova analisados. A média e a mediana permitem avaliar a tendência central da resistência, enquanto o desvio-padrão indica sua variabilidade. Os valores mínimo e máximo mostram a amplitude dos resultados e podem indicar valores que mereçam investigação.

Essas informações, em conjunto, fornecem uma visão objetiva do comportamento e da uniformidade da resistência dos diferentes tipos de concreto.

5.39 🏆 Desafio Final

Nesta etapa final, foi desenvolvido um script integrado em R para simular a atuação de um engenheiro responsável pelo controle e tratamento de uma base de dados produzida por diferentes profissionais. Como os possíveis erros não são conhecidos previamente, o código foi organizado de forma sequencial, contemplando as etapas de inspeção, identificação de problemas, limpeza, tratamento e análise dos dados.

O objetivo é transformar a base inicialmente bruta em uma estrutura mais confiável para a realização de análises estatísticas e para a tomada de decisão na Engenharia Civil, utilizando prioritariamente ferramentas da família tidyverse.

5.39.1 Script final

O código abaixo reúne as principais etapas desenvolvidas ao longo da atividade, utilizando funções da família tidyverse para organizar, limpar, transformar e analisar os dados de forma sistemática.

# ============================================================
# DESAFIO FINAL — O ENGENHEIRO RESPONSÁVEL PELOS DADOS
# Controle tecnológico do concreto
# ============================================================


# ------------------------------------------------------------
# 1. CARREGAMENTO DOS PACOTES E IMPORTAÇÃO DA BASE
# ------------------------------------------------------------

library(tidyverse)

# Importando a base de dados.
dados <- read_csv2("base_de_dados.csv", trim_ws = FALSE)

# Inspeção inicial da base.
head(dados)
tail(dados)
glimpse(dados)

# Verificando as dimensões da base.
dim(dados)


# ------------------------------------------------------------
# 2. IDENTIFICAÇÃO DE POSSÍVEIS PROBLEMAS
# ------------------------------------------------------------

# Verificando os valores distintos das variáveis qualitativas.
dados |>
  select(id_corpo_prova, obra, tipo_concreto) |>
  map(unique)

# Procurando possíveis caracteres que indiquem erros de
# digitação ou formatação.
dados |>
  filter(
    if_any(
      everything(),
      ~ str_detect(as.character(.x), regex("O|,", ignore_case = TRUE))
    )
  )


# ------------------------------------------------------------
# 3. VERIFICAÇÃO DOS VALORES AUSENTES
# ------------------------------------------------------------

# Contando a quantidade de valores ausentes em cada variável.
dados |>
  summarise(
    across(
      everything(),
      ~ sum(is.na(.x))
    )
  ) |>
  pivot_longer(
    cols = everything(),
    names_to = "variável",
    values_to = "quantidade_na"
  ) |>
  arrange(desc(quantidade_na))


# ------------------------------------------------------------
# 4. CRIAÇÃO DA BASE PARA LIMPEZA
# ------------------------------------------------------------

# Criando uma cópia para preservar os dados originais.
dados_limpos <- dados


# ------------------------------------------------------------
# 5. PADRONIZAÇÃO DAS VARIÁVEIS QUALITATIVAS
# ------------------------------------------------------------

# Removendo espaços desnecessários e padronizando a escrita.
dados_limpos <- dados_limpos |>
  mutate(
    obra = obra |>
      str_trim() |>
      str_to_upper(),
    
    tipo_concreto = tipo_concreto |>
      str_trim() |>
      str_to_upper()
  )


# ------------------------------------------------------------
# 6. TRATAMENTO DAS VARIÁVEIS QUANTITATIVAS
# ------------------------------------------------------------

# Corrigindo erros de digitação, separadores decimais e
# convertendo as variáveis para formato numérico.
dados_limpos <- dados_limpos |>
  mutate(
    idade_dias = parse_number(as.character(idade_dias)),
    
    resistencia_mpa = as.character(resistencia_mpa) |>
      str_replace_all(",", ".") |>
      str_replace_all("O", "0") |>
      parse_number(),
    
    cimento_kg_m3 = as.character(cimento_kg_m3) |>
      str_replace_all("O", "0") |>
      parse_number(),
    
    relacao_a_c = as.character(relacao_a_c) |>
      str_replace_all(",", ".") |>
      parse_number(),
    
    abatimento_mm = parse_number(as.character(abatimento_mm)),
    
    densidade_kg_m3 = parse_number(as.character(densidade_kg_m3)),
    
    absorção_agregado_pct =
      parse_number(as.character(absorção_agregado_pct))
  )


# ------------------------------------------------------------
# 7. PADRONIZAÇÃO E TRATAMENTO DOS VALORES AUSENTES
# ------------------------------------------------------------

# Transformando diferentes representações de ausência em NA.
dados_ausentes <- dados_limpos |>
  mutate(
    across(
      everything(),
      ~ na_if(str_trim(as.character(.x)), "")
    )
  ) |>
  mutate(
    across(
      everything(),
      ~ case_when(
        .x %in% c("NA", "N/A", "NULL", "null", "-") ~ NA_character_,
        TRUE ~ .x
      )
    )
  )

# Identificando as observações que possuem valores ausentes.
dados_excluidos <- dados_ausentes |>
  filter(if_any(everything(), is.na))

# Mantendo somente as observações completas.
dados_limpos <- dados_ausentes |>
  filter(if_all(everything(), ~ !is.na(.)))


# ------------------------------------------------------------
# 8. RECONVERSÃO DAS VARIÁVEIS QUANTITATIVAS
# ------------------------------------------------------------

# Garantindo que as variáveis quantitativas estejam em formato
# numérico após o tratamento dos valores ausentes.
dados_limpos <- dados_limpos |>
  mutate(
    idade_dias = parse_number(idade_dias),
    resistencia_mpa = parse_number(resistencia_mpa),
    cimento_kg_m3 = parse_number(cimento_kg_m3),
    relacao_a_c = parse_number(relacao_a_c),
    abatimento_mm = parse_number(abatimento_mm),
    densidade_kg_m3 = parse_number(densidade_kg_m3),
    absorção_agregado_pct = parse_number(absorção_agregado_pct)
  )


# ------------------------------------------------------------
# 9. VERIFICAÇÃO DA BASE APÓS A LIMPEZA
# ------------------------------------------------------------

# Conferindo a estrutura dos dados limpos.
glimpse(dados_limpos)

# Obtendo um resumo das variáveis.
summary(dados_limpos)


# ------------------------------------------------------------
# 10. ESTATÍSTICAS DESCRITIVAS
# ------------------------------------------------------------

# Calculando estatísticas da resistência por tipo de concreto.
resumo_resistencia <- dados_limpos |>
  group_by(tipo_concreto) |>
  summarise(
    quantidade = n(),
    média = mean(resistencia_mpa),
    mediana = median(resistencia_mpa),
    desvio_padrao = sd(resistencia_mpa),
    mínimo = min(resistencia_mpa),
    máximo = max(resistencia_mpa),
    .groups = "drop"
  ) |>
  arrange(tipo_concreto)

# Apresentando os resultados em uma tabela.
knitr::kable(
  resumo_resistencia,
  digits = 2,
  caption = "Estatísticas descritivas da resistência à compressão por tipo de concreto."
)


# ------------------------------------------------------------
# 11. CRIAÇÃO DE VARIÁVEIS DERIVADAS
# ------------------------------------------------------------

# Criando uma variável com a resistência de referência de cada
# classe de concreto e calculando a resistência relativa.
dados_limpos <- dados_limpos |>
  mutate(
    resistência_referência = case_when(
      tipo_concreto == "C25" ~ 25,
      tipo_concreto == "C30" ~ 30,
      tipo_concreto == "C35" ~ 35,
      tipo_concreto == "C40" ~ 40,
      TRUE ~ NA_real_
    ),
    
    resistencia_relativa =
      resistencia_mpa / resistência_referência,
    
    classificação = case_when(
      resistencia_relativa >= 1.00 ~
        "Igual ou superior à referência",
      resistencia_relativa >= 0.90 ~
        "Próxima da referência",
      TRUE ~
        "Abaixo da referência"
    ),
    
    acima_media =
      resistencia_mpa > mean(resistencia_mpa)
  )


# ------------------------------------------------------------
# 12. INFORMAÇÕES PARA O ENGENHEIRO
# ------------------------------------------------------------

# Resumo final por tipo de concreto.
resumo_engenheiro <- dados_limpos |>
  group_by(tipo_concreto) |>
  summarise(
    quantidade = n(),
    média_resistencia = mean(resistencia_mpa),
    desvio_padrao = sd(resistencia_mpa),
    menor_resistencia = min(resistencia_mpa),
    maior_resistencia = max(resistencia_mpa),
    .groups = "drop"
  ) |>
  arrange(tipo_concreto)

knitr::kable(
  resumo_engenheiro,
  digits = 2,
  caption = "Informações para acompanhamento da qualidade do concreto."
)


# ------------------------------------------------------------
# 13. GRÁFICO 1 — RESISTÊNCIA POR TIPO DE CONCRETO
# ------------------------------------------------------------

ggplot(
  dados_limpos,
  aes(
    x = tipo_concreto,
    y = resistencia_mpa
  )
) +
  geom_boxplot() +
  labs(
    title = "Distribuição da resistência por tipo de concreto",
    x = "Tipo de concreto",
    y = "Resistência à compressão (MPa)"
  ) +
  theme_minimal()


# ------------------------------------------------------------
# 14. GRÁFICO 2 — CIMENTO X RESISTÊNCIA
# ------------------------------------------------------------

# O filtro evita que um valor muito elevado de cimento distorça
# a visualização da relação entre as variáveis.
ggplot(
  dados_limpos |>
    filter(cimento_kg_m3 < 1000),
  aes(
    x = cimento_kg_m3,
    y = resistencia_mpa
  )
) +
  geom_point() +
  geom_smooth(
    method = "lm",
    se = FALSE
  ) +
  labs(
    title = "Relação entre consumo de cimento e resistência",
    x = "Cimento (kg/m³)",
    y = "Resistência à compressão (MPa)"
  ) +
  theme_minimal()


# ------------------------------------------------------------
# 15. RESULTADO FINAL
# ------------------------------------------------------------

# Visualizando as principais informações geradas para apoiar
# o acompanhamento da qualidade do concreto.
dados_limpos |>
  count(tipo_concreto, classificação) |>
  arrange(tipo_concreto, classificação)
  

O script realiza o processamento dos dados de forma sequencial. Inicialmente, a base é importada e inspecionada para verificar suas dimensões, estrutura, tipos de variáveis e estatísticas descritivas. Em seguida, são identificados valores ausentes, erros de preenchimento, categorias despadronizadas e possíveis inconsistências nos dados.

Na etapa de limpeza, a base original é preservada no objeto dados, enquanto uma cópia chamada dados_limpos é utilizada para as correções. As variáveis qualitativas são padronizadas com str_trim() e str_to_upper(), enquanto as variáveis quantitativas são corrigidas e convertidas para o formato numérico utilizando funções como str_replace_all() e parse_number().

Após o tratamento dos valores ausentes, as observações incompletas são excluídas das análises, resultando em uma base final com dados completos. Essa etapa permite realizar os cálculos estatísticos sem a interferência de valores ausentes.

Também foram criadas variáveis derivadas para ampliar a interpretação dos dados. A variável resistencia_relativa compara a resistência observada com a resistência de referência da classe do concreto. A variável classificacao permite identificar o desempenho em relação a essa referência. Além disso, acima_media indica se a resistência de cada corpo de prova está acima da média de sua respectiva classe.

As funções do tidyverse, como filter(), mutate(), group_by(), summarise(), across(), case_when(), if_any(), if_all(), str_trim(), str_to_upper(), str_replace_all(), parse_number() e ggplot(), foram utilizadas para organizar, transformar e analisar os dados de forma sistemática.

5.39.2 Informações geradas para o engenheiro

A partir do script, foram obtidas informações relevantes para o acompanhamento do controle tecnológico, como:

  • número de corpos de prova analisados após o tratamento;
  • resistência média global;
  • resistência mínima e máxima;
  • resistência média por obra;
  • resistência média por tipo de concreto;
  • resistência média por idade;
  • quantidade de corpos de prova por classe;
  • variabilidade da resistência por meio do desvio-padrão;
  • resistência relativa à classe do concreto;
  • classificação dos resultados em relação à referência;
  • relação entre as propriedades do concreto, observada por meio dos gráficos.

Essas informações permitem ao engenheiro acompanhar o comportamento da resistência, comparar diferentes tipos de concreto e obras e identificar resultados que possam exigir uma análise mais detalhada.

5.39.3 Principal problema identificado

O principal problema encontrado na base foi a presença de inconsistências de preenchimento nas variáveis quantitativas. Alguns valores que deveriam ser numéricos foram armazenados como texto devido à utilização de vírgulas como separador decimal e à presença da letra O no lugar do número 0.

Um exemplo foi o registro 3O,4, identificado na variável resistencia_mpa, que representa um provável erro de digitação. Também foi identificado o valor 390O na variável cimento_kg_m3.

Além disso, foram encontradas inconsistências nas variáveis qualitativas, como espaços desnecessários em obra e diferenças na forma de escrita das classes de concreto, como C30 e c30.

A decisão adotada foi corrigir os erros de formatação e padronização identificados, converter as variáveis quantitativas para o formato numérico e excluir as observações que apresentaram valores ausentes após o tratamento. A base original foi preservada no objeto dados, permitindo manter os dados originais e realizar as alterações somente na cópia destinada à análise.

6 🧠 Considerações finais

A principal diferença entre utilizar Base R e as ferramentas da família tidyverse para o processamento de dados está na forma de organizar e executar as operações. O Base R possui funções capazes de realizar as mesmas tarefas, porém o tidyverse oferece uma abordagem mais integrada e estruturada, permitindo encadear diferentes operações de forma mais clara e próxima da sequência lógica do processo de análise.

No desenvolvimento desta atividade, funções como filter(), mutate(), group_by(), summarise(), across() e case_when() permitiram realizar etapas de inspeção, limpeza, transformação e análise de maneira organizada. Além disso, funções do stringr e do ggplot2 facilitaram, respectivamente, o tratamento das informações textuais e a construção das visualizações.

Assim, embora o Base R e o tidyverse possam solucionar problemas semelhantes, o tidyverse apresenta vantagens na organização do código, principalmente quando são necessárias várias etapas de transformação dos dados. Essa característica torna o processamento mais legível, sistemático e fácil de reproduzir, o que é importante quando o script precisa ser compreendido e utilizado por outro profissional.

No contexto da Engenharia Civil, essa organização é especialmente relevante, pois os dados utilizados em análises de controle tecnológico podem apresentar erros de digitação, valores ausentes e diferentes formas de preenchimento. Antes de aplicar métodos estatísticos, é necessário garantir que os dados estejam adequadamente estruturados e tratados.

Dessa forma, o principal aprendizado desta atividade foi compreender que a escolha da ferramenta de processamento não está apenas relacionada à obtenção do resultado, mas também à forma como o processo é estruturado e documentado. O uso do tidyverse contribui para construir um fluxo de análise mais organizado, facilitando a transformação dos dados brutos em informações confiáveis para auxiliar a tomada de decisão na Engenharia Civil.

7 📖 Referências

BATISTA, B. D. DE O. Estatística & Probabilidade aplicada às Engenharias e Ciências. Ouro Branco, MG: [s.n.].
BATISTA, B. D. DE O.; ARTHUR, D. R básico: Coleção Estudando o Ambiente R. [s.l: s.n.]. v. 1