bfiguei commited on
Commit
9fd4111
·
verified ·
1 Parent(s): 01e3a40

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +100 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,102 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
1
  import streamlit as st
2
+ import pandas as pd
3
+ import matplotlib.pyplot as plt
4
+ from math import comb
5
+
6
+ # -------------------------------
7
+ # Funções auxiliares
8
+ # -------------------------------
9
+ def validar_probabilidade(p: float) -> None:
10
+ if not (0.0 <= p <= 1.0):
11
+ raise ValueError("Erro: probabilidade deve estar entre 0 e 1.")
12
+
13
+ def validar_capacidade(capacidade: int) -> None:
14
+ if capacidade < 0:
15
+ raise ValueError("Erro: capacidade deve ser maior ou igual a zero.")
16
+
17
+ def validar_passagens(vendidas: int, capacidade: int) -> None:
18
+ if vendidas < capacidade:
19
+ raise ValueError("Erro: passagens vendidas devem ser ≥ capacidade.")
20
+
21
+ def formatar_pct(x: float) -> str:
22
+ return f"{x*100:.2f}%"
23
+
24
+ # -------------------------------
25
+ # Funções de Overbooking (Binomial)
26
+ # -------------------------------
27
+ def prob_overbooking(vendidas: int, capacidade: int, p: float) -> float:
28
+ validar_capacidade(capacidade); validar_passagens(vendidas, capacidade); validar_probabilidade(p)
29
+ prob = 0.0
30
+ for x in range(capacidade+1, vendidas+1):
31
+ prob += comb(vendidas, x) * (p**x) * ((1-p)**(vendidas-x))
32
+ return prob
33
+
34
+ def curva_risco(capacidade: int, p: float, max_extra: int = 20) -> pd.DataFrame:
35
+ validar_capacidade(capacidade); validar_probabilidade(p)
36
+ dados = []
37
+ for vendidas in range(capacidade, capacidade+max_extra+1):
38
+ dados.append({"vendidas": vendidas, "risco": prob_overbooking(vendidas, capacidade, p)})
39
+ return pd.DataFrame(dados)
40
+
41
+ def max_vendidas_com_limite(capacidade: int, p: float, limite: float = 0.07, max_extra: int = 40):
42
+ df = curva_risco(capacidade, p, max_extra)
43
+ ok = df[df["risco"] <= limite]
44
+ return int(ok["vendidas"].max()) if not ok.empty else None
45
+
46
+ # -------------------------------
47
+ # Layout do App
48
+ # -------------------------------
49
+ st.set_page_config(page_title="Overbooking (Binomial)", layout="wide")
50
+
51
+ # Introdução em Markdown
52
+ st.markdown(
53
+ """
54
+ # Análise de Distribuição Binomial
55
+ ### Simulação de Overbooking em Voos
56
+ ---
57
+ Este aplicativo permite analisar o risco de **overbooking** em voos,
58
+ utilizando a **Distribuição Binomial**.
59
+ Ajuste os parâmetros nos controles abaixo e visualize:
60
+
61
+ - A **probabilidade de overbooking** para um número de passagens vendidas.
62
+ - A **curva de risco** conforme aumentam as vendas acima da capacidade.
63
+ - O número máximo de passagens que pode ser vendido sem ultrapassar
64
+ o **nível de risco aceito**.
65
+ """
66
+ )
67
+
68
+ # Entradas
69
+ col1, col2, col3 = st.columns(3)
70
+ with col1:
71
+ capacidade = st.slider("Capacidade do Avião (assentos)", 50, 600, 120)
72
+ with col2:
73
+ vendidas = st.slider("Passagens Vendidas", capacidade, capacidade+80, capacidade+10)
74
+ with col3:
75
+ p = st.slider("Prob. de Comparecimento (p)", 0.5, 0.99, 0.88, 0.01)
76
+
77
+ limite = st.slider("Nível de Risco Aceito", 0.0, 0.30, 0.07, 0.01)
78
+ max_extra = st.slider("Faixa analisada (capacidade + ...)", 10, 120, 40, 5)
79
+
80
+ # Cálculos
81
+ risco_pontual = prob_overbooking(vendidas, capacidade, p)
82
+ df = curva_risco(capacidade, p, max_extra)
83
+ nmax = max_vendidas_com_limite(capacidade, p, limite, max_extra)
84
+
85
+ # Métricas
86
+ m1, m2, m3 = st.columns(3)
87
+ m1.metric("Risco atual", formatar_pct(risco_pontual))
88
+ m2.metric("Capacidade", capacidade)
89
+ m3.metric("Máx. vendidas com risco ≤ limite", f"{nmax}" if nmax else "—")
90
+
91
+ # Gráfico
92
+ fig, ax = plt.subplots()
93
+ ax.plot(df["vendidas"], df["risco"], marker="o")
94
+ ax.axhline(limite, linestyle="--", color="red", label="Limite de risco")
95
+ ax.set_xlabel("Passagens vendidas")
96
+ ax.set_ylabel("Probabilidade de overbooking")
97
+ ax.legend()
98
+ st.pyplot(fig)
99
 
100
+ # Tabela
101
+ with st.expander("Ver tabela de valores"):
102
+ st.dataframe(df)