算法描述
随机森林算法
决策树运行的每一步都涉及到对数据集中的最优**点(best split point
)进行贪婪选择(
greedy selection
)。
这个机制使得决策树在没有被剪枝的情况下易产生较高的方差。整合通过提取训练数据库中不同样本(某一问题的不同表现形式)构建的复合树及其生成的预测值能够稳定并降低这样的高方差。这种方法被称作引导**算法(bootstrap aggregating
),其简称
bagging
正好是装进口袋,袋子的意思,所以被称为「装袋算法」。该算法的局限在于,由于生成每一棵树的贪婪算法是相同的,那么有可能造成每棵树选取的**点(
split point
)相同或者极其相似,最终导致不同树之间的趋同(树与树相关联)。相应地,反过来说,这也使得其会产生相似的预测值,降低原本要求的方差。
我们可以采用限制特征的方法来创建不一样的决策树,使贪婪算法能够在建树的同时评估每一个**点。这就是随机森林算法(Random Forest algorithm
)。
与装袋算法一样,随机森林算法从训练集里撷取复合样本并训练。其不同之处在于,数据在每个**点处完全**并添加到相应的那棵决策树当中,且可以只考虑用于存储属性的某一固定子集。
对于分类问题,也就是本教程中我们将要探讨的问题,其被考虑用于**的属性数量被限定为小于输入特征的数量之**根。代码如下:
num_features_for_split = sqrt(total_input_features)
这个小更改会让生成的决策树各不相同(没有关联),从而使得到的预测值更加多样化。而多样的预测值组合往往会比一棵单一的决策树或者单一的装袋算法有更优的表现。
声纳数据集(Sonar dataset)
我们将在本教程里使用声纳数据集作为输入数据。这是一个描述声纳反射到不同物体表面后返回的不同数值的数据集。60
个输入变量表示声纳从不同角度返回的强度。这是一个二元分类问题(
binary classification problem
),要求模型能够区分出岩石和金属柱体的不同材质和形状,总共有
208
个观测样本。
该数据集非常易于理解——
每个变量都互有连续性且都在
0
到
1
的标准范围之间,便于数据处理。作为输出变量,字符串
’M’
表示金属矿物质,
’R’
表示岩石。二者需分别转换成整数
1
和
0
。
通过预测数据集(M
或者金属矿物质)中拥有最多观测值的类,零规则算法(
Zero Rule Algorithm
)可实现
53%
的精确度。
更多有关该数据集的内容可参见 UCI Machine Learning repository
:
https://archive.ics.uci.edu/ml/datasets/Connectionist+Bench+(Sonar,+Mines+vs.+Rocks)
免费下载该数据集,将其命名为 sonar.all-data.csv
,并存储到需要被操作的工作目录当中。
教程
此次教程分为两个步骤。
1.
**次数的计算。
2.
声纳数据集案例研究
这些步骤能让你了解为你自己的预测建模问题实现和应用随机森林算法的基础
**次数的计算
在决策树中,我们通过找到一些特定属性和属性的值来确定**点,这类特定属性需表现为其所需的成本是最低的。
分类问题的成本函数(cost function
)通常是基尼指数(
Gini index
),即计算由**点产生的数据组的纯度(
purity
)。对于这样二元分类的分类问题来说,指数为
0
表示绝对纯度,说明类值被完美地分为两组。
从一棵决策树中找到最佳**点需要在训练数据集中对每个输入变量的值做成本评估。
在装袋算法和随机森林中,这个过程是在训练集的样本上执行并替换(放回)的。因为随机森林对输入的数据要进行行和列的采样。对于行采样,采用有放回的方式,也就是说同一行也许会在样本中被选取和放入不止一次。
我们可以考虑创建一个可以自行输入属性的样本,而不是枚举所有输入属性的值以期找到获取成本最低的**点,从而对这个过程进行优化。
该输入属性样本可随机选取且没有替换过程,这就意味着在寻找最低成本**点的时候每个输入属性只需被选取一次。
如下的代码所示,函数 get_split()
实现了上述过程。它将一定数量的来自待评估数据的输入特征和一个数据集作为参数,该数据集可以是实际训练集里的样本。辅助函数
test_split()
用于通过候选的**点来分割数据集,函数
gini_index()
用于评估通过创建的行组(
groups of rows
)来确定的某一**点的成本。
以上我们可以看出,特征列表是通过随机选择特征索引生成的。通过枚举该特征列表,我们可将训练集中的特定值评估为符合条件的**点。
# Select the best split point for a dataset
def
get_split(dataset, n_features):
class_values = list(set(row[-1]
for row
in dataset))
b_index, b_value, b_score, b_groups = 999, 999, 999,
None
features = list()
while len(features) < n_features:
index = randrange(len(dataset[0])-1)
if index
not
in features:
features.append(index)
for index
in features:
for row
in dataset:
groups = test_split(index, row[index], dataset)
gini = gini_index(groups, class_values)
if gini < b_score:
b_index, b_value, b_score, b_groups = index, row[index], gini, groups
return {'index':b_index, 'value':b_value, 'groups':b_groups}
至此,我们知道该如何改造一棵用于随机森林算法的决策树。我们可将之与装袋算法结合运用到真实的数据集当中。
关于声纳数据集的案例研究
<