brunaaaz commited on
Commit
ce82fea
·
verified ·
1 Parent(s): a605cf7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +51 -20
app.py CHANGED
@@ -30,7 +30,12 @@ st.set_page_config(
30
 
31
  # --- Título e Contexto ---
32
  st.title("🏨 Dashboard de Previsão de Cancelamento de Reservas")
33
-
 
 
 
 
 
34
 
35
 
36
  # --- Funções de Processamento (Otimizadas com Cache) ---
@@ -53,35 +58,27 @@ def preprocess_data(df):
53
  df_proc = df.copy()
54
 
55
  # 1. Tratamento de valores faltantes
56
- # Preenche 'country' com a moda (mais comum)
57
  df_proc["country"].fillna(df_proc["country"].mode()[0], inplace=True)
58
- # Para 'agent' e 'company', NaN significa "Não Aplicável" ou "Direto". Substituímos por 0.
59
  df_proc["agent"].fillna(0, inplace=True)
60
  df_proc["company"].fillna(0, inplace=True)
61
- # Assume que NaN em 'children' significa 0 crianças.
62
  df_proc["children"].fillna(0, inplace=True)
63
 
64
  # 2. Tratamento de Outliers (simples, para performance)
65
- # Remove 'adr' (Average Daily Rate) irrealista
66
  df_proc = df_proc[(df_proc["adr"] >= 0) & (df_proc["adr"] < 5000)]
67
 
68
  # 3. Engenharia de Features (simples)
69
- # Cria 'total_stay' e 'total_guests'
70
  df_proc["total_stay"] = (
71
  df_proc["stays_in_weekend_nights"] + df_proc["stays_in_week_nights"]
72
  )
73
  df_proc["total_guests"] = (
74
  df_proc["adults"] + df_proc["children"] + df_proc["babies"]
75
  )
76
-
77
- # Remove hóspedes com 0 pessoas (inválido)
78
  df_proc = df_proc[df_proc["total_guests"] > 0]
79
 
80
  # 4. Seleção de Variáveis (Baseado na Tarefa 3 - 8 a 15 features)
81
- # Variável Alvo
82
  y = df_proc["is_canceled"]
83
 
84
- # Features Numéricas
85
  numeric_features = [
86
  "lead_time",
87
  "total_stay",
@@ -94,7 +91,6 @@ def preprocess_data(df):
94
  "total_of_special_requests",
95
  ]
96
 
97
- # Features Categóricas
98
  categorical_features = [
99
  "hotel",
100
  "market_segment",
@@ -104,7 +100,6 @@ def preprocess_data(df):
104
  "is_repeated_guest",
105
  ]
106
 
107
- # Garante que todas as colunas existem
108
  all_features = numeric_features + categorical_features
109
  df_features = df_proc[all_features]
110
 
@@ -120,7 +115,7 @@ def get_model(algorithm, params):
120
  if algorithm == "Regressão Logística":
121
  model = LogisticRegression(
122
  C=params["C_rl"],
123
- solver="liblinear", # Bom para datasets menores e binários
124
  random_state=42,
125
  max_iter=1000,
126
  )
@@ -133,7 +128,7 @@ def get_model(algorithm, params):
133
  C=params["C_svm"],
134
  kernel=params["kernel"],
135
  gamma=params["gamma"] if params["kernel"] == "rbf" else "auto",
136
- probability=True, # Necessário para Curva ROC
137
  random_state=42,
138
  )
139
  return model
@@ -162,7 +157,6 @@ def plot_roc_curve(y_test, y_proba, auc):
162
  def plot_confusion_matrix(y_test, y_pred):
163
  """Plota a Matriz de Confusão usando Plotly."""
164
  cm = confusion_matrix(y_test, y_pred)
165
- cm_text = [[str(y) for y in x] for x in cm]
166
 
