Regressão Linear em Vendas: Os benefícios de um desconto…
14 de outubro de 2026
Rafael Colucci

Regressão Linear em Vendas pode parecer algo pouco útil, mas se bem utilizada traz benefícios incríveis em suas operações comerciais.

⏱️ Tempo de leitura: 4 minutos para ver como dados simples evitam a ilusão de ganho fácil e protegem suas margens.

Resumo: Dar desconto para bater a meta no fim do mês costuma inflar o total de pedidos, mas corrói o caixa aos poucos. Neste artigo, mostramos como aplicar a regressão linear em vendas com Python para medir a perda real dessa prática e trocar achismos por decisões claras.

Todo fim de trimestre traz a mesma história nas empresas.

A pressa para bater a meta aperta, as negociações parecem travadas e a saída mais rápida surge quase no susto: baixar o preço para o cliente assinar o contrato na hora.

Como efeito direto, surge um alívio rápido.

Afinal, o número total de pedidos sobe, a tela do sistema mostra novos clientes e a equipe festeja o volume.

No entanto, quando as contas do mês fecham pouco tempo depois, a surpresa costuma ser ruim. Isso acontece porque o total de pedidos subiu, mas o dinheiro que sobrou no caixa ficou no mesmo lugar ou até caiu.

Portanto, o erro não está em negociar, mas em dar descontos sem saber o efeito real disso no bolso.

É exatamente nessa hora que a regressão linear em vendas deixa de ser aquela ferramenta que você aprendeu na escola, sem ter algum uso prático, e vira uma aliada eficiente para cuidar da saúde da empresa.

Conheça mais sobre Machine Learning em nossa página.

Volume contra ganho real: o que devemos focar na hora de definir um desconto?

Para olhar essa questão com fatos, analisamos o histórico de 120 vendas fechadas em uma empresa.

Naquele time, os vendedores tinham carta branca para dar abatimentos de 2% a 25%, a depender do cliente.

A princípio, a defesa do time comercial parecia fazer sentido.

Eles diziam que cortar o preço ajudava a fechar negócios maiores e trazia mais dinheiro no fim das contas.

Contudo, para checar se isso era verdade ou apenas uma desculpa fácil para fechar rápido, usamos um cálculo direto.

Desse modo, a regressão linear em vendas entrou em jogo para comparar as opiniões com a realidade do caixa.

Por que usar a regressão linear em vendas no dia a dia?

Muitas vezes, quem cuida das vendas foge da matemática por achar que ela exige fórmulas difíceis ou robôs caros. Pelo contrário, a ideia por trás dessa conta é bem simples.

Em resumo, queremos responder a uma pergunta básica: a cada 1% a mais de desconto dado na mesa, quanto dinheiro a mais ou a menos entra na conta da empresa?

Por causa disso, o cálculo traça uma linha média entre todas as vendas feitas no período. Além disso, o teste tira as dúvidas do caminho ao mostrar de forma direta se o desconto ajuda a faturar mais ou se ele apenas drena o lucro.

Do gráfico à ação: como mostrar os dados para a diretoria

Levar planilhas cheias de números para uma reunião com a diretoria só traz sono e confusão. Por outro lado, quando usamos uma boa imagem com foco na ação, o time enxerga o ponto certo sem perda de tempo.

Veja o gráfico feito a partir desse teste prático:

Regressão Linear em Vendas a análise de descontos e seus impactos nas margens

Regressão Linear em Vendas aplicada em um estudo de descontos.

A imagem acima deixa claras três lições:

  1.  Linha que só desce: Os pontos mostram que baixar o preço não atraiu pedidos maiores. Em vez disso, a empresa só entregou o mesmo produto por um valor bem menor.
  2.  O custo de cada ponto: A linha reta prova que, em média, a cada 1% a mais de desconto, o caixa perdeu cerca de R$ 1,95 mil por pedido.
  3.  A diferença nas pontas: Enquanto vendas com apenas 5% de desconto renderam em média R$ 75 mil, os pedidos fechados com mais de 20% de corte mal passaram de R$ 45 mil.

Assim, os dados provaram que dar desconto para todo mundo não fez a empresa crescer.

A prática serviu apenas para dar dinheiro da empresa para o cliente sem ganhar nada a mais em troca.

