Previsão de demanda de loja de vinhos — Parte 2/3 — Analisando os dados

Na primeira parte do nosso projeto, que você encontra aqui, fizemos um estudo de caso, entendemos um pouco do negócio e fizemos a limpeza dos dados de um catálogo de vinhos. Nessa segunda parte, iremos analisar esses dados junto aos dados de vendas.

Guilherme Marczewski
9 min readMay 17, 2021

Na continuação do nosso projeto iniciado na semana passada, iremos fazer uma análise tanto do conjunto de dados que realizamos a limpeza e tratamento de dados na parte 1, quanto do histórico de vendas. Para o conjunto de dados das vendas, não será realizado o tratamento de dados tão minuciosamente, mas dificilmente fugirá do que fizemos na primeira parte: verificar o formato dos dados, espaços em branco e substituir caracteres que não serão utilizados.

Para a análise de dados da carta de vinhos, será utilizado o dataframe que finalizamos na primeira parte e está disponível aqui, pronto para ser trabalhado.

Primeiro vamos verificar a quantidade de vinhos por produtor e safra. Usaremos a biblioteca de visualização de dados Seaborn, que já foi importada logo no início do projeto, agrupando pelo produtor e depois pela safra, fazendo uma contagem de linhas.

f, ax = plt.subplots(figsize=(16, 8))sns.countplot(x=df.producer, order=df.producer.value_counts().index);plt.xticks(rotation=90)plt.show();
Quantidade de vinhos por produtor.
f, ax = plt.subplots(figsize=(16, 8))sns.countplot(x=df.vintage, order=df.vintage.value_counts().index);plt.xticks(rotation=90)plt.show();
Quantidade de vinhos por safra.

Além disso, vamos verificar qual o vinho mais caro, mais barato e a média dos preços.

print(df.price_usd.describe(), "\n")print("O vinho mais caro custa: USD $",df.price_usd.max())print("O vinho mais barato custa: USD $", df.price_usd.min())print("A média de preço dos vinhos é de: USD $", df.price_usd.mean())

Considerando o nosso conjunto de dados que tem apenas 219 linhas, talvez seja mais fácil usar o Microsoft Excel para ordenar os vinhos do maior pro menor preço, e depois o contrário, para achar o vinho mais barato e o mais caro. Mas imagine que o catálogo contivesse 2 milhões de linhas, esse método se tornaria menos prático. Devido a isso, irei procurar esses vinhos direto pelo valor, que descobrimos na última etapa.

Para achar o vinho mais caro:

df[df.price_usd == 1901.73]

E para achar o vinho mais barato:

df[df.price_usd == 9.13]

Agora vamos verificar os preços dos 15 vinhos mais caros da carta:

f, ax = plt.subplots(figsize=(16, 8))sns.barplot(x=df.name, y=df.price_usd, order=df.sort_values('price_usd', ascending=False).name.iloc[0:15])plt.xticks(rotation=90)plt.show();

Com esse último gráfico, podemos verificar que o terceiro vinho mais caro, custa praticamente metade do preço do mais caro, que passa dos US$ 1.900,00. Esse valor, convertido para real na data de hoje, 11/05/2021, chega próximo dos R$ 10.000,00, o preço de muitos carros usados.

Agora vamos fazer uma análise por safra:

data = pd.concat([df.price_usd, df.vintage], axis=1)f, ax = plt.subplots(figsize=(16, 8))fig = sns.boxplot(x=df.vintage, y=df.price_usd, data=data)fig.axis();plt.xticks(rotation=90);

Podemos notar que os vinhos mais caros de algumas safras não passam dos US$ 250, como as de 2003 e 2004. E algumas safras possuem apenas um tipo de vinho, mas de valor elevado, como a de 2002 e 2007. Enquanto isso temos a safra de 2010, que possui uma melhor distribuição dos valores de vinhos.

Um detalhe a ser notado, é referente à safra “0”, que na primeira parte do nosso projeto possuía o nome como “NV”, de Non Vintage. Esses são os vinhos que não possuem uma safra específica, mantendo um sabor constante, o que faz com que o preço seja realmente mais baixo.

Dados de vendas

Agora que conhecemos um pouco a nossa carta de vinhos, vamos dar uma olhada nos dados de vendas.

