iT邦幫忙

2025 iThome 鐵人賽

DAY 29
0
自我挑戰組

30天用Python打造你的數位金融實力:從零開始的FinTech入門筆記系列 第 29

把模組串成 Demo:用 Streamlit 做一個「FinTech 迷你儀表板」

  • 分享至 

  • xImage
  •  

目標

把前面做的 expense.csv、tx_log.csv、amortization.csv、premium_quote.csv、customers_sanitized.csv、claims_sim.csv 等檔案整合成可互動的儀表板,能快速展示報表、圖表與下載功能,方便放作品集或面試 Demo。

為什麼有價值

  • 面試時比起單篇文章,雲端或本機啟動的儀表板更具示範力。
  • 展示你會把多個功能(記帳 / 風控 / KYC / 貸款 / 保險)串成一個產品化的 Demo。
  • 技術門檻低(Streamlit + pandas + matplotlib),新手友好。

使用三步驟

  1. 安裝:pip install streamlit pandas matplotlib
  2. 建立檔案 day29_dashboard.py
  3. 執行:streamlit run day29_dashboard.py → 在瀏覽器看你的儀表板

範例程式

說明:程式會自動檢查常用 CSV,若不存在會產生示範資料。

# day29_dashboard.py
import os
import streamlit as st
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime

plt.rcParams['font.family'] = 'Heiti TC'

st.set_page_config(page_title="FinTech Mini Dashboard", layout="wide")
st.title("FinTech Mini Dashboard(迷你儀表板)")
st.markdown("展示:記帳、交易紀錄、貸款攤還、保險報價、KYC 掃描與理賠模擬。")

# ---------- helper: load or create demo data ----------
def ensure_expense():
    path = "expense.csv"
    if not os.path.exists(path):
        demo = pd.DataFrame({
            "日期": pd.to_datetime(["2025-08-01","2025-08-02","2025-08-03","2025-08-06","2025-08-07"]),
            "類別": ["早餐","午餐","購物","交通","咖啡"],
            "金額": [60,120,900,35,75]
        })
        demo.to_csv(path, index=False)
    df = pd.read_csv(path)
    if "日期" in df.columns:
        try:
            df["日期"] = pd.to_datetime(df["日期"])
        except:
            pass
    return df

def ensure_txlog():
    path = "tx_log.csv"
    if not os.path.exists(path):
        demo = pd.DataFrame([
            {"id":"tx1","ts":datetime.now().isoformat(),"from":"Alice","to":"Bob","amount":120,"ccy":"TWD","memo":"午餐","status":"SUCCESS"},
            {"id":"tx2","ts":datetime.now().isoformat(),"from":"Bob","to":"Alice","amount":50,"ccy":"TWD","memo":"咖啡","status":"SUCCESS"},
        ])
        demo.to_csv(path, index=False)
    return pd.read_csv(path)

def ensure_amort():
    path = "amortization.csv"
    if not os.path.exists(path):
        demo = pd.DataFrame([
            {"期數":1, "每期應繳":5100, "利息":1666.67, "本金":3433.33, "剩餘本金":996566.67},
            {"期數":2, "每期應繳":5100, "利息":1664.28, "本金":3435.72, "剩餘本金":993130.95},
        ])
        demo.to_csv(path, index=False)
    return pd.read_csv(path)

def ensure_premium():
    path = "premium_quote.csv"
    if not os.path.exists(path):
        demo = pd.DataFrame([
            {"name":"Alice","age":29,"BMI":20.6,"年保費_估":6000},
            {"name":"Bob","age":43,"BMI":28.7,"年保費_估":11700},
        ])
        demo.to_csv(path, index=False)
    return pd.read_csv(path)

def ensure_customers():
    path = "customers_sanitized.csv"
    if not os.path.exists(path):
        demo = pd.DataFrame([
            {"cust_id":"cust_a1","name_masked":"王*","email_masked":"m***@example.com","phone_masked":"***45678","card_masked":"411111******1111","is_email_valid":1,"is_card_valid":1,"issues":""},
        ])
        demo.to_csv(path, index=False)
    return pd.read_csv(path)

