# app.py - 电信客户流失预测Streamlit交互页面 import streamlit as st import joblib import pandas as pd import matplotlib.pyplot as plt import seaborn as sns # 基础设置(中文显示) plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] plt.rcParams['axes.unicode_minus'] = False # 缓存模型 @st.cache_resource def load_trained_model(): try: model = joblib.load('telco_churn_model.pkl') return model except FileNotFoundError: st.error("❌ 未找到模型文件!请先运行 src/model.py 训练模型") return None # 页面标题 st.set_page_config(page_title="电信客户流失预测系统", page_icon="📱", layout="wide") st.title("📱 电信客户流失预测系统") st.divider() # 1. 客户信息输入 st.subheader("1. 输入客户信息") with st.form("customer_form"): col1, col2 = st.columns(2) with col1: tenure = st.number_input("在网时长(月)", min_value=0, max_value=72, value=12) monthly_charges = st.number_input("月消费金额", min_value=18.0, max_value=120.0, value=69.99) total_charges = st.number_input("总消费金额", min_value=18.0, max_value=8684.0, value=839.88) with col2: contract = st.selectbox("合约类型", ["Month-to-month(月付)", "One year(1年)", "Two year(2年)"]) internet_service = st.selectbox("网络服务", ["DSL(宽带)", "Fiber optic(光纤)", "No(无)"]) payment_method = st.selectbox("支付方式", ["Electronic check(电子支票)", "Mailed check(邮寄支票)", "Bank transfer(银行转账)", "Credit card(信用卡)"]) submit_btn = st.form_submit_button("🚀 预测流失风险") # 2. 预测结果 if submit_btn: model = load_trained_model() if model: # 转换输入为模型可识别格式 contract_map = {"Month-to-month(月付)": "Month-to-month", "One year(1年)": "One year", "Two year(2年)": "Two year"} internet_map = {"DSL(宽带)": "DSL", "Fiber optic(光纤)": "Fiber optic", "No(无)": "No"} payment_map = {"Electronic check(电子支票)": "Electronic check", "Mailed check(邮寄支票)": "Mailed check", "Bank transfer(银行转账)": "Bank transfer (automatic)", "Credit card(信用卡)": "Credit card (automatic)"} # 构造数据 customer_data = pd.DataFrame({ 'customerID': ['TEST001'], 'tenure': [tenure], 'MonthlyCharges': [monthly_charges], 'TotalCharges': [total_charges], 'Contract': [contract_map[contract]], 'InternetService': [internet_map[internet_service]], 'PaymentMethod': [payment_map[payment_method]], 'OnlineSecurity': ['No'], 'TechSupport': ['No'], 'PaperlessBilling': ['Yes'], 'gender': ['Female'], 'SeniorCitizen': [0], 'Partner': ['Yes'], 'Dependents': ['No'], 'PhoneService': ['Yes'], 'MultipleLines': ['No'], 'OnlineBackup': ['Yes'], 'DeviceProtection': ['No'], 'StreamingTV': ['Yes'], 'StreamingMovies': ['No'] }) # 添加特征组合 customer_data['tenure_monthly'] = customer_data['tenure'] * customer_data['MonthlyCharges'] customer_data['tenure_ratio'] = customer_data['tenure'] / (customer_data['TotalCharges'] + 1) customer_data['monthly_total_ratio'] = customer_data['MonthlyCharges'] / (customer_data['TotalCharges'] + 1) # 预测 churn_pred = model.predict(customer_data)[0] churn_prob = model.predict_proba(customer_data)[:, 1][0] # 展示结果 st.divider() st.subheader("2. 流失风险预测结果") if churn_pred == 1: st.error(f"⚠️ 流失风险高(概率:{churn_prob:.2%})") else: st.success(f"✅ 流失风险低(概率:{churn_prob:.2%})") # 3. 分析与建议 st.divider() st.subheader("3. 流失影响因素") st.image("特征重要性TOP10.png", caption="影响流失的TOP10因素") st.subheader("4. 留存建议") st.markdown("- 短在网时长+高消费:提供长期合约折扣\n- 光纤用户:优化网络稳定性\n- 电子支票支付:自动续费优惠")