Regressão Linear em Vendas: Como utilizar as informações para pensar o que mudar na rotina da equipe

O trabalho com números só tem valor se mudar a forma como as pessoas agem.

Com o apoio da regressão linear em vendas, a gestão tomou três passos firmes:

  1. Regras de corte: Descontos acima de 10% passaram a exigir o aval do diretor, com trocas reais no contrato, como pagar à vista ou assinar por mais tempo.
  2. Comissão no lucro: A comissão do time mudou para pagar melhor quem traz margem limpa, e não quem só traz pedidos sem lucro.
  3. Vendas de valor: O time aprendeu a mostrar o ganho que o produto gera antes de ceder ao primeiro pedido de desconto do cliente.

Em suma, aplicar a regressão linear em vendas não pede sistemas caros nem termos difíceis. Fazer o básico bem feito, com dados limpos e figuras fáceis de ler, é o jeito mais seguro de tomar boas decisões e crescer de verdade.

Para vocês que querem acompanhar melhor nossos conteúdos, estaremos atualizando nossos cursos na Udemy com cada um destes casos, assim como nosso Canal do Youtube, onde você encontra informações de Transformação Digital, Dados e liderança.

Passo a passo: código em Python para testar no seu negócio

Se você quiser rodar esse mesmo teste nas suas vendas, pode usar o código abaixo no Google Colab, no computador ou no tablet.

O código roda com pacotes básicos e fáceis de usar:

# ==========================================================
# Importando as bibliotecas necessárias
# ==========================================================
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score

# ==========================================================
# BASE DE DADOS: Simulação do histórico de 120 pedidos
# Criar uma base de dados aleatórios para facilitar sua análise
# ==========================================================

np.random.seed(42)
n_pedidos = 120
desconto_pct = np.random.uniform(2, 25, n_pedidos).round(2)
faturamento_milhares = 85 - 1.9 * desconto_pct + np.random.normal(0, 4.5, n_pedidos).round(2)

df_pedidos = pd.DataFrame({
    'desconto': desconto_pct,
    'faturamento': faturamento_milhares
})

# ==========================================================
# PASSO 1: Análise Inicial e Resumo Estatístico
# Amplitude, média e desvio padrão
# ==========================================================
print("--- PASSO 1: Primeiras Linhas e Resumo Estatístico ---")
print(df_pedidos.head())
print("\nEstatísticas descritivas:")
print(df_pedidos.describe().round(2))

# ==========================================================
# VISUALIZAÇÃO INICIAL: Dispersão Simples dos Pedidos
# ==========================================================

plt.figure(figsize=(8, 5), dpi=120)
plt.scatter(
    df_pedidos['desconto'], 
    df_pedidos['faturamento'], 
    color='#34495e', 
    alpha=0.6, 
    s=45, 
    edgecolors='w', 
    linewidth=0.5
)

plt.title('Distribuição Inicial: Valor do Pedido vs. Desconto', fontsize=11, fontweight='bold', pad=12)
plt.xlabel('Desconto Concedido (%)', fontsize=9)
plt.ylabel('Valor do Pedido (R$ mil)', fontsize=9)
plt.grid(True, linestyle='--', alpha=0.5)
plt.tight_layout()
plt.show()

# ==========================================================
# PASSO 2: Iniciando uma análise do ponto de vista de negócios.
# Intervalos de descontos
# Hipótese: A queda visível do tíquete conforme o desconto sobe
# ==========================================================
df_pedidos['faixa_desconto'] = pd.cut(
    df_pedidos['desconto'],
    bins=[0, 8, 16, 26],
    labels=['Baixo (até 8%)', 'Médio (8% a 16%)', 'Alto (> 16%)']
)

resumo_faixas = df_pedidos.groupby('faixa_desconto', observed=False).agg(
    total_pedidos=('faturamento', 'count'),
    faturamento_medio=('faturamento', 'mean'),
    faturamento_minimo=('faturamento', 'min'),
    faturamento_maximo=('faturamento', 'max')
).round(2)

print("\n--- PASSO 2: Médias por Faixa de Desconto ---")
print(resumo_faixas)

