Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -18,9 +18,7 @@ import warnings
|
|
| 18 |
# Configuração da Página
|
| 19 |
st.set_page_config(page_title="CrediFast - Risco de Crédito", layout="wide", page_icon="💰")
|
| 20 |
|
| 21 |
-
#
|
| 22 |
-
# st.set_option('deprecation.showPyplotGlobalUse', False)
|
| 23 |
-
|
| 24 |
warnings.filterwarnings('ignore')
|
| 25 |
|
| 26 |
# Título e Cabeçalho
|
|
@@ -30,16 +28,13 @@ st.markdown("---")
|
|
| 30 |
# --- FUNÇÕES DE CACHE (Para performance) ---
|
| 31 |
|
| 32 |
@st.cache_data
|
| 33 |
-
def carregar_dados(
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
except:
|
| 41 |
-
return None
|
| 42 |
-
return df
|
| 43 |
|
| 44 |
@st.cache_data
|
| 45 |
def processar_dados(df):
|
|
@@ -83,26 +78,28 @@ def treinar_modelo(X, y):
|
|
| 83 |
X_test_final = pd.DataFrame(X_test_scaled, columns=feature_names)
|
| 84 |
|
| 85 |
# Treinamento XGBoost
|
| 86 |
-
|
|
|
|
| 87 |
model.fit(X_train_final, y_train_bal)
|
| 88 |
|
| 89 |
return model, scaler, X_test_final, y_test, X_train_final, feature_names
|
| 90 |
|
| 91 |
-
# ---
|
| 92 |
-
st.sidebar.header("📂 Configuração")
|
| 93 |
-
uploaded_file = st.sidebar.file_uploader("Upload do CSV (credit_risk_dataset.csv)", type="csv")
|
| 94 |
|
| 95 |
-
|
|
|
|
| 96 |
|
| 97 |
if df_raw is not None:
|
| 98 |
-
# Processamento
|
| 99 |
-
|
|
|
|
| 100 |
X, y, df_clean = processar_dados(df_raw)
|
| 101 |
model, scaler, X_test, y_test, X_train, feature_names = treinar_modelo(X, y)
|
| 102 |
|
| 103 |
-
|
|
|
|
|
|
|
| 104 |
|
| 105 |
-
# Simulador (Bônus)
|
| 106 |
st.sidebar.markdown("---")
|
| 107 |
st.sidebar.subheader("🎲 Simulador de Crédito")
|
| 108 |
st.sidebar.info("Simule um perfil para ver a probabilidade de calote.")
|
|
@@ -116,7 +113,7 @@ if df_raw is not None:
|
|
| 116 |
|
| 117 |
# Botão Simular
|
| 118 |
if st.sidebar.button("Calcular Risco"):
|
| 119 |
-
# Lógica simplificada de simulação
|
| 120 |
input_data = pd.DataFrame(0, index=[0], columns=feature_names)
|
| 121 |
input_data['person_income'] = sim_income
|
| 122 |
input_data['person_age'] = sim_age
|
|
@@ -189,35 +186,39 @@ if df_raw is not None:
|
|
| 189 |
with tab3:
|
| 190 |
st.subheader("Por que o modelo toma essas decisões?")
|
| 191 |
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
|
| 222 |
# TAB 4: Clusters
|
| 223 |
with tab4:
|
|
@@ -278,5 +279,6 @@ if df_raw is not None:
|
|
| 278 |
""")
|
| 279 |
|
| 280 |
else:
|
| 281 |
-
|
| 282 |
-
st.
|
|
|
|
|
|
| 18 |
# Configuração da Página
|
| 19 |
st.set_page_config(page_title="CrediFast - Risco de Crédito", layout="wide", page_icon="💰")
|
| 20 |
|
| 21 |
+
# Desativar avisos
|
|
|
|
|
|
|
| 22 |
warnings.filterwarnings('ignore')
|
| 23 |
|
| 24 |
# Título e Cabeçalho
|
|
|
|
| 28 |
# --- FUNÇÕES DE CACHE (Para performance) ---
|
| 29 |
|
| 30 |
@st.cache_data
|
| 31 |
+
def carregar_dados():
|
| 32 |
+
# Carrega diretamente o arquivo local
|
| 33 |
+
try:
|
| 34 |
+
df = pd.read_csv('credit_risk_dataset.csv')
|
| 35 |
+
return df
|
| 36 |
+
except FileNotFoundError:
|
| 37 |
+
return None
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
@st.cache_data
|
| 40 |
def processar_dados(df):
|
|
|
|
| 78 |
X_test_final = pd.DataFrame(X_test_scaled, columns=feature_names)
|
| 79 |
|
| 80 |
# Treinamento XGBoost
|
| 81 |
+
# FIX: base_score=0.5 ajuda a evitar o erro '[5E-1]' no SHAP com XGBoost novos
|
| 82 |
+
model = XGBClassifier(use_label_encoder=False, eval_metric='logloss', random_state=42, base_score=0.5)
|
| 83 |
model.fit(X_train_final, y_train_bal)
|
| 84 |
|
| 85 |
return model, scaler, X_test_final, y_test, X_train_final, feature_names
|
| 86 |
|
| 87 |
+
# --- LOGICA PRINCIPAL ---
|
|
|
|
|
|
|
| 88 |
|
| 89 |
+
# Tenta carregar os dados automaticamente
|
| 90 |
+
df_raw = carregar_dados()
|
| 91 |
|
| 92 |
if df_raw is not None:
|
| 93 |
+
# Processamento Automático
|
| 94 |
+
# Mostra um spinner enquanto carrega para o usuário saber que está trabalhando
|
| 95 |
+
with st.spinner('Inicializando sistema: Processando dados e treinando IA...'):
|
| 96 |
X, y, df_clean = processar_dados(df_raw)
|
| 97 |
model, scaler, X_test, y_test, X_train, feature_names = treinar_modelo(X, y)
|
| 98 |
|
| 99 |
+
# --- SIDEBAR (Simulador) ---
|
| 100 |
+
st.sidebar.header("📂 Menu")
|
| 101 |
+
st.sidebar.success("✅ Modelo Carregado e Pronto")
|
| 102 |
|
|
|
|
| 103 |
st.sidebar.markdown("---")
|
| 104 |
st.sidebar.subheader("🎲 Simulador de Crédito")
|
| 105 |
st.sidebar.info("Simule um perfil para ver a probabilidade de calote.")
|
|
|
|
| 113 |
|
| 114 |
# Botão Simular
|
| 115 |
if st.sidebar.button("Calcular Risco"):
|
| 116 |
+
# Lógica simplificada de simulação
|
| 117 |
input_data = pd.DataFrame(0, index=[0], columns=feature_names)
|
| 118 |
input_data['person_income'] = sim_income
|
| 119 |
input_data['person_age'] = sim_age
|
|
|
|
| 186 |
with tab3:
|
| 187 |
st.subheader("Por que o modelo toma essas decisões?")
|
| 188 |
|
| 189 |
+
try:
|
| 190 |
+
# Calcular SHAP
|
| 191 |
+
explainer = shap.TreeExplainer(model)
|
| 192 |
+
shap_values = explainer.shap_values(X_test)
|
| 193 |
+
|
| 194 |
+
st.markdown("**1. Visão Global (Quais variáveis importam mais?)**")
|
| 195 |
+
# Correção para exibir o gráfico sem warning: criar figura explícita e passar para st.pyplot
|
| 196 |
+
fig_summary, ax = plt.subplots()
|
| 197 |
+
shap.summary_plot(shap_values, X_test, show=False)
|
| 198 |
+
st.pyplot(plt.gcf())
|
| 199 |
+
plt.clf() # Limpar figura atual
|
| 200 |
+
|
| 201 |
+
st.markdown("---")
|
| 202 |
+
st.markdown("**2. Visão Local (Análise caso a caso)**")
|
| 203 |
+
|
| 204 |
+
# Seletor de índice
|
| 205 |
+
idx = st.number_input("Selecione o ID do Cliente para auditar:", min_value=0, max_value=len(X_test)-1, value=0)
|
| 206 |
+
|
| 207 |
+
real_val = y_test.iloc[idx]
|
| 208 |
+
pred_val = y_pred[idx]
|
| 209 |
+
st.write(f"Cliente ID {idx} | Real: {'Bad' if real_val==1 else 'Good'} | Predito: {'Bad' if pred_val==1 else 'Good'}")
|
| 210 |
+
|
| 211 |
+
# Waterfall Plot
|
| 212 |
+
fig_waterfall = plt.figure()
|
| 213 |
+
shap.plots.waterfall(shap.Explanation(values=shap_values[idx],
|
| 214 |
+
base_values=explainer.expected_value,
|
| 215 |
+
data=X_test.iloc[idx],
|
| 216 |
+
feature_names=X_test.columns.tolist()),
|
| 217 |
+
max_display=10, show=False)
|
| 218 |
+
st.pyplot(fig_waterfall)
|
| 219 |
+
except Exception as e:
|
| 220 |
+
st.error(f"Erro ao calcular SHAP: {e}")
|
| 221 |
+
st.warning("Dica: Tente recarregar a página ou verifique compatibilidade de versões.")
|
| 222 |
|
| 223 |
# TAB 4: Clusters
|
| 224 |
with tab4:
|
|
|
|
| 279 |
""")
|
| 280 |
|
| 281 |
else:
|
| 282 |
+
# Caso o arquivo não seja encontrado
|
| 283 |
+
st.error("🚨 Arquivo `credit_risk_dataset.csv` não encontrado no diretório.")
|
| 284 |
+
st.info("Por favor, adicione o arquivo csv na aba 'Files' do Hugging Face Spaces junto com este app.py.")
|