Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -704,25 +704,28 @@ if st.session_state.app_step == "predict":
|
|
| 704 |
st.sidebar.caption(f"**Data loaded:** {up.name} • {df0.shape[0]} rows × {df0.shape[1]} cols")
|
| 705 |
if st.sidebar.button("Preview data", use_container_width=True, disabled=(up is None)):
|
| 706 |
st.session_state.show_preview_modal = True
|
| 707 |
-
|
| 708 |
-
# Corrected logic: Move the code that depends on the button's click
|
| 709 |
-
# to be immediately after the button is defined.
|
| 710 |
if st.sidebar.button("Predict", type="primary", use_container_width=True):
|
| 711 |
if up is not None:
|
| 712 |
book = read_book_bytes(up.getvalue()); name = list(book.keys())[0]
|
| 713 |
df = normalize_df(book[name].copy())
|
| 714 |
if not ensure_cols(df, FEATURES):
|
| 715 |
-
st.markdown('<div class="st-message-box st-error">Missing required feature columns.</div>', unsafe_allow_html=True)
|
| 716 |
st.stop()
|
| 717 |
-
|
| 718 |
pred_raw = model.predict(df[FEATURES])
|
| 719 |
df["GR_Pred"] = inverse_target(np.asarray(pred_raw, dtype=float), TARGET_TRANSFORM)
|
| 720 |
st.session_state.results["PredictOnly"]=df
|
| 721 |
-
|
| 722 |
-
|
|
|
|
| 723 |
if ranges:
|
| 724 |
any_viol = pd.DataFrame({f:(df[f]<ranges[f][0])|(df[f]>ranges[f][1]) for f in FEATURES}).any(axis=1)
|
| 725 |
oor_pct = float(any_viol.mean()*100.0)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 726 |
st.session_state.results["sv_pred"]={
|
| 727 |
"n":len(df),
|
| 728 |
"pred_min":float(df["GR_Pred"].min()),
|
|
@@ -731,14 +734,42 @@ if st.session_state.app_step == "predict":
|
|
| 731 |
"pred_std":float(df["GR_Pred"].std(ddof=0)),
|
| 732 |
"oor":oor_pct
|
| 733 |
}
|
| 734 |
-
|
| 735 |
-
if st.sidebar.button("⬅ Back to Case Building", use_container_width=True): st.session_state.app_step="dev"; st.rerun()
|
| 736 |
|
| 737 |
-
|
|
|
|
|
|
|
| 738 |
|
| 739 |
-
|
| 740 |
-
# ... (Rest of the code to display the results)
|
| 741 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 742 |
# =========================
|
| 743 |
# Preview modal (re-usable)
|
| 744 |
# =========================
|
|
|
|
| 704 |
st.sidebar.caption(f"**Data loaded:** {up.name} • {df0.shape[0]} rows × {df0.shape[1]} cols")
|
| 705 |
if st.sidebar.button("Preview data", use_container_width=True, disabled=(up is None)):
|
| 706 |
st.session_state.show_preview_modal = True
|
| 707 |
+
|
|
|
|
|
|
|
| 708 |
if st.sidebar.button("Predict", type="primary", use_container_width=True):
|
| 709 |
if up is not None:
|
| 710 |
book = read_book_bytes(up.getvalue()); name = list(book.keys())[0]
|
| 711 |
df = normalize_df(book[name].copy())
|
| 712 |
if not ensure_cols(df, FEATURES):
|
| 713 |
+
st.markdown('<div class="st-message-box st-error">Missing required feature columns.</div>', unsafe_allow_html=True)
|
| 714 |
st.stop()
|
|
|
|
| 715 |
pred_raw = model.predict(df[FEATURES])
|
| 716 |
df["GR_Pred"] = inverse_target(np.asarray(pred_raw, dtype=float), TARGET_TRANSFORM)
|
| 717 |
st.session_state.results["PredictOnly"]=df
|
| 718 |
+
ranges = st.session_state.train_ranges
|
| 719 |
+
oor_pct = 0.0
|
| 720 |
+
oor_tbl = None
|
| 721 |
if ranges:
|
| 722 |
any_viol = pd.DataFrame({f:(df[f]<ranges[f][0])|(df[f]>ranges[f][1]) for f in FEATURES}).any(axis=1)
|
| 723 |
oor_pct = float(any_viol.mean()*100.0)
|
| 724 |
+
if any_viol.any():
|
| 725 |
+
oor_tbl = df.loc[any_viol, FEATURES].copy()
|
| 726 |
+
for c in FEATURES:
|
| 727 |
+
if pd.api.types.is_numeric_dtype(oor_tbl[c]): oor_tbl[c] = oor_tbl[c].round(2)
|
| 728 |
+
oor_tbl["Violations"] = pd.DataFrame({f:(df[f]<ranges[f][0])|(df[f]>ranges[f][1]) for f in FEATURES}).loc[any_viol].apply(lambda r:", ".join([c for c,v in r.items() if v]), axis=1)
|
| 729 |
st.session_state.results["sv_pred"]={
|
| 730 |
"n":len(df),
|
| 731 |
"pred_min":float(df["GR_Pred"].min()),
|
|
|
|
| 734 |
"pred_std":float(df["GR_Pred"].std(ddof=0)),
|
| 735 |
"oor":oor_pct
|
| 736 |
}
|
| 737 |
+
st.session_state.results["oor_tbl_pred"] = oor_tbl
|
|
|
|
| 738 |
|
| 739 |
+
if st.sidebar.button("⬅ Back to Case Building", use_container_width=True):
|
| 740 |
+
st.session_state.app_step="dev"
|
| 741 |
+
st.rerun()
|
| 742 |
|
| 743 |
+
sticky_header("Prediction", "Upload a dataset with the feature columns (no **GR**).")
|
|
|
|
| 744 |
|
| 745 |
+
if "PredictOnly" in st.session_state.results:
|
| 746 |
+
df = st.session_state.results["PredictOnly"]
|
| 747 |
+
sv = st.session_state.results["sv_pred"]
|
| 748 |
+
col_left, col_right = st.columns([2,3], gap="large")
|
| 749 |
+
with col_left:
|
| 750 |
+
table = pd.DataFrame({
|
| 751 |
+
"Metric": ["# points","Pred min","Pred max","Pred mean","Pred std","OOR %"],
|
| 752 |
+
"Value": [sv["n"],
|
| 753 |
+
round(sv["pred_min"],2),
|
| 754 |
+
round(sv["pred_max"],2),
|
| 755 |
+
round(sv["pred_mean"],2),
|
| 756 |
+
round(sv["pred_std"],2),
|
| 757 |
+
f'{sv["oor"]:.1f}%']
|
| 758 |
+
})
|
| 759 |
+
st.markdown('<div class="st-message-box st-success">Predictions ready ✓</div>', unsafe_allow_html=True)
|
| 760 |
+
df_centered_rounded(table, hide_index=True)
|
| 761 |
+
st.caption("**★ OOR** = % of rows whose input features fall outside the training min–max range.")
|
| 762 |
+
|
| 763 |
+
if st.session_state.results.get("oor_tbl_pred") is not None:
|
| 764 |
+
st.markdown('<div class="st-message-box st-warning">Some inputs fall outside **training min–max** ranges.</div>', unsafe_allow_html=True)
|
| 765 |
+
st.write("*Out-of-range rows (vs. Training min–max):*")
|
| 766 |
+
df_centered_rounded(st.session_state.results["oor_tbl_pred"])
|
| 767 |
+
|
| 768 |
+
with col_right:
|
| 769 |
+
st.plotly_chart(
|
| 770 |
+
track_plot(df, include_actual=False, pred_col="GR_Pred", actual_col="GR"),
|
| 771 |
+
use_container_width=False, config={"displayModeBar": False, "scrollZoom": True}
|
| 772 |
+
)
|
| 773 |
# =========================
|
| 774 |
# Preview modal (re-usable)
|
| 775 |
# =========================
|