Cash99/r2
0
1import pandas as pd2import matplotlib.pyplot as plt3import streamlit as st4import matplotlib as mpl5from io import BytesIO6import numpy as np7 8# 字型設定(繁體中文)9font_path = "SourceHanSansTW-Regular.otf"10mpl.font_manager.fontManager.addfont(font_path)11plt.rcParams['font.family'] = "Source Han Sans TW"12 13# 標題14st.title("📐 R² 傾斜分析工具")15 16# 📘 簡要說明17with st.expander("📘 R² 計算說明", expanded=False):18 st.markdown(r"""19**R²(決定係數)** 是評估資料與趨勢線吻合程度的統計指標,數值範圍為 -∞ 到 1,越接近 1 表示線性趨勢越明顯。20 21其計算公式如下:22 23$$24R^2 = 1 - \frac{SS_{res}}{SS_{tot}}25$$26 27其中: 28- `SS_{res}`:預測殘差平方和(Residual Sum of Squares) 29- `SS_{tot}`:總變異平方和(Total Sum of Squares)30""")31 32# 資料來源選擇33mode = st.radio("請選擇資料來源:", ["手動輸入資料", "上傳 CSV 檔案"])34 35data = None36 37if mode == "手動輸入資料":38 manual_input = st.text_area("請輸入以逗號分隔的數值資料(例:1, 2, 3, 4)", height=100)39 threshold = st.number_input("請輸入判定用的 R² 門檻值", value=0.2, step=0.01)40 41 if st.button("開始分析"):42 try:43 y = [float(i.strip()) for i in manual_input.split(",") if i.strip()]44 if len(y) < 2:45 st.error("❌ 至少需要 2 筆資料")46 else:47 x = list(range(1, len(y) + 1))48 df = pd.DataFrame({"X": x, "Y": y})49 st.write("🔍 資料預覽")50 st.dataframe(df)51 52 # 線性回歸與 R²53 x_np = np.array(x)54 y_np = np.array(y)55 slope, intercept = np.polyfit(x_np, y_np, 1)56 y_pred = slope * x_np + intercept57 ss_total = np.sum((y_np - np.mean(y_np)) ** 2)58 ss_res = np.sum((y_np - y_pred) ** 2)59 r_squared = 1 - (ss_res / ss_total)60 61 # 顯示結果62 st.write(f"📊 R² = `{r_squared:.4f}`")63 st.write(f"📐 斜率 = `{slope:.4f}`")64 65 if r_squared > threshold:66 st.error("🔺 判斷結果:傾斜")67 else:68 st.success("✅ 判斷結果:正常")69 70 # 畫圖71 fig, ax = plt.subplots(figsize=(10, 4))72 ax.plot(x, y, 'o-', label='原始資料')73 ax.plot(x, y_pred, '--', color='red', label='趨勢線')74 ax.set_title("資料趨勢圖")75 ax.set_xlabel("X")76 ax.set_ylabel("Y")77 ax.grid(True)78 ax.legend()79 st.pyplot(fig)80 except:81 st.error("❌ 請輸入正確格式的數值(逗號分隔)")82 83else:84 uploaded_file = st.file_uploader("請上傳 CSV 檔案", type=["csv"])85 if uploaded_file:86 try:87 df = pd.read_csv(uploaded_file)88 st.success("✅ 成功讀取 CSV")89 st.write("🔍 資料預覽")90 st.dataframe(df.head())91 92 numeric_cols = df.select_dtypes(include="number").columns.tolist()93 if len(numeric_cols) < 2:94 st.warning("❗ 檔案中需至少包含兩個數值欄位")95 else:96 x_col = st.selectbox("請選擇 X 軸欄位", options=numeric_cols)97 y_col = st.selectbox("請選擇 Y 軸欄位", options=numeric_cols)98 threshold = st.number_input("請輸入判定用的 R² 門檻值", value=0.2, step=0.01)99 100 if st.button("開始分析"):101 x = df[x_col].values102 y = df[y_col].values103 slope, intercept = np.polyfit(x, y, 1)104 y_pred = slope * x + intercept105 ss_total = np.sum((y - np.mean(y)) ** 2)106 ss_res = np.sum((y - y_pred) ** 2)107 r_squared = 1 - (ss_res / ss_total)108 109 st.write(f"📊 R² = `{r_squared:.4f}`")110 st.write(f"📐 斜率 = `{slope:.4f}`")111 112 if r_squared > threshold:113 st.error("🔺 判斷結果:傾斜")114 else:115 st.success("✅ 判斷結果:正常")116 117 # 畫圖118 fig, ax = plt.subplots(figsize=(10, 4))119 ax.scatter(x, y, label="原始資料", color="#0072B2")120 ax.plot(x, y_pred, '--', color='red', label='趨勢線')121 ax.set_title("資料趨勢圖")122 ax.set_xlabel(x_col)123 ax.set_ylabel(y_col)124 ax.grid(True)125 ax.legend()126 st.pyplot(fig)127 except Exception as e:128 st.error(f"❌ 讀取錯誤:{e}")129 