Spaces:
Sleeping
Sleeping
File size: 5,069 Bytes
69485c9 326e2bb 69485c9 9fd4111 69485c9 9fd4111 69485c9 9fd4111 69485c9 9fd4111 69485c9 9fd4111 8c415e0 69485c9 8c415e0 69485c9 9fd4111 69485c9 8c415e0 9fd4111 69485c9 9fd4111 69485c9 9fd4111 69485c9 9fd4111 69485c9 9fd4111 69485c9 8c415e0 69485c9 8c415e0 69485c9 9fd4111 69485c9 8c415e0 69485c9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
#!/usr/bin/env python
# coding: utf-8
import streamlit as st
import numpy as np
import pandas as pd
import plotly.graph_objects as go
from scipy.stats import binom
# =========================
# Configuração de página + estilo
# =========================
st.set_page_config(
page_title="Análise de Distribuição Binomial – Overbooking",
layout="wide",
initial_sidebar_state="expanded"
)
# Slider e detalhes em tema escuro (simples)
st.markdown(
"""
<style>
.stSlider > div > div > div > div > div > div {background-color: #C0392B !important;}
.big-title {text-align:center; color:#0d47a1;}
.sub-title {text-align:center; color:#0d47a1;}
</style>
""",
unsafe_allow_html=True,
)
# =========================
# Cabeçalho
# =========================
st.markdown("<h1 class='big-title'>Análise de Distribuição Binomial</h1>", unsafe_allow_html=True)
st.markdown("<h3 class='sub-title'>Simulação de Overbooking em Voos</h3>", unsafe_allow_html=True)
st.markdown("---")
# =========================
# Funções utilitárias
# =========================
def formatar_pct(x: float) -> str:
return f"{x*100:.2f}%"
def clamp_vendidas():
"""Garante vendidas >= capacidade sem causar 'tremedeira'."""
cap = st.session_state.capacidade
if st.session_state.vendidas < cap:
st.session_state.vendidas = cap
# =========================
# Parâmetros (no estilo do professor)
# =========================
st.markdown("### Distribuição Binomial — Simulação de Overbooking")
col1, col2, col3, col4 = st.columns(4)
with col1:
st.markdown("<h4 style='color:#0d47a1;'>Probabilidade de Comparecimento (p)</h4>", unsafe_allow_html=True)
st.slider("", min_value=0.50, max_value=0.99, value=0.88, step=0.01, key="p")
with col2:
st.markdown("<h4 style='color:#0d47a1;'>Capacidade do Avião</h4>", unsafe_allow_html=True)
st.slider("", min_value=60, max_value=300, value=120, step=1,
key="capacidade", on_change=clamp_vendidas)
with col3:
st.markdown("<h4 style='color:#0d47a1;'>Passagens Vendidas</h4>", unsafe_allow_html=True)
# intervalo amplo e independente; clamp ajusta se ficar < capacidade
st.slider("", min_value=60, max_value=380, value=130, step=1,
key="vendidas", on_change=clamp_vendidas)
with col4:
st.markdown("<h4 style='color:#0d47a1;'>Nível de Risco Aceito (%)</h4>", unsafe_allow_html=True)
st.slider("", min_value=0.01, max_value=0.30, value=0.07, step=0.01, key="limite")
# faixa da curva (capacidade até capacidade+max_extra)
st.markdown("<h4 style='color:#0d47a1;'>Faixa da Curva (capacidade + ...)</h4>", unsafe_allow_html=True)
max_extra = st.slider("", min_value=10, max_value=120, value=40, step=5)
# Valores finais
p = float(st.session_state.p)
capacidade = int(st.session_state.capacidade)
vendidas = int(max(st.session_state.vendidas, capacidade))
limite = float(st.session_state.limite)
# =========================
# Cálculos (SciPy Binomial)
# =========================
# Risco pontual: P(X > capacidade) = 1 - CDF(capacidade)
risco_pontual = 1.0 - binom.cdf(capacidade, vendidas, p)
# Curva: de capacidade até capacidade+max_extra
vendidas_range = np.arange(capacidade, capacidade + max_extra + 1)
riscos = 1.0 - binom.cdf(capacidade, vendidas_range, p)
# Tabela
tabela = pd.DataFrame(
{"Passagens vendidas": vendidas_range, "Risco de Overbooking": riscos}
)
# Máximo de vendidas respeitando o limite
ok = tabela[tabela["Risco de Overbooking"] <= limite]
max_seguro = int(ok["Passagens vendidas"].max()) if not ok.empty else None
# =========================
# Métricas
# =========================
m1, m2, m3, m4 = st.columns(4)
m1.metric("Risco atual (P>X_cap)", formatar_pct(risco_pontual))
m2.metric("Capacidade", capacidade)
m3.metric("Vendidas (ponto atual)", vendidas)
m4.metric("Máximo com risco ≤ limite", f"{max_seguro}" if max_seguro else "—")
# =========================
# Gráfico (Plotly)
# =========================
fig = go.Figure()
fig.add_trace(go.Scatter(
x=vendidas_range,
y=riscos,
mode="lines",
line=dict(color="#003366", width=3),
name="Risco de Overbooking"
))
fig.add_hline(y=limite, line_dash="dash", line_color="red", line_width=1, name="Limite")
fig.update_layout(
title=f"Risco de Overbooking para mais de {capacidade} passageiros",
xaxis_title="Passagens vendidas",
yaxis_title=f"Probabilidade de mais de {capacidade} passageiros aparecerem",
xaxis=dict(tickmode="linear"),
yaxis=dict(range=[0, 1]),
plot_bgcolor="white",
width=900,
height=420,
showlegend=False,
)
st.plotly_chart(fig, use_container_width=True)
# =========================
# Tabela
# =========================
st.write("### Tabela de Probabilidades")
st.dataframe(tabela, use_container_width=True)
if max_seguro is not None:
st.info(f"▶ Máximo de passagens com risco ≤ {formatar_pct(limite)}: **{max_seguro}**.")
else:
st.warning(f"Nenhum valor de venda dentro do limite de {formatar_pct(limite)} na faixa analisada.")
|