连载的上一篇文章,小鱼和大家一起学习了 ROC 曲线和 AUC 面积:AUC 被定义为 ROC 曲线下方的面积,AUC 面积的取值为 0.5 ~ 1 之间,越接近于 1 则分类器的分类效果越好。
此外,我们还对导入的政党捐赠数据集进行了标签处理、度热编码以及数据集的切分。得到的训练集数据和标签如下:
本节,小鱼将使用决策树和随机森林进行建模,我们来实际感受一下随机森林 Bagging 思想的魅力。
数据集样本占比情况
首先,我们来看一下原始数据集中正负样本分布情况:
y_counts = df.cand_pty_affiliation.value_counts(normalize=True)
y_counts.plot(kind='bar', title="Share of donations")
value_counts
函数如果想得出计数占比,可以加参数 normalize=True
绘制结果:
使用过采样方法平衡正负样本:
from imblearn.over_sampling import SMOTE
smote = SMOTE(random_state=SEED)
x_over_sample_train, y_over_sample_train = smote.fit_resample(xtrain, ytrain)
plt.bar(['DEM', 'REP'],y_over_sample_train.value_counts())
plt.title('over sample train dataset')
SMOTE 过采样结果:
这样就可以是的模型在训练时学习到的正负样本数量一样多,从而做出更客观的决断。
树模型的可视化以及 ROC-AUC Score
下面,我们来定义决策树可视化的函数 print_graph
:
环境:需要安装
pydotplus
Python 库,并在操作系统安装 graphviz。
graphviz 的下载地址为:http://download.csdn.net/download/shouwangzhelv/9492517 ,将安装或者解压的 graphviz 下的 bin 目录添加到系统的 path 中,重启 notebook。
sklearn.tree.export_graphviz
的参数 class_names
可以指定决策树分类标签使用的绘制名称;clf
为训练好的决策树模型。套用小鱼的 print_graph
函数时,只需要修改这两个参数即可。
import pydotplus
from IPython.display import Image
from sklearn.metrics import roc_auc_score
from sklearn.tree import DecisionTreeClassifier, export_graphviz
def print_graph(clf, feature_names):
"""pringt decision tree"""
graph = export_graphviz(clf, label="root", proportion=True, impurity=False, out_file=None,
feature_names=feature_names, class_names={0: "D", 1: "R"}, filled=True, rounded=True)
graph = pydotplus.graph_from_dot_data(graph)
return Image(graph.create_png())
下面,小鱼就来绘制一个深度为 1 的决策树试试吧~
t1_o = DecisionTreeClassifier(max_depth=1, random_state=SEED)
t1_o.fit(x_over_sample_train, y_over_sample_train)
p_o = t1_o.predict_proba(xtest)[:,1]
print("Decision tree ROC-AUC score: ", roc_auc_score(ytest, p_o))
print_graph(t1_o, x_over_sample_train.columns)
其中,roc_auc_score
导入自 sklearn.metrics
模块,用于评估模型的分类效果,越接近于 1 ,说明模型越理想。
Decision tree ROC-AUC score: 0.6243616070247398
决策树根节点中的 transation_tp_15E <=0.5 指出了该节点分类时使用的判断条件,value
表示正负样本的占比。
叶子节点中,第一行百分比表示有多少样本落在了当前节点:经过根节点的切分,86.6% 的样本落在了左子树,13.4% 的样本落在了右子树。
第二行,即 value 值,表示正负样本占比情况:左边的叶子节点中,标签 0 占比为 0.425,标签 1 占比为 0.575,因此左边的叶子节点被判定为标签 1 类型,即 R,已经在第三行为我们标识出来了。
决策树模型
首先,我们来训练一棵决策树。
注:为了可视化演示的方便,小鱼这里将决策树的深度限制为 3 。
t2_o = DecisionTreeClassifier(max_depth=3, random_state=SEED)
t2_o.fit(x_over_sample_train, y_over_sample_train)
p_o = t2_o.predict_proba(xtest)[:,1]
print("Decision tree ROC-AUC score: ", roc_auc_score(ytest, p_o))
print_graph(t2_o, x_over_sample_train.columns)
ROC-AUC Score 为:
Decision tree ROC-AUC score: 0.7541002451733411
决策树可视化展示:
上述决策树中,有个叶子节点非常醒目,有 49.8% 的样本都落到了该叶子节点;还有最左侧的叶子节点,23.9% 的样本也落在了该叶子节点上。
此时的模型过拟合的风险是比较大的,因为它很可能过度地关注某一个特征,而忽视了其它特征。我们希望模型在做决策时,充分考虑所有特征,群策群力,而不是过分依赖某个特征,这样的模型是片面的。
下面,我们尝试去掉对结果响应最大的特征 transaction_tp_15E
看看:
drop = ["transaction_tp_15E"]
xtrain_slim_o = x_over_sample_train.drop(drop, axis=1)
xtest_slim = xtest.drop(drop, axis=1)
t3_o = DecisionTreeClassifier(max_depth=3, random_state=SEED)
t3_o.fit(xtrain_slim_o, y_over_sample_train)
p = t3_o.predict_proba(xtest_slim)[:, 1]
print("Decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))
print_graph(t3_o, xtrain_slim.columns)
去掉 transaction_tp_15E
后的决策树 ROC-AUC Score 为:
Decision tree ROC-AUC score: 0.765
可视化展示:
两棵树的 ROC-AUC Score 值基本一致,评估结果差不多;但决策树的内部构造确是完全不同的,可以说它们各自有各自的错误,也各自有各自的优点,那我们何不综合这两棵树来得出最终的预测呢?
p1_o = t2_o.predict_proba(xtest)[:, 1]
p2_o = t3_o.predict_proba(xtest_slim)[:, 1]
p = np.mean([p1_o, p2_o], axis=0)
print("Average of decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))
综合两棵树得出的 ROC-AUC Score 值:
Average of decision tree ROC-AUC score: 0.773
一平均 ROC-AUC 的值还真的提高了!可见,选择不同的特征会产生不同的结果,然后用不同的结果进行组合得到了一个升华!那让我们多选几组不就是随机森林了吗?
随机森林
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(n_estimators=100, max_features=3, random_state=SEED)
rf.fit(x_over_sample_train, y_over_sample_train)
p_o = rf.predict_proba(xtest)[:, 1]
print("Average of decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p_o))
使用随机森林构造 100 棵不同的决策树,评估结果:
Average of decision tree ROC-AUC score: 0.869
使用随机森林建模的 ROC-AUC Score 值又有了显著的提升!这就是 Bagging 集成思想的魅力~
补充
除了使用 Graphviz 插件绘制决策树之外,还可以使用 sklearn 自带的 plot_tree
函数来绘制:
from sklearn import tree
import matplotlib.pyplot as plt
fig, axe = plt.subplots(figsize=(12,6), dpi=150)
# 使用sklearn自带的工具绘制决策树, impurity为True则显示gini系数
tree.plot_tree(t2_o, filled=True, ax=axe, proportion=True, rounded=True, impurity=False, label='root',
feature_names=xtrain.columns, fontsize=10, class_names={0:'D', 1:'R'})
绘图结果:
网友评论