def ensure_claims():
    path = "claims_sim.csv"
    if not os.path.exists(path):
        demo = pd.DataFrame([
            {"policy_id":1,"claim_no":1,"gross":50000,"payout":45000},
            {"policy_id":2,"claim_no":1,"gross":12000,"payout":7000},
        ])
        demo.to_csv(path, index=False)
    return pd.read_csv(path)

# load data
expense_df = ensure_expense()
tx_df = ensure_txlog()
amort_df = ensure_amort()
premium_df = ensure_premium()
cust_df = ensure_customers()
claims_df = ensure_claims()

# ---------- Layout: three columns of KPIs ----------
c1, c2, c3 = st.columns(3)
c1.metric("總支出(筆數)", expense_df.shape[0])
c2.metric("交易筆數", tx_df.shape[0])
c3.metric("理賠案件", claims_df.shape[0])

# ---------- 消費板塊 ----------
st.subheader("消費記錄(expense.csv)")
st.dataframe(expense_df)
with st.expander("消費圖表"):
    try:
        cat_sum = expense_df.groupby("類別")["金額"].sum().sort_values(ascending=False)
        fig, ax = plt.subplots(figsize=(6,3))
        cat_sum.plot(kind="bar", ax=ax)
        ax.set_ylabel("金額")
        st.pyplot(fig)
    except Exception as e:
        st.write("無法繪圖:", e)
st.download_button("下載 expense.csv", expense_df.to_csv(index=False).encode('utf-8'), file_name="expense.csv", mime="text/csv")

# ---------- 交易紀錄 ----------
st.subheader("交易紀錄(tx_log.csv)")
st.dataframe(tx_df)
st.download_button("下載 tx_log.csv", tx_df.to_csv(index=False).encode('utf-8'), file_name="tx_log.csv")

# ---------- 貸款攤還 ----------
st.subheader("貸款攤還表(amortization.csv)")
st.dataframe(amort_df.head(10))
st.markdown(f"每期應繳(示例,前一筆): {amort_df.loc[0,'每期應繳'] if not amort_df.empty else 'N/A'}")
st.download_button("下載 amortization.csv", amort_df.to_csv(index=False).encode('utf-8'), file_name="amortization.csv")

# ---------- 保費估算 ----------
st.subheader("保費估算(premium_quote.csv)")
st.dataframe(premium_df)
st.download_button("下載 premium_quote.csv", premium_df.to_csv(index=False).encode('utf-8'), file_name="premium_quote.csv")

# ---------- KYC / 客戶資料 ----------
st.subheader("KYC 去識別化(customers_sanitized.csv)")
st.dataframe(cust_df)
st.download_button("下載 customers_sanitized.csv", cust_df.to_csv(index=False).encode('utf-8'), file_name="customers_sanitized.csv")

# ---------- 理賠模擬 ----------
st.subheader("理賠模擬明細(claims_sim.csv)")
st.dataframe(claims_df.head(20))
st.download_button("下載 claims_sim.csv", claims_df.to_csv(index=False).encode('utf-8'), file_name="claims_sim.csv")

st.markdown("---")
st.info("提示:把你在前面日子產出的 CSV(expense.csv、tx_log.csv、amortization.csv、...)放到同一資料夾,重新整理頁面就能直接看到真實資料。")

小結與面試使用建議

  • 把這個儀表板放到 GitHub 並寫一個 README(執行步驟、示範圖),面試時用 streamlit run day29_dashboard.py 即可展示你的產品思維。
  • Demo 時,先說明「資料來源(CSV)→ 清洗 → 視覺化 → 下載」,然後切換幾個實際檔案展示:這樣能清楚傳遞你不只會寫程式,還能把功能串成產品。

上一篇
用 Python 做資料遮罩、卡號 Luhn 驗證與匿名化 ID
系列文
30天用Python打造你的數位金融實力:從零開始的FinTech入門筆記29
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言