dcga commited on
Commit
30ffb09
·
verified ·
1 Parent(s): eb90b64
Files changed (1) hide show
  1. app.py +63 -81
app.py CHANGED
@@ -877,21 +877,6 @@ def main():
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,45 +900,39 @@ def main():
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,13 +953,14 @@ def main():
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, use_container_width=True, key='shap_summary_plot')
983
- plt.close(fig_summary)
 
984
 
985
  # Análise das principais variáveis
986
  st.markdown("### 📈 Análise das Variáveis Mais Importantes")
@@ -1050,17 +1030,18 @@ def main():
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, use_container_width=True, key='shap_waterfall_good')
1063
- plt.close(fig_wf)
 
1064
 
1065
  st.markdown("""
1066
  **Interpretação:** Este cliente foi classificado como bom pagador porque:
@@ -1074,17 +1055,18 @@ def main():
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, use_container_width=True, key='shap_waterfall_bad')
1087
- plt.close(fig_wf2)
 
1088
 
1089
  st.markdown("""
1090
  **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
  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
  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
  </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
  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
  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: