dcga commited on
Commit
2c91c4c
·
verified ·
1 Parent(s): 30ffb09

novo teste para parar de vibrar

Browse files
Files changed (1) hide show
  1. app.py +81 -63
app.py CHANGED
@@ -877,6 +877,21 @@ def main():
877
  st.markdown('<h2 class="section-header">III. Explicabilidade com SHAP</h2>',
878
  unsafe_allow_html=True)
879
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
880
  if 'trained_models' not in st.session_state:
881
  st.warning("⚠️ Por favor, treine os modelos primeiro na seção 'II. Modelagem Supervisionada'")
882
  else:
@@ -900,39 +915,45 @@ def main():
900
  key='shap_model_selector'
901
  )
902
 
903
- if st.button("🔬 Calcular SHAP Values", type="primary", key='calc_shap_btn'):
904
- with st.spinner("Calculando SHAP values... Isso pode levar alguns minutos."):
905
- model = trained_models[model_for_shap]
 
 
 
 
 
 
 
 
 
 
 
 
906
 
907
- # Usar TreeExplainer para modelos de árvore
908
- try:
909
- explainer = shap.TreeExplainer(model)
910
- X_sample = X_test_scaled[:500]
911
- shap_values = explainer.shap_values(X_sample)
912
-
913
- # Para modelos de classificação binária
914
- if isinstance(shap_values, list):
915
- shap_values = shap_values[1] # Classe positiva (bad)
916
-
917
- # Obter base_value corretamente
918
- expected_val = explainer.expected_value
919
- if isinstance(expected_val, (list, np.ndarray)):
920
- if len(expected_val) > 1:
921
- base_val = float(expected_val[1])
922
- else:
923
- base_val = float(expected_val[0])
924
  else:
925
- base_val = float(expected_val)
926
-
927
- st.session_state['shap_explainer'] = explainer
928
- st.session_state['shap_values'] = shap_values
929
- st.session_state['X_sample_shap'] = X_sample
930
- st.session_state['shap_model'] = model_for_shap
931
- st.session_state['shap_base_val'] = base_val
932
-
933
- st.success("✅ SHAP values calculados com sucesso!")
934
- except Exception as e:
935
- st.error(f"Erro ao calcular SHAP values: {str(e)}")
 
 
936
 
937
  if 'shap_values' in st.session_state:
938
  shap_values = st.session_state['shap_values']
@@ -953,14 +974,13 @@ def main():
953
  </div>
954
  """, unsafe_allow_html=True)
955
 
956
- # Summary plot com matplotlib - usando container para estabilizar
957
- summary_container = st.container()
958
- with summary_container:
959
- fig_summary = plt.figure(figsize=(10, 8))
960
- shap.summary_plot(shap_values, X_sample, feature_names=feature_names,
961
- plot_type="dot", show=False)
962
- st.pyplot(fig_summary, clear_figure=True)
963
- plt.close(fig_summary)
964
 
965
  # Análise das principais variáveis
966
  st.markdown("### 📈 Análise das Variáveis Mais Importantes")
@@ -1030,18 +1050,17 @@ def main():
1030
  st.markdown("#### Análise de um Cliente Classificado como GOOD")
1031
  idx_good = good_indices[0]
1032
 
1033
- # Waterfall plot usando container estável
1034
- wf_container1 = st.container()
1035
- with wf_container1:
1036
- fig_wf = plt.figure(figsize=(10, 6))
1037
- shap.waterfall_plot(shap.Explanation(
1038
- values=shap_values[idx_good],
1039
- base_values=base_val,
1040
- data=X_sample[idx_good],
1041
- feature_names=feature_names
1042
- ), show=False)
1043
- st.pyplot(fig_wf, clear_figure=True)
1044
- plt.close(fig_wf)
1045
 
1046
  st.markdown("""
1047
  **Interpretação:** Este cliente foi classificado como bom pagador porque:
@@ -1055,18 +1074,17 @@ def main():
1055
  st.markdown("#### Análise de um Cliente Classificado como BAD")
1056
  idx_bad = bad_indices[0]
1057
 
1058
- # Waterfall plot usando container estável
1059
- wf_container2 = st.container()
1060
- with wf_container2:
1061
- fig_wf2 = plt.figure(figsize=(10, 6))
1062
- shap.waterfall_plot(shap.Explanation(
1063
- values=shap_values[idx_bad],
1064
- base_values=base_val,
1065
- data=X_sample[idx_bad],
1066
- feature_names=feature_names
1067
- ), show=False)
1068
- st.pyplot(fig_wf2, clear_figure=True)
1069
- plt.close(fig_wf2)
1070
 