O conjunto de dados de vendas utilizado nesse projeto, assim como a carta de vinhos, também é sintético, feito com base em um conjunto de dados utilizado em uma competição do Kaggle. Os dados originais continham o histórico diário de vendas de 10 lojas durante 5 anos, porém trabalharemos com um conjunto modificado, considerando apenas 3 anos.

Como dito na parte 1 sobre o conjunto de dados contendo os dados dos vinhos, por se tratar de um conjunto sintético, esse projeto não representa a realidade do mercado de vinhos, mas sim a realidade do conjunto de dados. Devido a isso, é possível que no conjunto de dados de vendas tenham vendas de um vinho antes de sua safra, algo que não ocorreria com um conjunto de dados real.

Agora vamos verificar o nosso dataset com o histórico de vendas, que está disponível aqui.

Acima podemos notar que é um conjunto de dados bem simples, contendo a data, loja, item (que nesse caso é o número do vinho, presente na carta de vinhos, o dataset que trabalhamos na parte 1 desse projeto) e a quantidade de vendas.

Junção dos conjuntos de dados

Em um primeiro momento, iremos juntar o nosso conjunto de dados de venda com o conjunto de dados dos produtos. Assim teremos além das informações de vendas, as informações do produto vendido, o que facilitará a análise.

Para mesclarmos os dois conjuntos, utilizaremos o comando “merge”. Esse comando é equivale ao “join”, muito utilizado no SQL, para juntar dois bancos de dados diferentes. É necessário, para isso, termos uma coluna comum entre os dois datasets, que nesse caso é a coluna “item” nos dados de venda e a “item_id” na carta de vinhos. Apesar dos nomes das colunas terem uma pequena diferença, se referem à mesma informação, o código de identificação do vinho. Também é necessário que o tipo de dados dessas duas colunas seja o mesmo tipo, então iremos deixar as duas como string.

store.rename(columns= {'item': 'item_id'}, inplace=True)store.item_id = store.item_id.astype(str)store = df.merge(store, on='item_id', how='right')

Após essa junção, iremos converter a coluna date para o formato “datetime” e indexá-la, além de excluir a antiga coluna “date”.

import datetime as dtstore['date'] = pd.to_datetime(store['date'])store.index = store['date']store.drop('date', axis=1, inplace=True)

Agora nosso conjunto de dados “store” está completo, contendo os dados de venda e dos produtos.

Série Temporal

Agora que nosso conjunto de dados tem a data e informação das vendas, podemos tirar alguns insights ao alterarmos a granularidade dos dados. Enquanto foram disponibilizadas somente a informação do dia, mês e ano, com simples comandos podemos verificar o dia da semana, semana e trimestre, além do dia do mês, mês e ano de forma isolada.

Iremos criar uma cópia do dataset, para não alterarmos o original, chamada “df_clean”, além de abrir a data de venda para termos novas visões. Também iremos retirar informações do ano de 2016, que possui apenas uma entrada.

df_clean["Year"] = df_clean.index.yeardf_clean["Quarter"] = df_clean.index.quarterdf_clean["Month"] = df_clean.index.monthdf_clean["Week"] = df_clean.index.weekdf_clean["Weekday"] = df_clean.index.weekdaydf_clean["Day"] = df_clean.index.daydf_clean["Dayofyear"] = df_clean.index.dayofyeardf_clean["Date"] = pd.DatetimeIndex(df_clean.index).datedf_clean.drop(df_clean[df_clean.Year == 2016].index, axis=0, inplace=True)

Na primeira linha, nas colunas destacadas em vermelho, temos as seguintes informações da data de venda: Foi feita em 2018, no primeiro trimestre, mês e dia 1, primeira semana do ano, em uma segunda-feira (considerando que a contagem dos dias de semana iniciam na segunda, com o número zero, e finalizam no domingo, número 6), no primeiro dia do ano.

Com a informação dos dias da semana, podemos verificar se a maior quantidade de vendas ocorre durante o final de semana ou em dias úteis.

Para fazermos isso, vamos primeiro criar um coluna denominada “Weekend”, com todas as linhas contendo o número zero. Depois disso vamos localizar as colunas com os números 5 e 6, sábado e domingo, respectivamente, e substituir o zero pelo número um. Agora temos uma coluna que possui o número zero para vendas em dia de semana e um para vendas aos finais de semana, então iremos substituir o 0 por “Week Day” e o 1 por “Weekend”. E com essas informações, plotaremos um gráfico simples.