# ==========================================================
# VISUALIZAÇÃO DO PASSO 2: Gráficos de Negócio por Faixa
# ==========================================================
import seaborn as sns
import matplotlib.pyplot as plt

# Garantindo que a coluna 'faixa_desconto' exista no DataFrame caso as células anteriores tenham sido reiniciadas
if 'faixa_desconto' not in df_pedidos.columns:
    df_pedidos['faixa_desconto'] = pd.cut(
        df_pedidos['desconto'],
        bins=[0, 8, 16, 26],
        labels=['Baixo (até 8%)', 'Médio (8% a 16%)', 'Alto (> 16%)']
    )

# Recriando também o resumo_faixas de segurança
resumo_faixas = df_pedidos.groupby('faixa_desconto', observed=False).agg(
    total_pedidos=('faturamento', 'count'),
    faturamento_medio=('faturamento', 'mean'),
    faturamento_minimo=('faturamento', 'min'),
    faturamento_maximo=('faturamento', 'max')
).round(2)

# Configurando o estilo visual dos gráficos
sns.set_theme(style="whitegrid")
fig, axes = plt.subplots(1, 2, figsize=(14, 5), dpi=120)

# Gráfico 1: Faturamento Médio por Faixa de Desconto
sns.barplot(
    x=resumo_faixas.index,
    y='faturamento_medio',
    data=resumo_faixas,
    hue=resumo_faixas.index,
    palette='Blues_r',
    ax=axes[0],
    legend=False
)
axes[0].set_title('Faturamento Médio por Faixa de Desconto', fontsize=11, fontweight='bold', pad=10)
axes[0].set_xlabel('Faixa de Desconto', fontsize=9)
axes[0].set_ylabel('Faturamento Médio (R$ mil)', fontsize=9)

# Adicionando rótulos de valor nas barras do primeiro gráfico
for p in axes[0].patches:
    axes[0].annotate(f"R$ {p.get_height():.2f} mil", 
                    (p.get_x() + p.get_width() / 2., p.get_height()), 
                    ha='center', va='center', 
                    xytext=(0, 8), 
                    textcoords='offset points', fontsize=9, fontweight='bold')

# Gráfico 2: Distribuição dos Pedidos (Boxplot) por Faixa
sns.boxplot(
    x='faixa_desconto',
    y='faturamento',
    data=df_pedidos,
    hue='faixa_desconto',
    palette='Blues_r',
    ax=axes[1],
    legend=False
)
axes[1].set_title('Distribuição de Faturamento por Faixa', fontsize=11, fontweight='bold', pad=10)
axes[1].set_xlabel('Faixa de Desconto', fontsize=9)
axes[1].set_ylabel('Valor do Pedido (R$ mil)', fontsize=9)

plt.tight_layout()
plt.show()

# ==========================================================
# PASSO 3: Existe uma correlação que reforce nossa hipótese?
# Correlação Linear de Pearson
# ==========================================================
correlacao = df_pedidos['desconto'].corr(df_pedidos['faturamento'])
print(f"\n--- PASSO 3: Coeficiente de Correlação de Pearson ---")
print(f"Correlação: {correlacao:.3f} ")

# ==========================================================
# PASSO 4: Treinamento da Regressão Linear Simples
# O R² (poder explicativo) e o impacto de cada 1%
# ==========================================================
X = df_pedidos[['desconto']]
y = df_pedidos['faturamento']

modelo = LinearRegression()
modelo.fit(X, y)
df_pedidos['predicao'] = modelo.predict(X)

r2 = r2_score(y, df_pedidos['predicao'])
valor_perda = abs(modelo.coef_[0])

print("\n--- PASSO 4: Métricas do Modelo ---")
print(f"R² (poder explicativo): {r2:.3f}")
print(f"Perda estimada a cada 1% de desconto: R$ {valor_perda:.2f} mil")

# ==========================================================
# PASSO 5: Gráfico Executivo para Decisão (Data Storytelling)
# Como apresentar para a diretoria? (Conforme sugerido pela IA)
# ==========================================================
plt.figure(figsize=(9, 5), dpi=150)
plt.scatter(df_pedidos['desconto'], df_pedidos['faturamento'],
            color='#34495e', alpha=0.55, s=50, label='Pedidos Fechados')