167
  fig = px.imshow(
168
  cm,
@@ -274,6 +268,9 @@ if df_original is not None:
274
 
275
  # 2. Pré-processar
276
  X, y = preprocess_data(df_sample)
 
 
 
277
 
278
  # 3. Dividir (Train/Test)
279
  X_train, X_test, y_train, y_test = train_test_split(
@@ -281,6 +278,8 @@ if df_original is not None:
281
  )
282
 
283
  # 4. Escalonar (MUITO importante para KNN e SVM)
 
 
284
  scaler = StandardScaler()
285
  X_train_scaled = scaler.fit_transform(X_train)
286
  X_test_scaled = scaler.transform(X_test)
@@ -301,7 +300,6 @@ if df_original is not None:
301
  report = classification_report(y_test, y_pred, output_dict=True)
302
  report_df = pd.DataFrame(report).transpose()
303
 
304
- # Extrai métricas específicas para classe 1 (Cancelamento)
305
  (
306
  precision,
307
  recall,
@@ -339,6 +337,42 @@ if df_original is not None:
339
 
340
  st.subheader("Relatório de Classificação Detalhado")
341
  st.dataframe(report_df.style.format("{:.3f}"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
 
343
  # --- Interpretação Gerencial Automática ---
344
  st.header("💡 Interpretação Gerencial e Recomendações")
@@ -348,7 +382,7 @@ if df_original is not None:
348
  if algorithm == "Regressão Logística":
349
  st.markdown("""
350
  **O que é?** Um modelo estatístico que calcula a *probabilidade* de cancelamento. É o modelo mais fácil de interpretar.
351
- **Ponto Forte (Interpretabilidade):** Podemos ver exatamente quais fatores (como `lead_time` ou `deposit_type`) mais aumentam ou diminuem as chances de cancelamento.
352
  **Ponto Fraco:** Pode não capturar relações complexas entre as variáveis.
353
  """)
354
  elif algorithm == "KNN":
@@ -390,9 +424,6 @@ if df_original is not None:
390
  3. **Para Eficiência Operacional (Maximizar a *Precisão*):**
391
  * **Vencedor:** Geralmente **Regressão Logística** ou **SVM (linear)**.
392
  * **Ação:** Se temos uma equipe de retenção pequena e cara (ex: ligações telefônicas), queremos ter certeza de que cada reserva sinalizada é *realmente* de alto risco. Priorizamos a **Precisão**.
393
-
394
- **Recomendação Prática (Exemplo):**
395
- "O modelo de Regressão Logística (AUC de ~0.85) mostrou que reservas do tipo 'Transient' (não-grupo) com `deposit_type` = 'Non Refund' e `lead_time` > 120 dias têm 70% mais chance de cancelar. Recomenda-se uma política de overbooking de 3% para esse segmento específico ou um contato proativo 60 dias antes do check-in."
396
  """)
397
 
398
  else:
 
30
 
31
  # --- Título e Contexto ---
32
  st.title("🏨 Dashboard de Previsão de Cancelamento de Reservas")
33
+ st.markdown(
34
+ """
35
+ **Sua Missão como Analista de Dados:**
36
+ Você é analista de dados em uma rede internacional de hotéis. Sua missão é desenvolver e comparar três modelos preditivos (Regressão Logística, KNN e SVM) capazes de identificar antecipadamente as reservas com maior probabilidade de cancelamento. Esta ferramenta permite simular esse processo de forma interativa.
37
+ """
38
+ )
39
 
40
 
41
  # --- Funções de Processamento (Otimizadas com Cache) ---
 
58
  df_proc = df.copy()
59
 
60
  # 1. Tratamento de valores faltantes
 
61
  df_proc["country"].fillna(df_proc["country"].mode()[0], inplace=True)
 
62
  df_proc["agent"].fillna(0, inplace=True)
63
  df_proc["company"].fillna(0, inplace=True)
 
64
  df_proc["children"].fillna(0, inplace=True)
65
 
66
  # 2. Tratamento de Outliers (simples, para performance)
 
67
  df_proc = df_proc[(df_proc["adr"] >= 0) & (df_proc["adr"] < 5000)]
68
 
69
  # 3. Engenharia de Features (simples)
 
70
  df_proc["total_stay"] = (
71
  df_proc["stays_in_weekend_nights"] + df_proc["stays_in_week_nights"]
72
  )
73
  df_proc["total_guests"] = (
74
  df_proc["adults"] + df_proc["children"] + df_proc["babies"]
75
  )
 
 
76
  df_proc = df_proc[df_proc["total_guests"] > 0]
77
 
78
  # 4. Seleção de Variáveis (Baseado na Tarefa 3 - 8 a 15 features)
79
+ # Esta seleção é manual para garantir performance e relevância
80
  y = df_proc["is_canceled"]
81
 
 
82
  numeric_features = [
83
  "lead_time",
84
  "total_stay",
 
91
  "total_of_special_requests",
92
  ]
93
 
 
94
  categorical_features = [
95
  "hotel",
96
  "market_segment",
 
100
  "is_repeated_guest",
101
  ]
102
 
 
103
  all_features = numeric_features + categorical_features
104
  df_features = df_proc[all_features]
105
 
 
115
  if algorithm == "Regressão Logística":
116
  model = LogisticRegression(
117
  C=params["C_rl"],
118
+ solver="liblinear",
119
  random_state=42,
120
  max_iter=1000,
121
  )
 
128
  C=params["C_svm"],
129
  kernel=params["kernel"],
130
  gamma=params["gamma"] if params["kernel"] == "rbf" else "auto",
131
+ probability=True,
132
  random_state=42,
133
  )
134
  return model
 
157
  def plot_confusion_matrix(y_test, y_pred):
158
  """Plota a Matriz de Confusão usando Plotly."""
159
  cm = confusion_matrix(y_test, y_pred)
 
160
 
161
  fig = px.imshow(
162
  cm,
 
268
 
269
  # 2. Pré-processar
270
  X, y = preprocess_data(df_sample)
271
+
272
+ # **NOVO**: Captura os nomes das features APÓS o get_dummies
273
+ feature_names = X.columns.tolist()
274
 
275
  # 3. Dividir (Train/Test)
276
  X_train, X_test, y_train, y_test = train_test_split(
 
278
  )
279
 
280
  # 4. Escalonar (MUITO importante para KNN e SVM)
281
+ # Nota: RL com 'liblinear' não precisa de escalonamento,
282
+ # mas vamos manter para consistência e performance.
283
  scaler = StandardScaler()
284
  X_train_scaled = scaler.fit_transform(X_train)
285
  X_test_scaled = scaler.transform(X_test)
 
300
  report = classification_report(y_test, y_pred, output_dict=True)
301
  report_df = pd.DataFrame(report).transpose()
302
 
 
303
  (
304
  precision,
305
  recall,
 
337
 
338
  st.subheader("Relatório de Classificação Detalhado")
339
  st.dataframe(report_df.style.format("{:.3f}"))
340
+
341
+ # --- [NOVA SEÇÃO ADICIONADA] ---
342
+ # Interpretação específica da Regressão Logística
343
+ if algorithm == "Regressão Logística":
344
+ st.subheader("Análise de Coeficientes (Interpretabilidade)")
345
+
346
+ # Captura coeficientes e odds ratios
347
+ coefs = model.coef_[0]
348
+ odds_ratios = np.exp(coefs)
349
+
350
+ df_coef = pd.DataFrame({
351
+ 'Variável': feature_names,
352
+ 'Coeficiente (Log-Odds)': coefs,
353
+ 'Odds Ratio (Razão de Chances)': odds_ratios
354
+ })
355
+
356
+ df_coef = df_coef.sort_values(by="Odds Ratio", ascending=False)
357
+
358
+ st.dataframe(df_coef.style.format({
359
+ 'Coeficiente (Log-Odds)': '{:.4f}',
360
+ 'Odds Ratio (Razão de Chances)': '{:.3f}'
361
+ }).background_gradient(
362
+ cmap='RdBu_r',
363
+ subset=['Odds Ratio', 'Coeficiente (Log-Odds)'])
364
+ )
365
+
366
+ st.markdown("""
367
+ **Como interpretar esta tabela:**
368
+ * **Odds Ratio > 1 (Azul):** Aumenta a chance de cancelamento.
369
+ * *Exemplo: Se `lead_time` tem Odds Ratio de 1.02, cada dia extra de antecedência aumenta a chance de cancelar em 2%.*
370
+ * **Odds Ratio < 1 (Vermelho):** Diminui a chance de cancelamento (fator de proteção).
371
+ * *Exemplo: Se `deposit_type_Non Refund` tem Odds Ratio de 0.20, ter um depósito não-reembolsável reduz a chance de cancelar em 80%.*
372
+ * **Odds Ratio = 1:** Não tem efeito.
373
+ """)
374
+ # --- [FIM DA NOVA SEÇÃO] ---
375
+
376
 
377
  # --- Interpretação Gerencial Automática ---
378
  st.header("💡 Interpretação Gerencial e Recomendações")
 
382
  if algorithm == "Regressão Logística":
383
  st.markdown("""
384
  **O que é?** Um modelo estatístico que calcula a *probabilidade* de cancelamento. É o modelo mais fácil de interpretar.
385
+ **Ponto Forte (Interpretabilidade):** Como visto na tabela acima, podemos ver exatamente quais fatores (como `lead_time` ou `deposit_type`) mais aumentam ou diminuem as chances de cancelamento.
386
  **Ponto Fraco:** Pode não capturar relações complexas entre as variáveis.
387
  """)
388
  elif algorithm == "KNN":
 
424
  3. **Para Eficiência Operacional (Maximizar a *Precisão*):**
425
  * **Vencedor:** Geralmente **Regressão Logística** ou **SVM (linear)**.
426
  * **Ação:** Se temos uma equipe de retenção pequena e cara (ex: ligações telefônicas), queremos ter certeza de que cada reserva sinalizada é *realmente* de alto risco. Priorizamos a **Precisão**.
 
 
 
427
  """)
428
 
429
  else: