DAY 16

📅 2026/7/7 1:14:21 👁️ 阅读次数 📝 编程学习
DAY 16

浙大疏锦行

---------------------- 1. 导入所有依赖库 ----------------------

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings(“ignore”)

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import (
accuracy_score, precision_score, recall_score, f1_score,
roc_auc_score, roc_curve, precision_recall_curve, auc
)

设置中文显示,避免图表乱码

plt.rcParams[‘font.sans-serif’] = [‘SimHei’]
plt.rcParams[‘axes.unicode_minus’] = False

---------------------- 2. 读取数据 ----------------------

读取同目录下的 data.csv

df = pd.read_csv(r"C:\Python Study\Python60DaysChallenge-main\data.csv")

标签列:Credit Default(1=违约,0=正常)

target_col = “Credit Default”

查看数据基本信息

print(“=” * 60)
print(“数据基本信息”)
print(“=” * 60)
print(f"样本总数:{df.shape[0]},特征总数:{df.shape[1]-1}“)
print(f"正负样本分布:\n{df[target_col].value_counts()}”)
print(f"违约占比:{df[target_col].mean():.2%}“)
print(”\n")

---------------------- 3. 数据预处理 ----------------------

3.1 分离特征与标签

X = df.drop(target_col, axis=1)
y = df[target_col]

3.2 处理缺失值:数值型用中位数填充,类别型用众数填充

num_cols = X.select_dtypes(include=[np.number]).columns
cat_cols = X.select_dtypes(exclude=[np.number]).columns

X[num_cols] = X[num_cols].fillna(X[num_cols].median())
for col in cat_cols:
X[col] = X[col].fillna(X[col].mode()[0])

3.3 类别特征独热编码

X = pd.get_dummies(X, columns=cat_cols, drop_first=True)

3.4 划分训练集和测试集(保持正负样本比例)

X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y
)

3.5 数值特征标准化

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

print(“=” * 60)
print(“数据预处理完成”)
print(“=” * 60)
print(f"训练集样本数:{X_train.shape[0]},测试集样本数:{X_test.shape[0]}“)
print(f"预处理后特征数:{X_train.shape[1]}”)
print(“\n”)

---------------------- 4. 定义待对比模型 ----------------------

models = {
“逻辑回归”: LogisticRegression(random_state=42, class_weight=“balanced”, max_iter=1000),
“决策树”: DecisionTreeClassifier(random_state=42, class_weight=“balanced”),
“随机森林”: RandomForestClassifier(n_estimators=150, random_state=42, class_weight=“balanced”, n_jobs=-1),
“K近邻”: KNeighborsClassifier(n_neighbors=5)
}

---------------------- 5. 批量训练 + 计算评估指标 ----------------------

metrics_result = []
roc_dict = {}
pr_dict = {}

for model_name, model in models.items():
print(f"正在训练:{model_name}…")

# 逻辑回归和KNN用标准化后的数据,树模型用原始数据 if model_name in ["逻辑回归", "K近邻"]: model.fit(X_train_scaled, y_train) y_pred = model.predict(X_test_scaled) y_prob = model.predict_proba(X_test_scaled)[:, 1] else: model.fit(X_train, y_train) y_pred = model.predict(X_test) y_prob = model.predict_proba(X_test)[:, 1] # 计算核心评估指标 acc = accuracy_score(y_test, y_pred) precision = precision_score(y_test, y_pred) recall = recall_score(y_test, y_pred) f1 = f1_score(y_test, y_pred) roc_auc = roc_auc_score(y_test, y_prob) # 计算PR曲线及PR-AUC precision_curve, recall_curve, _ = precision_recall_curve(y_test, y_prob) pr_auc = auc(recall_curve, precision_curve) # 保存结果 metrics_result.append({ "模型名称": model_name, "准确率 Accuracy": round(acc, 4), "精确率 Precision": round(precision, 4), "召回率 Recall": round(recall, 4), "F1分数": round(f1, 4), "ROC-AUC": round(roc_auc, 4), "PR-AUC": round(pr_auc, 4) }) # 保存曲线数据 fpr, tpr, _ = roc_curve(y_test, y_prob) roc_dict[model_name] = (fpr, tpr, roc_auc) pr_dict[model_name] = (recall_curve, precision_curve, pr_auc)

打印评估指标总表

metrics_df = pd.DataFrame(metrics_result)
print(“\n”)
print(“=” * 80)
print(“各模型信贷风控评估指标汇总”)
print(“=” * 80)
print(metrics_df.to_string(index=False))
print(“\n”)

---------------------- 6. 绘制ROC曲线 ----------------------

plt.figure(figsize=(10, 6), dpi=100)
plt.plot([0, 1], [0, 1], “k–”, linewidth=1, label=“随机猜测 (AUC=0.5)”)

for name, (fpr, tpr, auc_val) in roc_dict.items():
plt.plot(fpr, tpr, linewidth=2, label=f"{name} (AUC={auc_val:.4f})")

plt.xlabel(“假正率 FPR”, fontsize=12)
plt.ylabel(“真正率 TPR”, fontsize=12)
plt.title(“各模型 ROC 曲线对比”, fontsize=14)
plt.legend(loc=“lower right”, fontsize=10)
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()

---------------------- 7. 绘制PR曲线 ----------------------

plt.figure(figsize=(10, 6), dpi=100)
pos_ratio = y_test.mean()
plt.axhline(y=pos_ratio, color=“k”, linestyle=“–”, linewidth=1,
label=f"随机猜测 (基准={pos_ratio:.3f})")

for name, (recall_curve, precision_curve, auc_val) in pr_dict.items():
plt.plot(recall_curve, precision_curve, linewidth=2,
label=f"{name} (AUC={auc_val:.4f})")

plt.xlabel(“召回率 Recall”, fontsize=12)
plt.ylabel(“精确率 Precision”, fontsize=12)
plt.title(“各模型 PR 曲线对比(不平衡数据场景)”, fontsize=14)
plt.legend(loc=“lower left”, fontsize=10)
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()

---------------------- 8. 模型能力解读(作业分析参考) ----------------------

print(“=” * 80)
print(“信贷风控视角下的模型能力理解要点”)
print(“=” * 80)
print(“1. ROC-AUC:衡量模型整体区分好坏客户的能力,越接近1表示整体排序能力越强;”)
print(“2. PR-AUC:针对信贷数据正负样本不平衡,比ROC更敏感,更能反映对违约样本的识别能力;”)
print(“3. 召回率:代表能识别出多少真实违约客户,值越高,漏判的坏账越少;”)
print(“4. 精确率:代表预测为违约的客户中真违约的比例,值越高,误拒的正常客户越少;”)
print(“5. 逻辑回归可解释性强,是风控行业基线模型;随机森林等集成模型预测精度更高;”)
print(“6. 实际风控中需要在召回率和精确率之间做权衡,根据业务成本选择最优阈值。”)