plt.plot(df_pedidos['desconto'], df_pedidos['predicao'],
         color='#c0392b', linewidth=2.5, label='Linha Média (Regressão)')

plt.title("O Perigo do Desconto: Impacto no Valor Final", fontsize=13, fontweight='bold', pad=15)
plt.xlabel("Desconto Dado (%)", fontsize=10)
plt.ylabel("Valor do Pedido (R$ mil)", fontsize=10)

plt.annotate(f"A cada 1% a mais de desconto,\no pedido perde cerca de R$ {valor_perda:.2f} mil\n(R² = {r2:.2f})",
             xy=(14, modelo.predict([[14]])[0]), xytext=(15.5, 74),
             arrowprops=dict(arrowstyle="->", color='#2c3e50', lw=1.5),
             fontsize=9, bbox=dict(boxstyle="round,pad=0.5", fc="#fdfefe", ec="#bdc3c7", lw=0.8))

plt.grid(True, linestyle='--', alpha=0.5)
plt.legend(frameon=True, facecolor='white', framealpha=0.9, fontsize=9)
plt.tight_layout()
plt.show()

# ==========================================================
# PASSO 6: Encontrando o Ponto de Equilíbrio (Otimização)
# ==========================================================

# Vamos simular que o desconto atrai mais clientes (elasticidade da demanda)
# Se desconto = 0%, vendemos o volume mínimo base. Se damos desconto, o volume cresce.
descontos_simulados = np.linspace(0, 25, 100)

# Modelo de Regressão do faturamento médio por pedido
faturamento_medio_predito = modelo.intercept_ + modelo.coef_[0] * descontos_simulados

# Suposição de Negócio: O volume de pedidos cresce de forma logística ou linear com o desconto.
# Digamos que sem desconto vendemos 50 pedidos, e a 25% de desconto vendemos 150 pedidos.
volume_pedidos_simulado = 50 + 4.0 * descontos_simulados 

# Faturamento Total Acumulado = Faturamento Médio * Volume de Pedidos
faturamento_total = faturamento_medio_predito * volume_pedidos_simulado

# Encontrando o ponto de máximo faturamento total (Ponto de Equilíbrio Ótimo)
indice_otimo = np.argmax(faturamento_total)
desconto_otimo = descontos_simulados[indice_otimo]
faturamento_otimo = faturamento_total[indice_otimo]

# Plotando a curva de otimização
fig, ax1 = plt.subplots(figsize=(10, 5), dpi=120)

color = '#2c3e50'
ax1.set_xlabel('Desconto Concedido (%)', fontsize=10)
ax1.set_ylabel('Faturamento Médio por Pedido (R$ mil)', color=color, fontsize=10)
ax1.plot(descontos_simulados, faturamento_medio_predito, color=color, linestyle='--', linewidth=2, label='Faturamento Médio (Regressão)')
ax1.tick_params(axis='y', labelcolor=color)

ax2 = ax1.twinx()
color = '#27ae60'
ax2.set_ylabel('Faturamento Total Acumulado (R$ mil)', color=color, fontsize=10)
ax2.plot(descontos_simulados, faturamento_total, color=color, linewidth=3, label='Faturamento Total Simulado')
ax2.tick_params(axis='y', labelcolor=color)

# Destacando o ponto de equilíbrio ótimo
ax2.scatter(desconto_otimo, faturamento_otimo, color='#e74c3c', s=120, zorder=5, label='Ponto de Equilíbrio Ótimo')
ax2.annotate(f"Ponto Ótimo: {desconto_otimo:.1f}% de Desconto\nFaturamento Total Máximo: R$ {faturamento_otimo:.1f} mil",
             xy=(desconto_otimo, faturamento_otimo), xytext=(desconto_otimo - 8, faturamento_otimo - 1000),
             arrowprops=dict(arrowstyle="->", color='#e74c3c', lw=1.5),
             fontsize=9.5, fontweight='bold', bbox=dict(boxstyle="round,pad=0.5", fc="#fdfefe", ec="#e74c3c", lw=1))

plt.title("Ponto de Equilíbrio: Faturamento Médio vs. Volume de Vendas", fontsize=12, fontweight='bold', pad=15)
fig.tight_layout()
plt.show()

 

0 comentários

Enviar um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *