Spaces:
Sleeping
Sleeping
| """ | |
| Aplicação Streamlit para visualizar dados, treinar modelos | |
| e avaliar a previsão de reclamações de clientes. | |
| Esta app atende aos requisitos do bônus: | |
| - Visualização com filtros dos dados; | |
| - Seleção dinâmica de variáveis para modelagem; | |
| - Exibição das métricas e curvas preditivas; | |
| - Interpretação automática baseada na importância das variáveis. | |
| """ | |
| from typing import List | |
| import matplotlib.pyplot as plt | |
| import pandas as pd | |
| import seaborn as sns | |
| import streamlit as st | |
| from sklearn.metrics import confusion_matrix | |
| from src.utils import ( | |
| carregar_dados, | |
| preparar_base, | |
| treinar_modelo, | |
| avaliar_modelo, | |
| calcular_curva_roc, | |
| obter_importancias, | |
| ) | |
| def interpretar_importancias(df_imp: pd.DataFrame, top_n: int = 3) -> str: | |
| """ | |
| Gera um texto simples de interpretação com base nas variáveis mais importantes. | |
| Parâmetros: | |
| df_imp: DataFrame com colunas 'Variavel' e 'Importancia'. | |
| top_n: número de variáveis a destacar. | |
| Retorno: | |
| Texto em português com interpretação básica. | |
| """ | |
| if df_imp.empty: | |
| return ( | |
| "Não foi possível identificar variáveis importantes para este modelo. " | |
| "Verifique se as variáveis selecionadas são adequadas." | |
| ) | |
| top_vars: List[str] = df_imp.head(top_n)["Variavel"].tolist() | |
| texto = ( | |
| "Com base nas importâncias calculadas, as variáveis mais relevantes para " | |
| "prever reclamações foram: " | |
| + ", ".join(top_vars) | |
| + ". Isso sugere que clientes associados a estas variáveis " | |
| "apresentam maior probabilidade de registrar insatisfações e podem ser " | |
| "priorizados em ações de atendimento preventivo." | |
| ) | |
| return texto | |
| def rodar_dashboard() -> None: | |
| """Executa a interface Streamlit do dashboard.""" | |
| st.set_page_config(page_title="Tarefa 4 - Reclamações", layout="wide") | |
| st.title("📊 Tarefa 4 – Previsão de Reclamações de Clientes") | |
| st.sidebar.header("Configurações") | |
| st.sidebar.write("Carregue a base `marketing_campaign.csv` para iniciar.") | |
| # Upload do CSV | |
| arquivo = st.sidebar.file_uploader( | |
| "Selecione o arquivo CSV", | |
| type=["csv"], | |
| help="Use a base original marketing_campaign.csv", | |
| ) | |
| aplicar_smote = st.sidebar.checkbox( | |
| "Aplicar SMOTE (balancear classes)", value=True | |
| ) | |
| nome_modelo = st.sidebar.selectbox( | |
| "Modelo de classificação", | |
| ["Regressão Logística", "Random Forest", "LightGBM"], | |
| ) | |
| if arquivo is None: | |
| st.info("⬅ Faça o upload do arquivo CSV na barra lateral para começar.") | |
| return | |
| # Carregar dados | |
| try: | |
| df = carregar_dados(arquivo) | |
| except Exception as exc: # noqa: BLE001 | |
| st.error(f"Erro ao carregar dados: {exc}") | |
| return | |
| st.subheader("👀 Pré-visualização dos dados") | |
| st.dataframe(df.head()) | |
| # Filtros simples | |
| st.subheader("🔍 Filtros básicos") | |
| filtros = {} | |
| col1, col2 = st.columns(2) | |
| if "Marital_Status" in df.columns: | |
| opcoes_ms = ["(Todos)"] + sorted(df["Marital_Status"].dropna().unique().tolist()) | |
| escolha_ms = col1.selectbox("Filtrar por estado civil", opcoes_ms) | |
| if escolha_ms != "(Todos)": | |
| filtros["Marital_Status"] = escolha_ms | |
| if "Education" in df.columns: | |
| opcoes_ed = ["(Todos)"] + sorted(df["Education"].dropna().unique().tolist()) | |
| escolha_ed = col2.selectbox("Filtrar por nível educacional", opcoes_ed) | |
| if escolha_ed != "(Todos)": | |
| filtros["Education"] = escolha_ed | |
| df_filtrado = df.copy() | |
| for coluna, valor in filtros.items(): | |
| df_filtrado = df_filtrado[df_filtrado[coluna] == valor] | |
| st.write(f"Número de linhas após filtros: **{df_filtrado.shape[0]}**") | |
| st.dataframe(df_filtrado.head()) | |
| # Preparar base | |
| st.subheader("⚙️ Preparação da base para modelagem") | |
| try: | |
| df_para_modelo = df_filtrado if df_filtrado.shape[0] > 50 else df | |
| X_train, X_test, y_train, y_test, feature_names, scaler = preparar_base( | |
| df_para_modelo, aplicar_smote=aplicar_smote | |
| ) | |
| st.success("Base preparada com sucesso!") | |
| st.write(f"Total de variáveis após tratamento: **{len(feature_names)}**") | |
| except Exception as exc: # noqa: BLE001 | |
| st.error(f"Erro ao preparar a base: {exc}") | |
| return | |
| # Seleção dinâmica de variáveis | |
| st.subheader("🧩 Seleção de variáveis para o modelo") | |
| features_selecionadas = st.multiselect( | |
| "Escolha as variáveis explicativas:", | |
| feature_names, | |
| default=feature_names, | |
| help="Você pode reduzir o modelo selecionando apenas algumas variáveis.", | |
| ) | |
| if not features_selecionadas: | |
| st.warning("Selecione ao menos uma variável para treinar o modelo.") | |
| return | |
| indices = [feature_names.index(f) for f in features_selecionadas] | |
| X_train_sel = X_train[:, indices] | |
| X_test_sel = X_test[:, indices] | |
| # Treinamento e avaliação | |
| st.subheader("🤖 Treinamento e avaliação") | |
| if st.button("Treinar modelo e calcular métricas"): | |
| with st.spinner("Treinando modelo e calculando métricas..."): | |
| try: | |
| modelo = treinar_modelo(nome_modelo, X_train_sel, y_train) | |
| except Exception as exc: # noqa: BLE001 | |
| st.error(f"Erro ao treinar o modelo: {exc}") | |
| return | |
| metricas = avaliar_modelo(modelo, X_test_sel, y_test) | |
| st.write("### 📈 Métricas de desempenho") | |
| st.table(pd.DataFrame([metricas])) | |
| # Curva ROC | |
| fpr, tpr, auc = calcular_curva_roc(modelo, X_test_sel, y_test) | |
| fig_roc, ax_roc = plt.subplots(figsize=(6, 4)) | |
| ax_roc.plot(fpr, tpr, label=f"AUC = {auc:.3f}") | |
| ax_roc.plot([0, 1], [0, 1], linestyle="--", color="gray") | |
| ax_roc.set_xlabel("False Positive Rate") | |
| ax_roc.set_ylabel("True Positive Rate") | |
| ax_roc.set_title("Curva ROC") | |
| ax_roc.legend() | |
| st.pyplot(fig_roc) | |
| # Matriz de confusão | |
| st.write("### 🧮 Matriz de confusão") | |
| y_pred = modelo.predict(X_test_sel) | |
| cm = confusion_matrix(y_test, y_pred) | |
| fig_cm, ax_cm = plt.subplots(figsize=(4, 3)) | |
| sns.heatmap(cm, annot=True, fmt="d", cmap="Blues", cbar=False, ax=ax_cm) | |
| ax_cm.set_xlabel("Previsto") | |
| ax_cm.set_ylabel("Real") | |
| st.pyplot(fig_cm) | |
| # Importância das variáveis | |
| st.write("### ⭐ Importância das variáveis") | |
| df_imp = obter_importancias(modelo, features_selecionadas) | |
| st.dataframe(df_imp.head(15)) | |
| fig_imp, ax_imp = plt.subplots(figsize=(8, 5)) | |
| sns.barplot( | |
| data=df_imp.head(10), | |
| x="Importancia", | |
| y="Variavel", | |
| ax=ax_imp, | |
| ) | |
| ax_imp.set_title("Top variáveis mais importantes") | |
| st.pyplot(fig_imp) | |
| # Interpretação automática | |
| st.write("### 🧠 Interpretação automática") | |
| texto_interpretacao = interpretar_importancias(df_imp) | |
| st.write(texto_interpretacao) | |
| if __name__ == "__main__": | |
| rodar_dashboard() | |