telco-customer-churn-predic.../app.py

80 lines
4.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 year1年", "Two year2年"])
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 year1年": "One year", "Two year2年": "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- 电子支票支付:自动续费优惠")