Python 数据分析实战:金融科技信贷风控领域研究
发布时间
阅读量:
阅读量
目录
一、案例背景
二、代码实现
2.1 数据收集
2.2 数据探索性分析
2.3 数据清洗
2.4 数据分析
2.4.1 构建信用评估模型
2.4.2 模型调优
2.4.3 模型评估与可视化
三、主要的代码难点解析
3.1 数据收集
3.2 数据清洗
3.3 数据分析 - 构建信用评估模型
3.4 数据分析 - 模型调优
3.5 数据可视化
四、可能改进的代码
4.1 数据收集改进
4.2 数据清洗改进
4.3 数据分析改进
一、案例背景
在当今金融科技蓬勃发展的背景下
二、代码实现
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import requests
from bs4 import BeautifulSoup
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_curve, auc
2.1 数据收集
该段文字经过改写后的内容如下:
注
从金融科技公司数据库中收集相关的历史信贷申请数据,涵盖 applicants' comprehensive information such as age, income, occupation, and detailed loan parameters including loan amount, term, and interest rate. Additionally, the repayment history will be recorded to assess default risks. All data will be formatted into a CSV file for easy access and analysis.
credit_data = pd.read_csv('financial_tech_credit_data.csv')
从第三方信用评级机构网站收集某些申请人的信用评分数据,并进行数据分析处理:
url = 'https://www.creditratingagency.com/credit_scores'
headers = {
'User - Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
response = requests.get(url, headers = headers)
soup = BeautifulSoup(response.text, 'html.parser')
credit_score_data = []
table = soup.find('table', class_='credit - score - table')
rows = table.find_all('tr')
for row in rows[1:]:
cols = row.find_all('td')
applicant_id = cols[0].text.strip()
credit_score = int(cols[1].text.strip())
credit_score_data.append({'Applicant_ID': applicant_id, 'Credit_Score': credit_score})
credit_score_df = pd.DataFrame(credit_score_data)
2.2 数据探索性分析
# 查看信贷数据基本信息
print(credit_data.info())
# 查看信用评分数据基本信息
print(credit_score_df.info())
# 分析贷款违约率
default_rate = credit_data['Default'].mean()
print(f'Loan default rate: {default_rate:.2f}%')
# 查看不同职业的贷款申请数量
occupation_count = credit_data['Occupation'].value_counts()
plt.figure(figsize=(10, 6))
sns.barplot(x=occupation_count.index, y=occupation_count.values)
plt.title('Number of Loan Applications by Occupation')
plt.xlabel('Occupation')
plt.ylabel('Number of Applications')
plt.xticks(rotation=45)
plt.show()
# 分析贷款金额与违约的关系
plt.figure(figsize=(12, 6))
sns.boxplot(x='Default', y='Loan_Amount', data=credit_data)
plt.title('Relationship between Loan Amount and Default')
plt.xlabel('Default (0 = No, 1 = Yes)')
plt.ylabel('Loan Amount')
plt.show()
2.3 数据清洗
# 合并信贷数据和信用评分数据
credit_data = pd.merge(credit_data, credit_score_df, on='Applicant_ID', how='left')
# 处理缺失值
# 对于数值型特征,用均值填充
credit_data['Income'].fillna(credit_data['Income'].mean(), inplace=True)
credit_data['Credit_Score'].fillna(credit_data['Credit_Score'].mean(), inplace=True)
# 对于类别型特征,用最频繁出现的值填充
credit_data['Occupation'].fillna(credit_data['Occupation'].value_counts().index[0], inplace=True)
# 处理异常值
# 去除贷款金额为负数的记录
credit_data = credit_data[credit_data['Loan_Amount'] > 0]
2.4 数据分析
2.4.1 构建信用评估模型
# 特征工程
X = credit_data.drop(['Applicant_ID', 'Default'], axis = 1)
y = credit_data['Default']
X = pd.get_dummies(X)
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 42)
# 逻辑回归模型
logreg = LogisticRegression()
logreg.fit(X_train, y_train)
y_pred_logreg = logreg.predict(X_test)
logreg_accuracy = accuracy_score(y_test, y_pred_logreg)
logreg_precision = precision_score(y_test, y_pred_logreg)
logreg_recall = recall_score(y_test, y_pred_logreg)
logreg_f1 = f1_score(y_test, y_pred_logreg)
print(f'Logistic Regression - Accuracy: {logreg_accuracy:.4f}, Precision: {logreg_precision:.4f}, Recall: {logreg_recall:.4f}, F1 - score: {logreg_f1:.4f}')
# 决策树模型
dt = DecisionTreeClassifier()
dt.fit(X_train, y_train)
y_pred_dt = dt.predict(X_test)
dt_accuracy = accuracy_score(y_test, y_pred_dt)
dt_precision = precision_score(y_test, y_pred_dt)
dt_recall = recall_score(y_test, y_pred_dt)
dt_f1 = f1_score(y_test, y_pred_dt)
print(f'Decision Tree - Accuracy: {dt_accuracy:.4f}, Precision: {dt_precision:.4f}, Recall: {dt_recall:.4f}, F1 - score: {dt_f1:.4f}')
# 随机森林模型
rf = RandomForestClassifier()
rf.fit(X_train, y_train)
y_pred_rf = rf.predict(X_test)
rf_accuracy = accuracy_score(y_test, y_pred_rf)
rf_precision = precision_score(y_test, y_pred_rf)
rf_recall = recall_score(y_test, y_pred_rf)
rf_f1 = f1_score(y_test, y_pred_rf)
print(f'Random Forest - Accuracy: {rf_accuracy:.4f}, Precision: {rf_precision:.4f}, Recall: {rf_recall:.4f}, F1 - score: {rf_f1:.4f}')
2.4.2 模型调优
# 随机森林模型调优
param_grid = {
'n_estimators': [50, 100, 150],
'max_depth': [3, 5, 7],
'min_samples_split': [2, 5, 10]
}
grid_search = GridSearchCV(rf, param_grid, cv = 5, scoring='f1')
grid_search.fit(X_train, y_train)
best_params = grid_search.best_params_
print('Best parameters for Random Forest:', best_params)
# 使用最佳参数重新训练随机森林模型
best_rf = RandomForestClassifier(**best_params)
best_rf.fit(X_train, y_train)
y_pred_best_rf = best_rf.predict(X_test)
best_rf_accuracy = accuracy_score(y_test, y_pred_best_rf)
best_rf_precision = precision_score(y_test, y_pred_best_rf)
best_rf_recall = recall_score(y_test, y_pred_best_rf)
best_rf_f1 = f1_score(y_test, y_pred_best_rf)
print(f'Best Random Forest - Accuracy: {best_rf_accuracy:.4f}, Precision: {best_rf_precision:.4f}, Recall: {best_rf_recall:.4f}, F1 - score: {best_rf_f1:.4f}')
2.4.3 模型评估与可视化
# 绘制ROC曲线
fpr_logreg, tpr_logreg, thresholds_logreg = roc_curve(y_test, logreg.predict_proba(X_test)[:, 1])
fpr_dt, tpr_dt, thresholds_dt = roc_curve(y_test, dt.predict_proba(X_test)[:, 1])
fpr_rf, tpr_rf, thresholds_rf = roc_curve(y_test, rf.predict_proba(X_test)[:, 1])
fpr_best_rf, tpr_best_rf, thresholds_best_rf = roc_curve(y_test, best_rf.predict_proba(X_test)[:, 1])
roc_auc_logreg = auc(fpr_logreg, tpr_logreg)
roc_auc_dt = auc(fpr_dt, tpr_dt)
roc_auc_rf = auc(fpr_rf, tpr_rf)
roc_auc_best_rf = auc(fpr_best_rf, tpr_best_rf)
plt.figure(figsize=(10, 8))
plt.plot(fpr_logreg, tpr_logreg, label='Logistic Regression (AUC = %0.2f)' % roc_auc_logreg)
plt.plot(fpr_dt, tpr_dt, label='Decision Tree (AUC = %0.2f)' % roc_auc_dt)
plt.plot(fpr_rf, tpr_rf, label='Random Forest (AUC = %0.2f)' % roc_auc_rf)
plt.plot(fpr_best_rf, tpr_best_rf, label='Best Random Forest (AUC = %0.2f)' % roc_auc_best_rf)
plt.plot([0, 1], [0, 1], 'k--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic')
plt.legend(loc="lower right")
plt.show()
三、主要的代码难点解析
3.1 数据收集
credit_data = pd.read_csv('financial_tech_credit_data.csv')
- 难点 :金融科技公司内部数据包含大量敏感信息(包含大量敏感信息),其数据安全与隐私保护要求极其严格(要求极其严格),获取与使用这些数据需遵循严格的合规流程(遵循)。第三方信用评级机构网站可能设置复杂的防反爬机制(可能设置),导致数据抓取受限(受限),且数据格式可能不统一(可能不统一),需要投入大量资源进行预处理工作(需要投入)。不同来源的数据结构存在显著差异(显著差异),整合难度较大(较大)。
- 解决思路 :在与金融科技公司合作时,应签署详尽的数据保密协议书(签署详尽的数据保密协议书),明确双方对数据使用范围、存储方式及保障措施的具体约定(具体约定),确保符合合规要求(合规要求)。针对第三方网站的防反爬机制,在确保不触发防反爬限制的前提下(的前提下),可采用模仿真实用户行为模式的方式进行请求控制(行为模式的方式进行请求控制)。通过设置合理的请求间隔并合理配置代理 IP 池来规避 IP 封锁问题(合理配置代理 IP 池来规避);获取相关数据后需编写统一的数据清洗与转换脚本以规范数据格式(清洗与转换脚本以规范)。开发基于数据字典和业务逻辑的数据整合工具,在保证结构一致性的同时实现多源数据的有效融合整合(同时实现有效融合整合)。
3.2 数据清洗
credit_data = pd.merge(credit_data, credit_score_df, on='Applicant_ID', how='left')
- 难点 :合并不同来源数据时,可能存在数据不匹配问题,如申请人 ID 格式不一致、部分 ID 缺失等。缺失值处理较为复杂,不同特征的缺失值需根据业务逻辑和数据分布选择合适的填充方法。异常值检测和处理也需结合金融业务知识,避免误删有效数据。
- 解决思路 :在合并数据前,对申请人 ID 进行格式统一和去重处理,通过数据验证确保 ID 的准确性。对于缺失值,数值型特征根据其分布情况选择均值、中位数或众数填充;类别型特征用最频繁出现的值填充,或者利用机器学习算法(如 K 近邻算法)进行预测填充。异常值检测采用统计方法(如箱线图、Z - score)和机器学习算法(如 Isolation Forest)结合,根据金融业务规则判断异常值是否合理,合理的异常值保留,不合理的进行修正或删除。
3.3 数据分析 - 构建信用评估模型
X = pd.get_dummies(X)
- 难点:在特征工程中,默认情况下类别型变量的编码会引发维度爆炸问题,并导致计算开销的显著提升以及过拟合问题的出现。由于各类机器学习模型对于变量类型的敏感度存在差异,在实际建模过程中需要依据具体业务背景选择合适的编码策略,并结合变量间的关系进行降维处理以优化预测效果。
- 解决思路:针对类别型变量的高基数问题,在实际应用中我们通常采用独热编码(One-Hot Encoding)的方式将分类变量转化为虚拟变量形式,并结合χ²检验以及Mutual Information Method等指标选择机制提取关键属性以实现降维目标;同时根据不同场景选择合适的预处理方法以满足各类机器学习算法的需求;最后通过系统调优或自动化搜索来确定最佳超参数配置以实现最优预测效果。
3.4 数据分析 - 模型调优
grid_search = GridSearchCV(rf, param_grid, cv = 5, scoring='f1')
- 关键问题:确定参数范围的过程本身充满挑战性。当范围设定过大时会导致计算量急剧上升;而如果设定得太小,则可能导致无法寻找到最佳参数。在优化过程中需要耗费大量计算资源尤其是面对复杂模型与海量数据时可能会导致运行时间延长甚至内存溢出。此外不同评估指标会对模型性能表现产生不同的侧重作用因此在优化策略的选择上需要结合具体业务需求来做出合适决策。
- 解决方案:首先结合经验与初步实验来设定一个大致的参数区间随后逐步缩小该区间并进行细致调整。为了提高优化效率可借助分布式计算框架(例如Dask或Apache Spark)以及云计算资源来提升效率从而减少时间和内存压力最终将优化目标聚焦于具体业务需求:若业务重点在于识别违约客户(即关注召回率)则建议采用召回率作为评价指标;而如果更加重视模型预测的准确性则可选用精确率或F1值作为评价标准。
3.5 数据可视化
plt.plot(fpr_logreg, tpr_logreg, label='Logistic Regression (AUC = %0.2f)' % roc_auc_logreg)
- 难点:绘制ROC曲线等可视化图表时需要以清晰的方式展示多个模型之间的性能对比,并且确保这些图表既美观又易于理解;尤其是当处理复杂模型或大数据集时,在这种情况下可能会出现数据点过于密集、曲线之间难以区分等问题。
- 解决思路:采用具有明显色彩区分度的颜色方案以及不同的线条样式来区分不同模型对应的ROC曲线,并附带详细的图例说明;对于数据密度较高的情况,则可以通过适当调节坐标轴范围及刻度设置来优化视觉效果;此外还可以使用标记符号突出关键数据点;最后,在图表中标注详细说明文字或标签来解释曲线的具体含义以及各模型之间的性能差异。
四、可能改进的代码
4.1 数据收集改进
# 从多个第三方信用评级机构网站抓取信用评分数据
rating_agency_urls = [
'https://www.creditratingagency1.com/credit_scores',
'https://www.creditratingagency2.com/credit_scores'
]
all_credit_score_data = []
for url in rating_agency_urls:
headers = {
'User - Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
response = requests.get(url, headers = headers)
soup = BeautifulSoup(response.text, 'html.parser')
table = soup.find('table', class_='credit - score - table')
rows = table.find_all('tr')
for row in rows[1:]:
cols = row.find_all('td')
applicant_id = cols[0].text.strip()
credit_score = int(cols[1].text.strip())
all_credit_score_data.append({'Applicant_ID': applicant_id, 'Credit_Score': credit_score})
all_credit_score_df = pd.DataFrame(all_credit_score_data)
4.2 数据清洗改进
# 使用K近邻算法填充缺失值
from sklearn.impute import KNNImputer
imputer = KNNImputer(n_neighbors = 5)
credit_data[['Income', 'Credit_Score']] = imputer.fit_transform(credit_data[['Income', 'Credit_Score']])
4.3 数据分析改进
# 使用XGBoost模型进行信用评估
from xgboost import XGBClassifier
xgb = XGBClassifier()
xgb.fit(X_train, y_train)
y_pred_xgb = xgb.predict(X_test)
xgb_accuracy = accuracy_score(y_test, y_pred_xgb)
xgb_precision = precision_score(y_test, y_pred_xgb)
xgb_recall = recall_score(y_test, y_pred_xgb)
xgb_f1 = f1_score(y_test, y_pred_xgb)
print(f'XGBoost - Accuracy: {xgb_accuracy:.4f}, Precision: {xgb_precision:.4f}, Recall: {x
全部评论 (0)
还没有任何评论哟~
