Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
# app_ucs.py — ST_GeoMech_UCS (Unified workflow like Tc)
|
| 2 |
|
| 3 |
import io, json, os, base64, math
|
| 4 |
from pathlib import Path
|
|
@@ -15,7 +15,7 @@ import matplotlib.pyplot as plt
|
|
| 15 |
from matplotlib.ticker import FuncFormatter
|
| 16 |
|
| 17 |
import plotly.graph_objects as go
|
| 18 |
-
from sklearn.metrics import mean_squared_error
|
| 19 |
|
| 20 |
# =========================
|
| 21 |
# Constants / Defaults
|
|
@@ -138,6 +138,18 @@ def pearson_r(y_true, y_pred) -> float:
|
|
| 138 |
if np.all(a == a[0]) or np.all(p == p[0]): return float("nan")
|
| 139 |
return float(np.corrcoef(a, p)[0, 1])
|
| 140 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
@st.cache_resource(show_spinner=False)
|
| 142 |
def load_model(model_path: str):
|
| 143 |
return joblib.load(model_path)
|
|
@@ -321,7 +333,7 @@ def build_export_workbook(selected: list[str] | None = None) -> tuple[bytes|None
|
|
| 321 |
sheets["Validation_Summary"] = _round_numeric(pd.DataFrame([sv])); order.append("Validation_Summary")
|
| 322 |
oor_tbl = res.get("oor_tbl")
|
| 323 |
if oor_tbl is not None and isinstance(oor_tbl, pd.DataFrame) and not oor_tbl.empty:
|
| 324 |
-
sheets["
|
| 325 |
|
| 326 |
# Prediction
|
| 327 |
if ("Prediction" in (selected or _available_sections())) and "PredictOnly" in res:
|
|
@@ -406,7 +418,6 @@ def cross_plot_static(actual, pred):
|
|
| 406 |
a = pd.Series(actual, dtype=float)
|
| 407 |
p = pd.Series(pred, dtype=float)
|
| 408 |
|
| 409 |
-
# Use data-driven limits with a small pad (or keep your fixed 6000–10000 if you prefer)
|
| 410 |
lo = float(min(a.min(), p.min()))
|
| 411 |
hi = float(max(a.max(), p.max()))
|
| 412 |
pad = 0.03 * (hi - lo if hi > lo else 1.0)
|
|
@@ -707,14 +718,14 @@ if st.session_state.app_step == "dev":
|
|
| 707 |
|
| 708 |
st.session_state.results["Train"]=tr; st.session_state.results["Test"]=te
|
| 709 |
st.session_state.results["m_train"]={
|
| 710 |
-
"R":
|
| 711 |
"RMSE": rmse(tr[TARGET], tr[PRED_COL]),
|
| 712 |
-
"
|
| 713 |
}
|
| 714 |
st.session_state.results["m_test"]={
|
| 715 |
-
"R":
|
| 716 |
"RMSE": rmse(te[TARGET], te[PRED_COL]),
|
| 717 |
-
"
|
| 718 |
}
|
| 719 |
|
| 720 |
tr_min = tr[FEATURES].min().to_dict(); tr_max = tr[FEATURES].max().to_dict()
|
|
@@ -723,12 +734,14 @@ if st.session_state.app_step == "dev":
|
|
| 723 |
|
| 724 |
def _dev_block(df, m):
|
| 725 |
c1,c2,c3 = st.columns(3)
|
| 726 |
-
c1.metric("R", f"{m['R']:.3f}")
|
|
|
|
|
|
|
| 727 |
st.markdown("""
|
| 728 |
<div style='text-align: left; font-size: 0.8em; color: #6b7280; margin-top: -16px; margin-bottom: 8px;'>
|
| 729 |
<strong>R:</strong> Pearson Correlation Coefficient<br>
|
| 730 |
<strong>RMSE:</strong> Root Mean Square Error<br>
|
| 731 |
-
<strong>
|
| 732 |
</div>
|
| 733 |
""", unsafe_allow_html=True)
|
| 734 |
col_track, col_cross = st.columns([2, 3], gap="large")
|
|
@@ -785,9 +798,9 @@ if st.session_state.app_step == "validate":
|
|
| 785 |
lambda r:", ".join([c for c,v in r.items() if v]), axis=1
|
| 786 |
)
|
| 787 |
st.session_state.results["m_val"]={
|
| 788 |
-
"R":
|
| 789 |
"RMSE": rmse(df[TARGET], df[PRED_COL]),
|
| 790 |
-
"
|
| 791 |
}
|
| 792 |
st.session_state.results["sv_val"]={"n":len(df), "pred_min":float(df[PRED_COL].min()), "pred_max":float(df[PRED_COL].max()), "oor":oor_pct}
|
| 793 |
st.session_state.results["oor_tbl"]=tbl
|
|
@@ -795,12 +808,14 @@ if st.session_state.app_step == "validate":
|
|
| 795 |
if "Validate" in st.session_state.results:
|
| 796 |
m = st.session_state.results["m_val"]
|
| 797 |
c1,c2,c3 = st.columns(3)
|
| 798 |
-
c1.metric("R", f"{m['R']:.3f}")
|
|
|
|
|
|
|
| 799 |
st.markdown("""
|
| 800 |
<div style='text-align: left; font-size: 0.8em; color: #6b7280; margin-top: -16px; margin-bottom: 8px;'>
|
| 801 |
<strong>R:</strong> Pearson Correlation Coefficient<br>
|
| 802 |
<strong>RMSE:</strong> Root Mean Square Error<br>
|
| 803 |
-
<strong>
|
| 804 |
</div>
|
| 805 |
""", unsafe_allow_html=True)
|
| 806 |
|
|
|
|
| 1 |
+
# app_ucs.py — ST_GeoMech_UCS (Unified workflow like Tc) — MAPE instead of MAE
|
| 2 |
|
| 3 |
import io, json, os, base64, math
|
| 4 |
from pathlib import Path
|
|
|
|
| 15 |
from matplotlib.ticker import FuncFormatter
|
| 16 |
|
| 17 |
import plotly.graph_objects as go
|
| 18 |
+
from sklearn.metrics import mean_squared_error # MAE removed
|
| 19 |
|
| 20 |
# =========================
|
| 21 |
# Constants / Defaults
|
|
|
|
| 138 |
if np.all(a == a[0]) or np.all(p == p[0]): return float("nan")
|
| 139 |
return float(np.corrcoef(a, p)[0, 1])
|
| 140 |
|
| 141 |
+
def mape(y_true, y_pred, eps: float = 1e-8) -> float:
|
| 142 |
+
"""
|
| 143 |
+
Mean Absolute Percentage Error in PERCENT.
|
| 144 |
+
Ignores rows where |y_true| < eps to avoid division blowups.
|
| 145 |
+
"""
|
| 146 |
+
a = np.asarray(y_true, dtype=float)
|
| 147 |
+
p = np.asarray(y_pred, dtype=float)
|
| 148 |
+
denom = np.where(np.abs(a) < eps, np.nan, np.abs(a))
|
| 149 |
+
pct = np.abs(a - p) / denom * 100.0
|
| 150 |
+
val = np.nanmean(pct)
|
| 151 |
+
return float(val) if np.isfinite(val) else float("nan")
|
| 152 |
+
|
| 153 |
@st.cache_resource(show_spinner=False)
|
| 154 |
def load_model(model_path: str):
|
| 155 |
return joblib.load(model_path)
|
|
|
|
| 333 |
sheets["Validation_Summary"] = _round_numeric(pd.DataFrame([sv])); order.append("Validation_Summary")
|
| 334 |
oor_tbl = res.get("oor_tbl")
|
| 335 |
if oor_tbl is not None and isinstance(oor_tbl, pd.DataFrame) and not oor_tbl.empty:
|
| 336 |
+
sheets["Validation_OOR"] = _round_numeric(oor_tbl.reset_index(drop=True)); order.append("Validation_OOR")
|
| 337 |
|
| 338 |
# Prediction
|
| 339 |
if ("Prediction" in (selected or _available_sections())) and "PredictOnly" in res:
|
|
|
|
| 418 |
a = pd.Series(actual, dtype=float)
|
| 419 |
p = pd.Series(pred, dtype=float)
|
| 420 |
|
|
|
|
| 421 |
lo = float(min(a.min(), p.min()))
|
| 422 |
hi = float(max(a.max(), p.max()))
|
| 423 |
pad = 0.03 * (hi - lo if hi > lo else 1.0)
|
|
|
|
| 718 |
|
| 719 |
st.session_state.results["Train"]=tr; st.session_state.results["Test"]=te
|
| 720 |
st.session_state.results["m_train"]={
|
| 721 |
+
"R": pearson_r(tr[TARGET], tr[PRED_COL]),
|
| 722 |
"RMSE": rmse(tr[TARGET], tr[PRED_COL]),
|
| 723 |
+
"MAPE": mape(tr[TARGET], tr[PRED_COL])
|
| 724 |
}
|
| 725 |
st.session_state.results["m_test"]={
|
| 726 |
+
"R": pearson_r(te[TARGET], te[PRED_COL]),
|
| 727 |
"RMSE": rmse(te[TARGET], te[PRED_COL]),
|
| 728 |
+
"MAPE": mape(te[TARGET], te[PRED_COL])
|
| 729 |
}
|
| 730 |
|
| 731 |
tr_min = tr[FEATURES].min().to_dict(); tr_max = tr[FEATURES].max().to_dict()
|
|
|
|
| 734 |
|
| 735 |
def _dev_block(df, m):
|
| 736 |
c1,c2,c3 = st.columns(3)
|
| 737 |
+
c1.metric("R", f"{m['R']:.3f}")
|
| 738 |
+
c2.metric("RMSE", f"{m['RMSE']:.2f}")
|
| 739 |
+
c3.metric("MAPE (%)", f"{m['MAPE']:.2f}%")
|
| 740 |
st.markdown("""
|
| 741 |
<div style='text-align: left; font-size: 0.8em; color: #6b7280; margin-top: -16px; margin-bottom: 8px;'>
|
| 742 |
<strong>R:</strong> Pearson Correlation Coefficient<br>
|
| 743 |
<strong>RMSE:</strong> Root Mean Square Error<br>
|
| 744 |
+
<strong>MAPE:</strong> Mean Absolute Percentage Error (percent of actual; rows with near-zero actuals are ignored).
|
| 745 |
</div>
|
| 746 |
""", unsafe_allow_html=True)
|
| 747 |
col_track, col_cross = st.columns([2, 3], gap="large")
|
|
|
|
| 798 |
lambda r:", ".join([c for c,v in r.items() if v]), axis=1
|
| 799 |
)
|
| 800 |
st.session_state.results["m_val"]={
|
| 801 |
+
"R": pearson_r(df[TARGET], df[PRED_COL]),
|
| 802 |
"RMSE": rmse(df[TARGET], df[PRED_COL]),
|
| 803 |
+
"MAPE": mape(df[TARGET], df[PRED_COL])
|
| 804 |
}
|
| 805 |
st.session_state.results["sv_val"]={"n":len(df), "pred_min":float(df[PRED_COL].min()), "pred_max":float(df[PRED_COL].max()), "oor":oor_pct}
|
| 806 |
st.session_state.results["oor_tbl"]=tbl
|
|
|
|
| 808 |
if "Validate" in st.session_state.results:
|
| 809 |
m = st.session_state.results["m_val"]
|
| 810 |
c1,c2,c3 = st.columns(3)
|
| 811 |
+
c1.metric("R", f"{m['R']:.3f}")
|
| 812 |
+
c2.metric("RMSE", f"{m['RMSE']:.2f}")
|
| 813 |
+
c3.metric("MAPE (%)", f"{m['MAPE']:.2f}%")
|
| 814 |
st.markdown("""
|
| 815 |
<div style='text-align: left; font-size: 0.8em; color: #6b7280; margin-top: -16px; margin-bottom: 8px;'>
|
| 816 |
<strong>R:</strong> Pearson Correlation Coefficient<br>
|
| 817 |
<strong>RMSE:</strong> Root Mean Square Error<br>
|
| 818 |
+
<strong>MAPE:</strong> Mean Absolute Percentage Error (percent of actual; rows with near-zero actuals are ignored).
|
| 819 |
</div>
|
| 820 |
""", unsafe_allow_html=True)
|
| 821 |
|