# app.py - Dashboard Interativo com Upload de Dados Reais import streamlit as st import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns import joblib from sklearn.metrics import (accuracy_score, precision_score, recall_score, f1_score, roc_auc_score, roc_curve, confusion_matrix) from sklearn.linear_model import LogisticRegression from sklearn.neighbors import KNeighborsClassifier from sklearn.svm import SVC from sklearn.model_selection import train_test_split, cross_val_score from sklearn.preprocessing import StandardScaler, LabelEncoder import plotly.graph_objects as go import time import warnings warnings.filterwarnings('ignore') # Configuração da página st.set_page_config( page_title="Dashboard - Cancelamento de Reservas", page_icon="🏨", layout="wide", initial_sidebar_state="expanded" ) # CSS customizado st.markdown(""" """, unsafe_allow_html=True) class HotelBookingDashboard: def __init__(self): self.models = {} self.results = {} self.X_train = None self.X_test = None self.y_train = None self.y_test = None def load_from_upload(self, uploaded_file): """Carrega dataset do upload do usuário e faz pré-processamento básico""" df = pd.read_csv(uploaded_file) st.success(f"✅ Arquivo carregado com sucesso! {df.shape[0]} linhas × {df.shape[1]} colunas") # Detectar coluna target target = None for c in ['is_canceled', 'is_cancelled', 'canceled', 'cancelled', 'booking_status']: if c in df.columns: target = c break if target is None: st.error("❌ Não foi encontrada a coluna de cancelamento ('is_canceled').") return False if target != 'is_canceled': df.rename(columns={target: 'is_canceled'}, inplace=True) # Remover colunas irrelevantes if 'company' in df.columns: df.drop('company', axis=1, inplace=True) # Tratar nulos for c in df.columns: if df[c].isna().sum() > 0: if df[c].dtype == 'object': df[c].fillna(df[c].mode()[0], inplace=True) else: df[c].fillna(df[c].median(), inplace=True) # Codificar variáveis categóricas cat_cols = df.select_dtypes(include='object').columns for c in cat_cols: if df[c].nunique() == 2: le = LabelEncoder() df[c] = le.fit_transform(df[c]) df = pd.get_dummies(df, drop_first=True) # Separar X e y X = df.drop(columns=['is_canceled']) y = df['is_canceled'] # Split + padronização X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y) scaler = StandardScaler() X_train = scaler.fit_transform(X_train) X_test = scaler.transform(X_test) self.X_train, self.X_test, self.y_train, self.y_test = X_train, X_test, y_train, y_test return True def train_logistic_regression(self, C=1.0, penalty='l2', solver='lbfgs'): model = LogisticRegression(C=C, penalty=penalty, solver=solver, max_iter=1000, random_state=42) start_time = time.time() model.fit(self.X_train, self.y_train) training_time = time.time() - start_time return model, training_time def train_knn(self, n_neighbors=5, metric='euclidean', weights='uniform'): model = KNeighborsClassifier(n_neighbors=n_neighbors, metric=metric, weights=weights) start_time = time.time() model.fit(self.X_train, self.y_train) training_time = time.time() - start_time return model, training_time def train_svm(self, C=1.0, kernel='rbf', gamma='scale'): model = SVC(C=C, kernel=kernel, gamma=gamma, probability=True, random_state=42) start_time = time.time() model.fit(self.X_train, self.y_train) training_time = time.time() - start_time return model, training_time def evaluate_model(self, model, training_time): y_pred = model.predict(self.X_test) y_proba = model.predict_proba(self.X_test)[:, 1] metrics = { 'Acurácia': accuracy_score(self.y_test, y_pred), 'Precisão': precision_score(self.y_test, y_pred, zero_division=0), 'Recall': recall_score(self.y_test, y_pred, zero_division=0), 'F1-Score': f1_score(self.y_test, y_pred, zero_division=0), 'AUC-ROC': roc_auc_score(self.y_test, y_proba), 'Tempo Treino (s)': training_time } fpr, tpr, _ = roc_curve(self.y_test, y_proba) cm = confusion_matrix(self.y_test, y_pred) return metrics, {'fpr': fpr, 'tpr': tpr, 'auc': metrics['AUC-ROC']}, cm def plot_roc(self, roc_data, model_name): fig = go.Figure() fig.add_trace(go.Scatter(x=roc_data['fpr'], y=roc_data['tpr'], mode='lines', name=f"{model_name} (AUC = {roc_data['auc']:.3f})", line=dict(color='blue', width=3))) fig.add_trace(go.Scatter(x=[0, 1], y=[0, 1], mode='lines', name='Aleatório', line=dict(color='gray', dash='dash'))) fig.update_layout(title='Curva ROC', xaxis_title='Falsos Positivos', yaxis_title='Verdadeiros Positivos', width=600, height=500) return fig def main(): st.markdown('