本文将介绍如何使用 Python 构建和使用随机森林。将从一个解决简单问题的单个决策树开始,然后逐渐深入,最终完成一个针对某个真实世界数据科学问题的随机森林。本文所涉及的完整代码可参阅GitHub 上的 Jupyter Notebook(点击阅读原文获取
先从一个如下所示的非常简单的二元分类任务开始:
我们的数据仅有两个特征,共有 6 个数据点,2 种标签。
尽管这个问题很简单,但却无法实现线性分割。现在我们采用决策树的方式来解决,为了创建决策树,并在数据上进行训练,在此使用 Scikit-Learn:
from
 sklearn.tree 
import
 DecisionTreeClassifier

# Make a decision tree and train

tree = DecisionTreeClassifier(random_state=RSEED) 

tree.fit(X, y) 
在训练数据上测试模型的准确度:
print(
f Model Accuracy: {tree.score(X, y)}
)


Model Accuracy: 
1.0
可以看到正确率为 100%,这符合预期。可视化如下:
尽管我们的模型能正确分类所有的训练数据点,但这并不意味着它就是完美的,因为它与训练数据可能过拟合了。你可能会问为什么不直接使用一个决策树?这种分类器堪称完美,因为根本不会犯任何错误!但要记住一个重点:决策树只是不会在训练数据上犯错。
过拟合是指我们的模型有很高的方差并且本质上记忆了训练数据的情况。这意味着其在训练数据上表现非常好,甚至能达到完美的程度,但这样它将无法在测试数据上做出准确的预测,因为测试数据是不同的!为什么当我们不限制决策树的最大深度时会使其容易过拟合呢?因为此时决策树有不受限制的复杂度,这意味着它会不断生长,直到针对每个观察都有一个叶节点,从而完美地分类所有数据点。
随机森林是由许多决策树构成的模型。这不仅仅是森林,而且是随机的,这涉及到两个概念:
1.随机采样数据点
2.基于特征的子集分割节点
随机森林的一大关键是每个树都在随机的数据点样本上进行训练。这些样本是可重复地抽取出来的(称为 bootstrapping),也就是说某些样本会多次用于单个树的训练(如果有需要,也可以禁止这种做法)。其思路是,通过在不同样本上训练每个树,尽管每个树依据训练数据的某个特定子集而可能有较高方差,但整体而言整个森林的方差会很低。这种在数据的不同子集上训练每个单个学习器然后再求预测结果的平均的流程被称为 bagging,这是 bootstrap aggregating 的缩写。

非常类似于其它 Scikit-Learn 模型,通过 Python 使用随机森林仅需要几行代码。我们将会构建一个随机森林,但不是针对上述的简单问题。为了比较随机森林与单个决策树的能力,我们将使用一个真实数据集,并将其分成了训练集和测试集。
数据集
该数据集是由美国疾病预防控制中心收集的,可在这里获取:https://www.kaggle.com/cdc/behavioral-risk-factor-surveillance-system。这是一个不平衡分类问题,因此准确度并不是合适的度量标准。我们将衡量曲线下受试者工作特性曲线(ROC AUC),该度量的取值范围为 0(最差)到 1(最好),随机猜测的分数为 0.5。我们还可以绘制 ROC 曲线来评估模型的表现。
在读取了数据之后,我们可以用以下代码实例化并训练一个随机森林:
from
 sklearn.ensemble 
import
 RandomForestClassifier


# Create the model with 100 trees

model = RandomForestClassifier(n_estimators=
100

random_state=RSEED, 

max_features = 
sqrt

n_jobs=
-1
, verbose = 
1
)


# Fit on training data

model.fit(train, train_labels) 
经过几分钟的训练之后,可以通过以下代码让该模型基于测试数据进行预测:
rf_predictions = model.predict(test) rf_probs = model.predict_proba(test)[:, 
1
]

我们既有类别预测结果(predict),也有预测概率(predict_proba),都是计算 ROC AUC 所需的。有了测试预测结果之后,我们可以将它们与测试标签进行比较,以计算出 ROC AUC。
from
 sklearn.metrics 
import
 roc_auc_score


# Calculate roc auc

roc_value = roc_auc_score(test_labels, rf_probs) 
随机森林的最终 ROC AUC 结果是 0.87,而单个决策树的结果是 0.67。如果我们看看训练分数,可以看到这两个模型都得到了 1.0 的 ROC AUC,同样这符合预期,因为我们已经为这些模型提供过训练数据的答案并且没有限制最大深度。但是,尽管随机森林过拟合了,但比起单个决策树,它仍能远远更好地泛化到测试数据上。
检视模型内部,可以看到单个决策树的最大深度为 55,共有 12327 个节点。随机森林中决策树的平均深度为 46,平均节点数为 13396。即使随机森林的平均节点数更大,它也能更好地泛化!
我们还可以绘制单个决策树(上)和随机森林(下)的 ROC 曲线。曲线越靠近左上角,则模型越好:
可以看到随机森林明显优于单个决策树。
我们还可以使用另一种模型诊断方法,即绘制测试预测结果的混淆矩阵(详见 Jupyter Notebook):
随机森林中的特征重要度是指在依据该特征分割的所有节点上基尼不纯度降低的总和。我们可以使用这一指标确定随机森林认为最重要的预测变量是什么。特征重要度可从训练后的随机森林中提取出来,并表示成 Pandas dataframe 的形式:
import
 pandas 
as
 pd


fi = pd.DataFrame({
feature
: list(train.columns), 

importance
: model.feature*importances*}). 

sort_values(
importance
, ascending = 
False
)


fi.head()


feature importance 

tDIFFWALKt0
.036200
tQLACTLM2t0
.030694
tEMPLOY1t 
0.024156
tDIFFALONt0
.022699
tUSEEQUIPt0
.016922
tDECIDEt 
0.016271
t_LMTSCL1t0
.013424
tINCOME2t 
0.011929
tCHCCOPD1t0
.011506
t_BMI5t 
0.011497
我们还可以使用特征重要度来进行特征选择,即移除重要度为 0 或较低的特征。
最后,我们可以可视化森林中的单个决策树。这时候我们就必须限定树的深度了,因为整个树非常大,难以转换成单张图像。我将最大深度设定为 6,得到了下面的图像。这仍然是一副很大的图!
希望这篇文章能为你提供信心,帮助你理解随机森林并开始在你自己的项目中使用它。随机森林是一种强大的机器学习模型,但这不应该妨碍我们理解它的工作方式!我们对一个模型的了解越多,我们就能越好地使用它以及解释它做预测的方式,这样其他人才会信任它!现在行动起来,用随机森林解决一些问题吧。
推荐阅读
继续阅读
阅读原文