1071
  st.markdown("""
1072
  **Interpretação:** Este cliente foi classificado como inadimplente porque:
 
877
  st.markdown('<h2 class="section-header">III. Explicabilidade com SHAP</h2>',
878
  unsafe_allow_html=True)
879
 
880
+ # CSS para estabilizar o layout e evitar tremidas
881
+ st.markdown("""
882
+ <style>
883
+ .shap-container {
884
+ min-height: 600px;
885
+ }
886
+ .stSpinner {
887
+ min-height: 50px;
888
+ }
889
+ div[data-testid="stVerticalBlock"] > div {
890
+ transition: none !important;
891
+ }
892
+ </style>
893
+ """, unsafe_allow_html=True)
894
+
895
  if 'trained_models' not in st.session_state:
896
  st.warning("⚠️ Por favor, treine os modelos primeiro na seção 'II. Modelagem Supervisionada'")
897
  else:
 
915
  key='shap_model_selector'
916
  )
917
 
918
+ # Usar form para evitar reruns durante o cálculo
919
+ calc_shap = st.button("🔬 Calcular SHAP Values", type="primary", key='calc_shap_btn')
920
+
921
+ # Placeholder para mensagens de status
922
+ status_placeholder = st.empty()
923
+
924
+ if calc_shap:
925
+ status_placeholder.info("⏳ Calculando SHAP values... Isso pode levar alguns minutos.")
926
+ model = trained_models[model_for_shap]
927
+
928
+ # Usar TreeExplainer para modelos de árvore
929
+ try:
930
+ explainer = shap.TreeExplainer(model)
931
+ X_sample = X_test_scaled[:500]
932
+ shap_values = explainer.shap_values(X_sample)
933
 
934
+ # Para modelos de classificação binária
935
+ if isinstance(shap_values, list):
936
+ shap_values = shap_values[1] # Classe positiva (bad)
937
+
938
+ # Obter base_value corretamente
939
+ expected_val = explainer.expected_value
940
+ if isinstance(expected_val, (list, np.ndarray)):
941
+ if len(expected_val) > 1:
942
+ base_val = float(expected_val[1])
 
 
 
 
 
 
 
 
943
  else:
944
+ base_val = float(expected_val[0])
945
+ else:
946
+ base_val = float(expected_val)
947
+
948
+ st.session_state['shap_explainer'] = explainer
949
+ st.session_state['shap_values'] = shap_values
950
+ st.session_state['X_sample_shap'] = X_sample
951
+ st.session_state['shap_model'] = model_for_shap
952
+ st.session_state['shap_base_val'] = base_val
953
+
954
+ status_placeholder.success(" SHAP values calculados com sucesso!")
955
+ except Exception as e:
956
+ status_placeholder.error(f"Erro ao calcular SHAP values: {str(e)}")
957
 
958
  if 'shap_values' in st.session_state:
959
  shap_values = st.session_state['shap_values']
 
974
  </div>
975
  """, unsafe_allow_html=True)
976
 
977
+ # Summary plot com matplotlib - fechar figuras anteriores para evitar tremidas
978
+ plt.close('all')
979
+ fig_summary, ax_summary = plt.subplots(figsize=(10, 8))
980
+ shap.summary_plot(shap_values, X_sample, feature_names=feature_names,
981
+ plot_type="dot", show=False)
982
+ st.pyplot(fig_summary, clear_figure=True)
983
+ plt.close('all')
 
984
 
985
  # Análise das principais variáveis
986
  st.markdown("### 📈 Análise das Variáveis Mais Importantes")
 
1050
  st.markdown("#### Análise de um Cliente Classificado como GOOD")
1051
  idx_good = good_indices[0]
1052
 
1053
+ # Waterfall plot - fechar figuras anteriores
1054
+ plt.close('all')
1055
+ fig_wf = plt.figure(figsize=(10, 6))
1056
+ shap.waterfall_plot(shap.Explanation(
1057
+ values=shap_values[idx_good],
1058
+ base_values=base_val,
1059
+ data=X_sample[idx_good],
1060
+ feature_names=feature_names
1061
+ ), show=False)
1062
+ st.pyplot(fig_wf, clear_figure=True)
1063
+ plt.close('all')
 
1064
 
1065
  st.markdown("""
1066
  **Interpretação:** Este cliente foi classificado como bom pagador porque:
 
1074
  st.markdown("#### Análise de um Cliente Classificado como BAD")
1075
  idx_bad = bad_indices[0]
1076
 
1077
+ # Waterfall plot - fechar figuras anteriores
1078
+ plt.close('all')
1079
+ fig_wf2 = plt.figure(figsize=(10, 6))
1080
+ shap.waterfall_plot(shap.Explanation(
1081
+ values=shap_values[idx_bad],
1082
+ base_values=base_val,
1083
+ data=X_sample[idx_bad],
1084
+ feature_names=feature_names
1085
+ ), show=False)
1086
+ st.pyplot(fig_wf2, clear_figure=True)
1087
+ plt.close('all')
 
1088
 
1089
  st.markdown("""
1090
  **Interpretação:** Este cliente foi classificado como inadimplente porque: