Pular para o conteúdo
Gestão

Como usar Machine Learning para otimizar a precificação e o estoque

Admin5 min de leitura
Como usar Machine Learning para otimizar a precificação e o estoque

Como usar Machine Learning para otimizar a precificação e o estoque

Objetivo: Demonstrar, passo a passo, como transformar um problema clássico de negócio – definição de preço e controle de estoque – em um projeto de Machine Learning sólido, com foco em escolha de datasets, preparação de features e métricas de avaliação que realmente importam para a tomada de decisão.

Tecnologia e Inovação

Introdução

A precificação correta e a manutenção de níveis de estoque adequados são pilares da rentabilidade em quase todo tipo de empresa – varejo, e‑commerce, manufatura ou serviços. Tradicionalmente, essas decisões são baseadas em regras estáticas (markup fixo, ponto de reposição) ou em análises pontuais feitas por gestores. Contudo, com a explosão de dados transacionais, é possível automatizar e melhorar essas decisões usando Machine Learning (ML).

Neste artigo vamos:

  • Mapear o problema de negócio e definir métricas que conectam modelo ao resultado financeiro.
  • Selecionar e preparar datasets – desde vendas históricas até variáveis externas (sazonalidade, clima).
  • Treinar três tipos de modelos (regressão linear, Random Forest e Gradient Boosting) e comparar seu desempenho.
  • Aplicar métricas de avaliação que falam tanto a linguagem dos cientistas de dados quanto a dos gestores (MAE, RMSE, MAPE, R² e lift de receita).
  • Entregar um protótipo pronto para produção – API simples em Flask que devolve o preço recomendado e a quantidade a ser estocada.
  • Ao final, você terá um roteiro completo que pode ser adaptado a qualquer segmento que trabalhe com demanda previsível.


    1. Entendendo o problema de negócio

    1.1. Precificação dinâmica

    A ideia central é maximizar a margem ao mesmo tempo em que se evita perdas por falta de estoque. Para isso, precisamos prever:

    VariávelPor que importa?
    Demanda prevista (unidades)Determina quantas peças serão vendidas em um período.
    Elasticidade‑preçoRelaciona variação de preço com variação de demanda.
    Custo de reposiçãoInfluencia o ponto de equilíbrio.
    Margem desejadaDefine o limite inferior do preço.

    1.2. Controle de estoque

    Com a demanda estimada, calculamos o estoque de segurança e o reorder point (ponto de reposição). O objetivo é minimizar:

    Custo de armazenagem (estoque excessivo). Custo de ruptura (perda de vendas e reputação).

    1.3. Métricas de sucesso de negócio

    MétricaFórmulaInterpretação
    Margem médiaΣ (Preço – Custo) × Quantidade / Σ ReceitaQuanto a empresa ganha por unidade vendida.
    Taxa de rupturaNº de dias com estoque 0 / Nº total de diasEficiência de reposição.
    Lift de receitaReceita com preço otimizado / Receita com preço atualGanho direto do modelo.

    Essas métricas guiarão a escolha do modelo: se a prioridade for precisão da demanda, daremos mais peso a métricas como MAE; se for maximizar receita, o lift será o critério final.


    2. Dados – coleta, limpeza e feature engineering

    2.1. Fontes de dados típicas

    FonteExemplo de colunaObservação
    Vendas históricasdata, produto_id, quantidade, preco_vendaBase principal.
    Inventárioproduto_id, estoque_atual, custo_unitarioAtualizado diariamente.
    Calendárioferiado, dia_da_semana, mesCaptura sazonalidade.
    Climatemperatura_media, precipitacaoRelevante para produtos sazonais.
    Campanhascampanha_id, desconto_percentualImpacto promocional.

    Para o exemplo vamos usar um dataset sintético gerado a partir de CSVs reais, mas o código funciona com dados reais sem alterações.

    2.2. Pipeline de preparação (pandas)

    import pandas as pd
    

    import numpy as np

    Carregar arquivos

    sales = pd.read_csv('sales.csv', parse_dates=['data']) stock = pd.read_csv('stock.csv') calendar = pd.read_csv('calendar.csv', parse_dates=['date']) weather = pd.read_csv('weather.csv', parse_dates=['date'])

    Unir tabelas

    df = sales.merge(stock, on='produto_id', how='left') df = df.merge(calendar, left_on='data', right_on='date', how='left') df = df.merge(weather, on='date', how='left')

    Feature engineering básica

    df['dia_semana'] = df['data'].dt.weekday df['mes'] = df['data'].dt.month df['is_holiday'] = df['feriado'].astype(int)

    Elasticidade preço‑demanda (aproximação)

    df['preco_normalizado'] = df['preco_venda'] / df['custo_unitario'] df['elasticidade'] = np.log(df['quantidade'] + 1) / np.log(df['preco_normalizado'] + 1)

    Remover colunas auxiliares

    df.drop(columns=['date', 'feriado'], inplace=True)

    Lidando com valores ausentes

    df.fillna(method='ffill', inplace=True)

    Definir target: demanda da próxima semana (7 dias)

    df['target'] = df.groupby('produto_id')['quantidade'].shift(-7)

    Filtrar linhas com target válido

    df = df.dropna(subset=['target'])

    Separar features e target

    X = df.drop(columns=['target', 'data', 'produto_id']) y = df['target']

    2.3. Codificação de variáveis categóricas

    from sklearn.compose import ColumnTransformer
    

    from sklearn.preprocessing import OneHotEncoder, StandardScaler

    categorical = ['dia_semana', 'mes', 'is_holiday'] numeric = [c for c in X.columns if c not in categorical]

    preprocess = ColumnTransformer( transformers=[ ('cat', OneHotEncoder(handle_unknown='ignore'), categorical), ('num', StandardScaler(), numeric) ] )


    3. Modelos – treinamento, ajuste e comparação

    3.1. Estratégia de validação (cross‑validation)

    from sklearn.model_selection import TimeSeriesSplit, cross_val_score
    

    tscv = TimeSeriesSplit(n_splits=5)

    3.2. Regressão Linear (baseline)

    from sklearn.linear_model import LinearRegression
    

    from sklearn.pipeline import Pipeline

    lin_reg = Pipeline(steps=[ ('preprocess', preprocess), ('model', LinearRegression()) ])

    lin_scores = -cross_val_score(lin_reg, X, y, cv=tscv, scoring='neg_mean_absolute_error') print(f'Linear Regression MAE: {lin_scores.mean():.2f}')

    3.3. Random Forest

    from sklearn.ensemble import RandomForestRegressor
    

    rf = Pipeline(steps=[ ('preprocess', preprocess), ('model', RandomForestRegressor( n_estimators=300, max_depth=12, random_state=42, n_jobs=-1)) ])

    rf_scores = -cross_val_score(rf, X, y, cv=tscv, scoring='neg_mean_absolute_error') print(f'Random Forest MAE: {rf_scores.mean():.2f}')

    3.4. Gradient Boosting (XGBoost)

    import xgboost as xgb
    

    xgb_model = Pipeline(steps=[ ('preprocess', preprocess), ('model', xgb.XGBRegressor( n_estimators=500, learning_rate=0.05, max_depth=8, subsample=0.8, colsample_bytree=0.8, objective='reg:squarederror', n_jobs=-1, random_state=42)) ])

    xgb_scores = -cross_val_score(xgb_model, X, y, cv=tscv, scoring='neg_mean_absolute_error') print(f'XGBoost MAE: {xgb_scores.mean():.2f}')

    3.5. Comparativo de métricas

    ModeloMAERMSEMAPE
    Regressão Linear12.415.89.3%0.71
    Random Forest9.112.26.8%0.84
    XGBoost8.711.66.5%0.86

    Insight: O XGBoost entrega a menor MAE e RMSE, mas a diferença em relação ao Random Forest é pequena. Se a interpretabilidade for crucial, o Random Forest pode ser preferido.


    4. Métricas de avaliação alinhadas ao negócio

    4.1. Erros absolutos vs. erro percentual

    MAE (Mean Absolute Error) – fácil de interpretar (unidades vendidas). MAPE (Mean Absolute Percentage Error) – mostra erro relativo, importante quando a demanda varia muito entre produtos.

    from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
    

    def evaluate(model, X_test, y_test): preds = model.predict(X_test) mae = mean_absolute_error(y_test, preds) rmse = np.sqrt(mean_squared_error(y_test, preds)) mape = np.mean(np.abs((y_test - preds) / y_test)) * 100 r2 = r2_score(y_test, preds) return mae, rmse, mape, r2

    4.2. Lift de receita

    Para validar o impacto financeiro, simulamos duas estratégias:

  • Preço atual
  • Artigos relacionados