# incluindo o número 0 ou 1 dependendo do dia da semanadf_clean['Weekend'] = 0df_clean.loc[(df_clean.Weekday == 5) | (df_clean.Weekday == 6), 'Weekend'] = 1# substituindo esses valores por “Week Day” ou “Weekend” e plotando o gráficoweekend_counts = df_clean.Weekend.value_counts().sort_values(ascending=False)fig, ax = plt.subplots(figsize=(8,8))sns.barplot(weekend_counts.index, weekend_counts.values, palette="Blues_r")plt.ylabel("Counts")plt.xlabel("Day of the Week")labels = [item.get_text() for item in ax.get_xticklabels()]labels[1] = 'Weekend'labels[0] = 'Week Day'ax.set_xticklabels(labels)plt.title("Top Selling Days");

Com o gráfico podemos visualizar que apesar do final de semana possuir apenas dois dias, sábado e domingo, representam quase metade das vendas de vinhos.

Analisando as vendas

Com a informação das colunas “sales” e “price_usd”, respectivamente a quantidade de vendas e o valor de venda, podemos fazer uma multiplicação entre elas e ter o valor total que entrou para cada loja para cada tipo de vinho.

Essa nova coluna se chamará “amount_spent”, ou seja, valor gasto.

df_clean['amount_spent'] = df_clean['price_usd'] * df_clean['sales']

Agora vamos fazer uma análise rápida das vendas:

round(df_clean.loc[:, ["sales", "amount_spent"]].describe(),2)

Podemos verificar que o dia com menos vendas teve apenas uma, no valor de US$ 9.13.

Já o melhor dia teve pouco menos 200 vendas, totalizando quase US$ 286000.00.

A média diária de vendas gira em torno de 70 garrafas.

Agora vamos fazer um comparativo dos vinhos mais vendidos com os vinhos que mais geram retorno, para verificar se temos alguma oportunidade, como um vinho que é muito vendido e gera pouca receita, podendo ser aumentado o preço para gerar um aumento no lucro.

Podemos notar que o vinho mais caro é o que mais produz receita, mas o segundo mais vendido não está nem entre as 15 maiores receitas.

Ao saber que o o vinho Domaine Ponsot é o mais vendido e gerador da maior receita, podemos fazer algumas campanhas especiais, como:

  • Buscar mais vinhos dessa região ou do mesmo tipo.
  • Vender um kit desse vinho com os vinhos que menos saem, por um valor maior, gerando uma maior rotatividade e até diminuindo o estoque desses ofensores.

Vamos fazer uma análise parecida com a anterior, mas tendo uma visão por produtor, e não por vinho.

Novamente o Domaine Ponsot se destacada, porém nota-se que os vinhos Chateau Latour geram a segunda maior receita e não figuram entre os 15 produtores mais vendidos, o que indica que os produtos possuem um valor elevado.

Partindo desse insight, vamos verificar se o valor do vinho influencia na quantidade de vendas, utilizando uma matriz de correlação.

Podemos verificar que existe uma correlação baixa entre o preço de vinhos e quantidade de vendas, o que nos leva a crer que os consumidores ligam mais para a qualidade do produto do que o preço em si.

Agora, para finalizarmos a segunda parte desse nosso projeto, vamos verificar o comparativo entre as regiões com vinhos mais vendidos, seus estoques e a receita gerada.

Nota-se que a maior parte das regiões o estoque, volume de vendas e receita caminham juntos. Porém a região de Ribera del Duero, apesar de ser a terceira em receita, não está nem no top 10 quantidade de vendas e estoque, talvez seja a hora de procurar e disponibilizar mais opções de vinhos dessa região.

Também destaca-se a região de Rhone, que apesar de ser a região com o terceiro maior estoque, não está nem no top 5 maiores geradores de receita.

Com essa última análise, encerramos a segunda parte do nosso projeto. Na parte 3, iremos utilizar o Facebook Prophet para criar o nosso algoritmo de previsão de demandas com base no histórico de vendas. Nos vemos lá!

--

--