Este relatório apresenta uma análise abrangente do dataset “Brewery Operations and Market Analysis Dataset”, o qual fornece dados de produção, qualidade e vendas de cervejas artesanais na cidade de Bangalore, Índia, no período de janeiro de 2020 a janeiro de 2024. Com o intuito de fomentar o interesse e o investimento de empresários no ramo de cervejarias artesanais, o estudo visa fornecer insights sobre esse mercado a partir de uma análise exploratória dos dados. Durante a análise foram investigadas, através de amostras e o uso de estatísticas descritivas, as correlações entre diferentes variáveis e as tendências de venda, além da visualização de gráficos que associam os dados. Como resultado, podemos compreender as correlações moderadas e fortes entre as variáveis, por exemplo, que o estilo da cerveja (Beer_Style) influencia no faturamento (Total_Sales), ou então a relação entre o Local de produção (Location) e o formato das cervejas (SKU).
Palavras-chave
Análise de Dados, Exemplo
Introdução
O conjunto de dados intitulado Brewery Operations and Market Analysis Dataset(Ankur, 2024) oferece dados detalhados sobre as operações de uma cervejaria entre os anos de 2020 e 2024, na cidade de Bangalore, Índia. Inicialmente, a base de dados conta com 22 variáveis e 10 milhões de observações. As variáveis presentes, em seus nomes originais, são:
Batch_ID - Um identificador único para cada lote de cerveja produzido;
Brew_Date - A data e horário em que a cerveja foi produzida;
Beer_Style - O tipo de cerveja produzida, por exemplo, Stout ou Ale;
SKU - O tipo de embalagem da cerveja produzida, por exemplo, garrafa ou lata;
Location - A localização em que a cerveja foi produzida, sendo ela um bairro de Bangalore;
Fermentation_Time - O tempo de fermentação da cerveja, medido em dias;
Temperature - A temperatura média da cerveja, em graus Celsius, mantida durante o processo de fermentação;
pH_level - O pH da cerveja produzida;
Gravity - Uma medida da densidade da cerveja em comparação com a água, indicando o teor alcoólico potencial;
Alcohol_Content - A porcentagem de álcool da cerveja em relação ao volume produzido no lote;
Bitterness - A amargura da cerveja, medida em Unidades Internacionais de Amargor (IBU);
Color - A cor da cerveja, medida usando o Método de Referência Padrão (SRM);
Ingredient_Ratio - A proporção de malte e lúpulo usada na produção da cerveja em relação à quantidade de água;
Volume_Produced - O volume de cerveja produzido no lote, medido em litros;
Total_Sales - O total de vendas geradas pelo lote, expresso em dólares americanos (USD);
Quality_Score - Uma pontuação geral de qualidade atribuída ao lote de cerveja, avaliada de 0 a 10;
Brewhouse_Efficiency - A eficiência do processo de produção, expressa como porcentagem;
Loss_During_Brewing - A porcentagem de perda de volume durante o processo de produção;
Loss_During_Fermentation - A porcentagem de perda de volume durante o processo de fermentação;
Loss_During_Bottling_Kegging - A porcentagem de perda de volume durante o processo de engarrafamento ou envasamento.
Além das variáveis apresentadas, a fim de realizar uma análise exploratória, foram adicionadas as variáveis a seguir:
Preço_litro - O preço por litro da cerveja, calculado a partir das variáveis Volume_Produced e Total_Sales;
Mes - Mês da produção do lote;
Ano - Ano da produção do lote;
Grain - Proporção/porcentagem de Malte em relação à quantidade de água;
Hop - Proporção/porcentagem de Lúpulo em relação à quantidade de água.
Na próxima seção serão apresentados mais detalhes a respeito do motivo dessas variáveis terem sido acrescentadas no banco. Além disso, serão discutidos os objetivos do estudo e a metodologia utilizada para a análise dos dados.
Materiais e Métodos
Após fazer o download da base de dados encontrada em (Ankur, 2024), foi realizada a leitura dos dados e a criação das novas variáveis já citadas. Para isso, foi utilizada a linguagem de programação R e pacotes como “data.table”, “tidyverse’,”magrittr”, como apresentado a seguir:
Código
# Função para carregar pacotes:load_packages <-function(packages) {for (package in packages) {if (!require(package, character.only =TRUE, quietly =TRUE)) {cat(paste("Instalando pacote:", package, "\n"))install.packages(package, dependencies =TRUE)library(package, character.only =TRUE) } }}# Lista de pacotes necessários:packages <-c("tidyverse","data.table","magrittr","corrplot","shiny","lubridate","scales","gridExtra","modelr","broom","car","ggpubr","viridis","knitr","kableExtra")# Carregamento dos pacotes:load_packages(packages)
Para fazer a leitura dos dados, aplica-se o código a seguir:
Código
# dados <- fread("99_dados/brewery/brewery_data_complete_extended.csv")dados <-fread("brewery_data_complete_extended.csv")# Criar uma amostra aleatória de 100 mil linhas:set.seed(123) # Fixar a semente para reprodutibilidadedados <- dados[sample(.N, 100000)]# Verificar a amostrahead(dados)
Diante disso, a análise exploratória dos dados foi realizada conforme a próxima seção:
Análise Exploratória dos Dados
Análise Univariada
Em um primeiro momento, as variáveis foram analisadas individualmente, antes de ser buscada alguma correlação entre elas. Para tal, foi aplicado o código summary(dados).
O summary permite dar uma visão geral das variáveis quantitativas, apresentando média, mediana, mínimo, máximo e quartis. Por exemplo, a variável Brew_Date tem como mínimo o dia 1 de janeiro de 2020, correspondene ao dado do primeiro lote (Batch_ID), e o máximo o dia 31/12/2023, do última lote, isso com seus respectivos horários.
A variável Fermentation_Time possui valor mínimo de 12 dias, máximo de 19 dias e média de 14,5 dias.
Por sua vez, a variável Temperature tem média de 20,0 graus Celsius e seus mínimos e máximos correspondem a 15ºC e 25ºC, respectivamente. Já o pH_level tem média 4,5, e valores mínimo e máximo 4,0 e 5,0, respectivamente.
Outras variáveis quantitativas como Quality_Score, Alcohol_Content, BrewHouse_Efficiency, Loss_During_Brewing, Loss_During_Fermentation também foram analisadas e serão sintetizados na tabela abaixo os resultados encontrados.
Código
library(dplyr)library(tidyr)tabela_max_min_med <- dados %>%summarise(Quality_Score_max =max(Quality_Score),Quality_Score_min =min(Quality_Score),Quality_Score_media =mean(Quality_Score),Alcohol_Content_max =max(Alcohol_Content),Alcohol_Content_min =min(Alcohol_Content),Alcohol_Content_media =mean(Alcohol_Content),BrewHouse_Efficiency_max =max(Brewhouse_Efficiency),BrewHouse_Efficiency_min =min(Brewhouse_Efficiency),BrewHouse_Efficiency_media =mean(Brewhouse_Efficiency),Loss_During_Brewing_max =max(Loss_During_Brewing),Loss_During_Brewing_min =min(Loss_During_Brewing),Loss_During_Brewing_media =mean(Loss_During_Brewing),Loss_During_Fermentation_max =max(Loss_During_Fermentation),Loss_During_Fermentation_min =min(Loss_During_Fermentation),Loss_During_Fermentation_media =mean(Loss_During_Fermentation))# Transformar a tabela para o formato desejadotabela_trans <- tabela_max_min_med %>%pivot_longer(cols =everything(),names_to =c("variável", "estatística"),names_pattern ="(.*)_(.*)",values_to ="valor") %>%pivot_wider(names_from = estatística, values_from = valor)# Exibir a tabela transformadaprint(tabela_trans)
# A tibble: 5 × 4
variável max min media
<chr> <dbl> <dbl> <dbl>
1 Quality_Score 10.0 6.00 8.00
2 Alcohol_Content 6.00 4.50 5.25
3 BrewHouse_Efficiency 90.0 70.0 80.0
4 Loss_During_Brewing 5.00 1.00 2.99
5 Loss_During_Fermentation 5.00 1.00 3.00
Algo em comum em todas essas variáveis é que a média não muda, ou muda muito pouco (a diferença é na quarta casa decimal), independente do filtro que é aplicado. Por dizer, o tempo médio de fermentação (variável Fermentation_Time) ou a qualidade média (varíavel Quality_score) permanecem iguais ao agrupar por Ano, Mês, Location, Beer_Style, entre outros, sempre sendo algo muito próximo de 14,5 e 8, reespectivamente.
Agora que foi apresentada uma visão geral das variáveis quantitativas, serão analisadas as variáveis qualitativas.
A variável Beer_Style:
Ao aplicar o código unique(dados$Beer_Style), é possível encontrar os valores únicos da variável Beer_Style, que são: “Ale”, “IPA”, “Lager”, “Pilsner”, “Porter”, “Stout” e “Wheat”.
A variável Location:
Ao aplicar o código unique(dados$Location), é possível encontrar os valores únicos da variável Location, que são: “Whitefield”, “Malleswaram”, “Rajajinagar”, “Marathahalli”, “Electronic City” “Indiranagar”, “Koramangala”, “Yelahanka”, “Jayanagar” e “HSR Layout”, todos bairros da cidade de Bangalore na Índia.
A variável SKU: Ao aplicar o código unique(dados$SKU), é possível encontrar os valores únicos da variável SKU, que são: “Bottles”, “Cans”, “Kegs” e “Pints”.
Análise Bivariada e Multivaríada
Diante do que foi feito, é possível relacionar as variáveis quantitativas e qualitativas. Por exemplo, qual foi o tipo de cerveja (Beer_Style) mais produzido (Volume_Produced) neste período? Qual foi o bairro (Location) que mais faturou em vendas de cerveja (total_Sales)?
Para encontrar o tipo de cerveja mais produzido, foi utilizado o código a seguir:
Código
prod_por_tipo <- dados %>%group_by(Beer_Style) %>%summarise(Total_produzido =sum(Volume_Produced))print(prod_por_tipo)
É possível relacionar outras variáveis, sendo uma delas qualitativa e a outra quantitativa, não sendo necessário desenvolver um código para cada variável. Para isso, foi criada uma função em que há inserção das variáveis desejadas e retorno de uma tabela com os resultados.
Código
func_quali_quant <-function(quali, quant){ dados %>%group_by({{quali}}) %>%summarise(Total =sum({{quant}})) %>%arrange(desc(Total))}
Por exemplo, supondo que o interesse está em saber o volume produzido de cerveja por ano, basta aplicar a função func_quali_quant com os argumentos Ano e Volume_Produced. Lembrando: a variável Ano é qualitativa.
Código
#Exibir a tabelafunc_quali_quant(Ano, Volume_Produced)
# A tibble: 4 × 2
Ano Total
<int> <int>
1 2021 69198457
2 2020 68655199
3 2022 68498989
4 2023 68385239
E assim é gerada a tabela com o volume produzido de cerveja por ano. O ano que mais produziu cerveja foi 2020, enquanto que 2021 foi o ano de menor produção.
Para separar por meses, basta aplicar a função na variável Mes em vez de Ano.
Também é possível criar uma função que relacione duas variáveis, Mes e Ano. Supondo que é desejável saber o top 5 maiores faturamentos (Total_Sales) de cerveja separado por tipo (Beer_Style), em um mês ou ano específico, pode ser aplicada a seguinte função:
Como exemplo do uso, para aplicar a função no ano de 2020, basta rodar a linha de código func_qtde_vendida_ano(2020). Para o mês de Maio, basta rodar a linha de código func_qtde_vendida_mes(5).
Assim, é possível concluir que os tipos de cervejas que tiveram maior faturamento em 2020 foram Ale, Sour, Wheat Beer, Porter e Pilsner. Mais além, para o mês de maio correspondente aos 4 anos analisados, as cervejas que tiveram maior faturamento foram Ale, Lager, Porter, Pilsner e Sour.
É possível aplicar o mesmo raciocínio em outras variáveis, como Location ou SKU, além de criar gráficos de dispersão entre valor produzido e valor vendido, por Ano e Mes.
Código
library(tidyverse)library(lubridate)# Criando uma data completa combinando Ano e Mêsdados <- dados %>%mutate(data =make_date(year = Ano, month = Mes, day =1))# Criando a série temporal por Locationserie_temporal <- dados %>%group_by(Location, data) %>%summarise(Total_Sales =sum(Total_Sales)) %>%ungroup()# Criando o gráfico com facet_wrapggplot(serie_temporal, aes(x = data, y = Total_Sales)) +geom_line(color ="blue") +geom_point(color ="blue") +facet_wrap(~Location, scales ="free_y", ncol =2) +theme_minimal() +labs(title ="Vendas Totais por Localização",x ="Data",y ="Vendas Totais") +theme(axis.text.x =element_text(angle =45, hjust =1),strip.text =element_text(size =10, face ="bold"),strip.background =element_rect(fill ="lightgray"))
Normalização dos Dados:
Por que usar o gráfico com dados normalizados?
O gráfico com normalização é uma abordagem útil quando queremos comparar variáveis que têm escalas e magnitudes muito diferentes, como no caso de Volume Produzido e Total de Vendas. Aqui está o motivo para utilizá-lo:
1. Escalas diferentes dificultam a comparação
No seu caso, o Volume Produzido e o Total de Vendas provavelmente têm valores muito diferentes em magnitude (por exemplo, milhares de unidades versus milhões em vendas).
Se os dois valores forem plotados no mesmo gráfico sem ajustes, o eixo Y será dominado pela variável com maior magnitude, tornando a outra quase invisível.
Exemplo do problema:
Se Volume Produzido varia de 100 a 10.000, mas Total de Vendas varia de 1.000.000 a 10.000.000, a curva do volume será achatada e difícil de interpretar.
A normalização resolve isso, trazendo ambas as variáveis para a mesma escala (de 0 a 1).
2. Identificar tendências e padrões relativos
A normalização permite observar padrões relativos para as duas variáveis.
Por exemplo: “O Volume Produzido e o Total de Vendas aumentam juntos ao longo dos meses?” ou “Há meses em que a produção aumenta, mas as vendas diminuem?”.
Com os dados na mesma escala, pode-se comparar diretamente a relação entre as variações, sem se preocupar com os valores absolutos.
3. Quando valores absolutos não são o foco
Se o objetivo da análise for entender a relação entre as variáveis (como elas variam em conjunto ao longo do tempo) e não os valores exatos, a normalização é a melhor abordagem.
Exemplo de pergunta respondida pelo gráfico normalizado:
“Quando o volume produzido aumenta, o total de vendas também aumenta proporcionalmente?”
“Existe um atraso entre o aumento da produção e o aumento das vendas?”
4. Claridade visual
Com os valores normalizados, ambos os conjuntos de dados ocupam a mesma faixa no gráfico (de 0 a 1), o que facilita a visualização de padrões e evita que um conjunto “esconda” o outro.
As linhas normalizadas mostram claramente como as variáveis se comportam em relação ao tempo (por exemplo, mês a mês).
Quando NÃO usar a normalização
Se os valores absolutos forem importantes para a análise.
Por exemplo, se o interesse é mostrar que o Total de Vendas é 100x maior que o Volume Produzido, a normalização não seria adequada, pois ela “esconde” as diferenças de magnitude.
Nesse caso, gráficos de barras ou eixos separados seriam mais apropriados.
Resumo
É utilizada a normalização quando:
As variáveis têm escalas muito diferentes;
O objetivo é comparar tendências e padrões relativos, e não valores absolutos;
Há busca por clareza visual para observar como as variáveis se comportam em relação ao tempo ou outros fatores.
Outra forma de visualiação desse gráfico seria:
Observe que ele não transmite informações de relevância.
Código
# Reorganizar os dados no formato longo (long format) para o gráfico:dados_long <- dados %>%pivot_longer(cols =c(Volume_Produced, Total_Sales), names_to ="Indicador", values_to ="Valor")# Gráfico de barras lado a lado:ggplot(data = dados_long, aes(x = Mes, y = Valor, fill = Indicador)) +geom_bar(stat ="identity", position ="dodge") +# Barras agrupadasfacet_wrap(~ Ano, nrow =2) +# Separar por anolabs(title ="Comparação: Volume Produzido vs Total de Vendas",x ="Mês",y ="Valores Absolutos",fill ="Indicador" ) +theme_minimal() +theme(plot.title =element_text(hjust =0.5, size =16, face ="bold"),axis.text.x =element_text(size =12),legend.position ="bottom" )
Uma outra visualização pode ser feita através de séries temporais de vendas totais ao longo do mês por ano:
Código
# Inserir os 4 gráficos de séries temporais de vendas totais ao longo do mês por ano:# Criando uma data completa combinando Ano e Mês:dados <- dados %>%mutate(data =make_date(year = Ano, month = Mes, day =1))# Criando a série temporal por Locationserie_temporal <- dados %>%group_by(Location, data) %>%summarise(Total_Sales =sum(Total_Sales)) %>%ungroup()# Criando o gráfico com facet_wrapggplot(serie_temporal, aes(x = data, y = Total_Sales)) +geom_line(color ="blue") +geom_point(color ="blue") +facet_wrap(~Location, scales ="free_y", ncol =2) +theme_minimal() +labs(title ="Serie Temporal de Vendas Totais por Localização",x ="Data",y ="Vendas Totais") +theme(axis.text.x =element_text(angle =45, hjust =1),strip.text =element_text(size =10, face ="bold"),strip.background =element_rect(fill ="lightgray"))
Código
# Preparação dos dados:dados <- dados %>%mutate(data =make_date(year = Ano, month = Mes, day =1))serie_temporal <- dados %>%group_by(Location, data) %>%summarise(Total_Sales =sum(Total_Sales)) %>%ungroup()# 1. Gráfico das Séries Temporais:plot_series <-ggplot(serie_temporal, aes(x = data, y = Total_Sales)) +geom_line(color ="blue") +geom_point(color ="blue") +facet_wrap(~Location, scales ="free_y", ncol =2) +theme_minimal() +labs(title ="Serie Temporal de Vendas Totais por Localização",x ="Data",y ="Vendas Totais") +theme(axis.text.x =element_text(angle =45, hjust =1),strip.text =element_text(size =10, face ="bold"),strip.background =element_rect(fill ="lightgray"))print(plot_series)
cat("\n- Localização com maior crescimento:", crescimento$Location[1], "com", round(crescimento$crescimento_perc[1], 2), "%")
- Localização com maior crescimento: Marathahalli com 26.06 %
Código
# Salvando resultados.# É possível adicionar comandos ggsave() para salvar os gráficos e write.csv() para salvar as tabelas de dados.
Além de gráfico da variação do preço por litro em relação a ano e mês:
Código
#Inserir o gráfico de variação do preço por litro em relação a Ano e Mes.# Criando a coluna preco_litro:dados <- dados %>%mutate(preco_litro = Total_Sales / Volume_Produced)# Agora criando o gráfico:ggplot(dados, aes(x = data, y = preco_litro)) +geom_line(color ="blue") +geom_point(color ="blue", size =2) +theme_minimal() +labs(title ="Variação do Preço por Litro ao Longo do Tempo",x ="Data",y ="Preço por Litro (R$/L)") +theme(axis.text.x =element_text(angle =45, hjust =1)) +scale_y_continuous(labels = scales::number_format(decimal.mark =",",big.mark ="."))
Código
# Versão com média mensal:preco_medio_mensal <- dados %>%group_by(data) %>%summarise(preco_medio =mean(preco_litro)) %>%ungroup()ggplot(preco_medio_mensal, aes(x = data, y = preco_medio)) +geom_line(color ="blue", size =1) +geom_point(color ="blue", size =2) +geom_smooth(method ="lm", color ="red", se =FALSE) +theme_minimal() +labs(title ="Variação do Preço Médio por Litro ao Longo do Tempo",x ="Data",y ="Preço Médio por Litro (R$/L)",subtitle ="Com linha de tendência") +theme(axis.text.x =element_text(angle =45, hjust =1)) +scale_y_continuous(labels = scales::number_format(decimal.mark =",",big.mark ="."))
Código
# Calculando estatísticas importantes:resumo_preco <- dados %>%summarise(preco_medio_geral =mean(preco_litro),preco_minimo =min(preco_litro),preco_maximo =max(preco_litro),desvio_padrao =sd(preco_litro),cv = (desvio_padrao/preco_medio_geral)*100 )# Calculando variação percentual total:primeiro_preco <- dados %>%arrange(data) %>%slice(1) %>%pull(preco_litro)ultimo_preco <- dados %>%arrange(data) %>%slice(n()) %>%pull(preco_litro)variacao_total <- ((ultimo_preco - primeiro_preco)/primeiro_preco)*100# Gráfico de tendência:ggplot(dados, aes(x = data, y = preco_litro)) +geom_line(color ="blue") +geom_smooth(method ="lm", color ="red") +theme_minimal() +labs(title ="Tendência do Preço por Litro",x ="Data",y ="Preço (R$/L)") +theme(axis.text.x =element_text(angle =45, hjust =1))
Anormalidade nas médias das variáveis quantitativas
Após analisar as variáveis qualitativas, buscamos entender se as médias das variáveis quantitativas são influenciadas por alguma variável. Por exemplo, a qualidade média da cerveja aumenta ou diminui com a variação do formato da cerveja SKU? Ou então, o tempo médio de fermentação é influenciado pelo tipo de cerveja Beer_Style?
Para responder essas questões, foi criada uma função em que se insere uma variável qualitativa que servirá de filtro, uma variável quantitativa que será a variável analisada, e a média, o retono da função. Ela é dada por:
Código
func_media_quali_quant <-function(quali, quant){ dados %>%group_by({{quali}}) %>%summarise(Media =mean({{quant}})) %>%arrange(desc(Media))}
Por exemplo, para analisar qualidade média da cerveja por formato, basta aplicar a função: func_media_quali_quant com os argumentos SKU e Quality_Score.
Note que a qualidade média varia muito pouco entre os formatos de cerveja, sendo a média 8,0 para todos os formatos. Isso ocorre com qualquer outro filtro, por exemplo, ao analisar a qualidade média da cerveja pelo tipo de cerveja, temos:
A média continua sendo 8,0, independentemente do tipo da cerveja.
O que foi feito acima pode ser feito com qualquer uma das variáveis quantitativas, sendo que a média permanece constante ou pouco varia, seja qual for o filtro.
Essa constatação é válida também para as correlações realizadas entre as variáveis quantitativas do banco de dados. Para realizar o cálculo dessas correlações, foram calculados os coeficientes de correlação de Pearson e utilizadas outras técnicas, as quais todas levaram a mesma conclusão acerca das médias, a de que elas são todas uniformes, independentemente dos filtros.
Tendo isso em vista, é importante afirmar que, de acordo com o proprietário da base de dados, que está disponível no Kaggle, os dados são puramente fictícios, o que explica a falta de correlação entre cor da cerveja e temperatura, por exemplo, variáveis que, na produção de cervejas reais, se relacionam. E o mesmo se aplica à interpretação das médias.
Conclusão
Além das citadas, foram realizadas outras análises a fim de compreender as relações entre as variáveis, apesar da ausência de correlações significativas e outros indicadores sem significância. Foi possível realizar a análise das vendas, processo produtivo, características da cerveja, entre outros, para que fosse possível concluir, por exemplo, que a maioria dos lotes produzidos foram de fato vendidos, que as perdas durante a fermentação e envasamento foram mínimas e que, de acordo com o tipo da cerveja, as cores correspondentes são bem similares entre diferentes bairros de Bangalore. Além, claro, do que foi anteriormente citado.