模型构建
导入包
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score, precision_score, recall_score,\
confusion_matrix, f1_score, roc_curve, roc_auc_score
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from lightgbm import LGBMClassifier
from xgboost import XGBClassifier
import warnings
%matplotlib inline
plt.rc('font', family='SimHei', size=14)
plt.rcParams['axes.unicode_minus']=False
%config InlineBackend.figure_format = 'retina'
warnings.filterwarnings(module='sklearn*', action='ignore', category=DeprecationWarning)
导入数据
从data_all.csv文件中导入原始数据,并查看数据相关信息:
data_origin = pd.read_csv('data_all.csv')
划分数据集
首先将status列作为数据标签y,其余列作为数据集X:
y = data_origin.status
X = data_origin.drop(['status'], axis=1)
再调用sklearn包将此金融数据集按比例7:3划分为训练集和数据集,随机种子2018:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=2018)
训练模型
构建并训练本次需要用到的七个模型,包含四个集成模型:XGBoost,LightGBM,GBDT,随机森林,和三个非集成模型:逻辑回归,SVM,决策树。所有模型暂时先使用默认参数。
# 逻辑回归
log_reg = LogisticRegression(random_state=2018).fit(X_train, y_train)
# SVM,注意Probability参数要设置为True,便于后续绘制ROC曲线
svc = SVC(random_state=2018, probability=True) .fit(X_train, y_train)
# 决策树
dt_clf = DecisionTreeClassifier(random_state=2018).fit(X_train, y_train)
# 随机森林
rf_clf = RandomForestClassifier(random_state=2018).fit(X_train, y_train)
# GBDT
gbdt = GradientBoostingClassifier(random_state=2018).fit(X_train, y_train)
# XGBoost
xgb = XGBClassifier(random_state=2018).fit(X_train, y_train)、
# LightGBM
lgbm = LGBMClassifier(random_state=2018).fit(X_train, y_train)
计算各指标值
首先定义两个字典,一个是要评估的七个模型,便于后续循环计算。另一个是数值型指标,用于最后整合结果。
models = {'随机森林': rf_clf,
'GBDT': gbdt,
'XGBoost': xgb,
'LightGBM': lgbm,
'逻辑回归': log_reg,
'SVM': svc,
'决策树': dt_clf}
assessments = {
'Accuracy': [],
'Precision': [],
'Recall': [],
'F1-score': [],
'AUC': []
}
准确度Accuracy
计算模型准确度并加入assessments中
for name, model in models.items():
acc_test = accuracy_score(model.predict(X_test), y_test) * 100
acc_train = accuracy_score(model.predict(X_train), y_train) * 100
accuracy = '训练集:%.2f%%;测试集:%.2f%%' % (acc_train, acc_test)
assessments['Accuracy'].append(accuracy)
混淆矩阵
混淆矩阵中的每一行表示一个实际的类, 而每一列表示一个预测的类。一个完美的分类器将只有真反例和真正例,所以混淆矩阵的左上到右下的对角线值越小越好。根据混淆矩阵定义,在二元分类任务中,根据scklearn文档,混淆矩阵的四个值的意义为:
True Negative(TN) | False Positive(FP) |
---|---|
False Negative(FN) | True Positive(TP) |
-
True Positive(TP)表示被正确预测的正例个数
-
False Positive(FP)表示被错误预测的正例个数
-
False Negative(FN)表示被错误预测的反例个数
-
True Negative(TN)表示被正确预测的反例个数
此处仅使用七个模型对测试集进行混淆矩阵的计算,作为示例。
def plot_confusion_matrix(conf, classes, title, cmap=plt.cm.gray):
plt.imshow(conf, interpolation='nearest', cmap=cmap)
plt.title(title)
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes)
plt.yticks(tick_marks, classes)
plt.ylabel('真实标签')
plt.xlabel('预测标签')
plt.tight_layout()
fig = plt.figure(figsize=(12, 9))
i=1
classes=['未逾期', '逾期']
for name, model in models.items():
conf = confusion_matrix(model.predict(X_test), y_test) * 100
print('%s模型的混淆矩阵为\n%s' % (name, conf))
subfig = plt.subplot(3,3,i)
plot_confusion_matrix(conf, classes, name)
plt.subplots_adjust(wspace =0, hspace =0.4)
i += 1
随机森林模型的混淆矩阵为
[[100500 26400]
[ 6300 9500]]
GBDT模型的混淆矩阵为
[[98800 23300]
[ 8000 12600]]
XGBoost模型的混淆矩阵为
[[99300 23100]
[ 7500 12800]]
LightGBM模型的混淆矩阵为
[[97300 23300]
[ 9500 12600]]
逻辑回归模型的混淆矩阵为
[[106800 35900]
[ 0 0]]
SVM模型的混淆矩阵为
[[106800 35900]
[ 0 0]]
决策树模型的混淆矩阵为
[[82900 21100]
[23900 14800]]
精确率Precision
精确率的定义如下:
P
r
e
c
i
s
i
o
n
=
T
P
T
P
+
F
P
Precision=\frac{TP}{TP+FP}
Precision=TP+FPTP
即在所有预测为正例的测试样本中,正确预测的比例。
for name, model in models.items():
pre_test = precision_score(model.predict(X_test), y_test) * 100
pre_train = precision_score(model.predict(X_train), y_train) * 100
precision = '训练集:%.2f%%;测试集:%.2f%%' % (pre_train, pre_test)
assessments['Precision'].append(precision)
召回率Recall
召回率定义如下:
R
e
c
a
l
l
=
T
P
T
P
+
F
N
Recall=\frac{TP}{TP+FN}
Recall=TP+FNTP
即在所有实际为正例的测试样本中,正确预测的比例。
for name, model in models.items():
rec_test = recall_score(model.predict(X_test), y_test) * 100
rec_train = recall_score(model.predict(X_train), y_train) * 100
recall = '训练集:%.2f%%;测试集:%.2f%%' % (rec_train, rec_test)
assessments['Recall'].append(recall)
UndefinedMetricWarning: Recall is ill-defined and being set to 0.0 due to no true samples.
'recall', 'true', average, warn_for)
在模型预测的结果中,若不存在TP和FN样本,会导致Recall定义式的分母为0,即定义错误(ill-dedined)。sklearn会因此给出相关警告信息,并将Recall值设置为0。
返回之前的混淆矩阵计算结果可以分析出,警告是在计算SVM和逻辑回归的Recall值时产生的,因为它们的FN、TP值均为0。
F1值
F1值的定义如下:
F
1
S
c
o
r
e
=
2
×
p
r
e
c
i
s
i
o
n
×
r
e
c
a
l
l
p
r
e
c
i
s
i
o
n
+
r
e
c
a
l
l
F1\space Score=\frac{2\times precision\times recall}{precision + recall}
F1 Score=precision+recall2×precision×recall
F1值是在认为召回率和精确率权重(重要性)相等的情况下,对两者的综合考虑。
for name, model in models.items():
f1_test = f1_score(model.predict(X_test), y_test) * 100
f1_train = f1_score(model.predict(X_train), y_train) * 100
f1 = '训练集:%.2f%%;测试集:%.2f%%' % (f1_train, f1_test)
assessments['F1-score'].append(f1)
UndefinedMetricWarning: F-score is ill-defined and being set to 0.0 due to no true samples.
'recall', 'true', average, warn_for)
和之前Recall值的警告原因类似。在模型预测的结果中,若precision和recall值均为0,会导致F1定义式的分母为0,即定义错误(ill-dedined)。sklearn会因此给出相关警告信息,并将F1值设置为0。
从Recall和Precision计算结果(见总结指标部分)可以分析出,警告是同样是在计算SVM和逻辑回归的Recall值时产生的,因为它们的FN、TP值均为0。
ROC曲线
首先考虑两个指标True positive rate(TPR)和False positive rate(FPR)。TPR定义和召回率相同,而FPR定义如下:
F
P
R
=
F
P
F
P
+
T
N
=
1
−
T
P
R
FPR = \frac{FP}{FP+TN}=1-TPR
FPR=FP+TNFP=1−TPR
以FPR为x轴,TPR为y轴,就得到了ROC曲线。
# ROC曲线绘制函数
def plot_roc_curve(fpr, tpr, label=None):
plt.plot(fpr, tpr, label=label)
plt.plot([0, 1], [0, 1], 'k--')
plt.axis([0, 1, 0, 1])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend()
plt.tight_layout()
单独计算每个模型训练集和测试集的ROC曲线:
for name, model in models.items():
fig = plt.figure(figsize=(8, 6))
proba = model.predict_proba(X_test)[:,1]
fpr, tpr, thresholds = roc_curve(y_test, proba)
plot_roc_curve(fpr, tpr, label='测试集')
proba = model.predict_proba(X_train)[:,1]
fpr, tpr, thresholds = roc_curve(y_train, proba)
plot_roc_curve(fpr, tpr, label='训练集')
plt.title(name)
七个模型对训练集的ROC曲线:
fig = plt.figure(figsize=(8, 6))
for name, model in models.items():
proba = model.predict_proba(X_train)[:,1]
fpr, tpr, thresholds = roc_curve(y_train, proba)
plot_roc_curve(fpr, tpr, label=name)
七个模型对测试集的ROC曲线:
fig = plt.figure(figsize=(8, 6))
for name, model in models.items():
proba = model.predict_proba(X_test)[:,1]
fpr, tpr, thresholds = roc_curve(y_test, proba)
plot_roc_curve(fpr, tpr, label=name)
这里省略结果,放在总结中。
AUC值
AUC值即为ROC曲线下的面积,AUC值越大,模型的区分能力就越强。
for name, model in models.items():
auc_test = roc_auc_score(y_test, model.predict_proba(X_test)[:,1]) * 100
auc_train = roc_auc_score(y_train, model.predict_proba(X_train)[:,1]) * 100
auc = '训练集:%.2f%%;测试集:%.2f%%' % (auc_train, auc_test)
assessments['AUC'].append(auc)
总结指标
数值型指标:
ass_df = pd.DataFrame(assessments, index=models.keys())
ass_df
AUC | Accuracy | F1-score | Precision | Recall | |
---|---|---|---|---|---|
随机森林 | 训练集:99.95% 测试集:71.90% | 训练集:98.47% 测试集:77.08% | 训练集:96.85% 测试集:36.75% | 训练集:93.88%: 测试集:26.46% | 训练集:100.00% 测试集:60.13% |
GBDT | 训练集:92.07%: 测试集:76.38% | 训练集:86.23%: 测试集:78.07% | 训练集:65.41%: 测试集:44.60% | 训练集:51.92%: 测试集:35.10% | 训练集:88.37% 测试集:61.17% |
XGBoost | 训练集:91.84% 测试集:77.14% | 训练集:85.24% 测试集:78.56% | 训练集:62.08% 测试集:45.55% | 训练集:48.20% 测试集:35.65% | 训练集:87.20% 测试集:63.05% |
LightGBM | 训练集:100.00% 测试集:75.74% | 训练集:99.73% 测试集:77.01% | 训练集:99.46% 测试集:43.45% | 训练集:98.92% 测试集:35.10% | 训练集:100.00% 测试集:57.01% |
逻辑回归 | 训练集:57.62% 测试集:56.75% | 训练集:74.93% 测试集:74.84% | 训练集:0.00% 测试集:0.00% | 训练集:0.00% 测试集:0.00% | 训练集:0.00% 测试集:0.00% |
SVM | 训练集:0.00% 测试集:50.00% | 训练集:100.00% 测试集:74.84% | 训练集:100.00% 测试集:0.00% | 训练集:100.00% 测试集:0.00% | 训练集:100.00% 测试集:0.00% |
决策树 | 训练集:100.00% 测试集:59.42% | 训练集:100.00% 测试集:68.47% | 训练集:100.00% 测试集:39.68% | 训练集:100.00% 测试集:41.23% | 训练集:100.00% 测试集:38.24% |
集成模型 | 非集成模型 |
---|---|
综合比较ROC曲线:
训练集 | 测试集 |
---|---|