机器学习之决策树、随机森林
- 1 决策树
- 2 特征选择
- 3 信息增益
- 4 代码实现决策树算法
- 5 决策树优点缺点分析
- 6 随机森林
- 7 代码实现随机森林算法
- 8 随机森林总结
前言:主要介绍机器学习中的决策树和随机森林,通过举例用代码实现决策树和随机森林的算法。
1 决策树
- 决策树是一种基本的分类方法,当然也可以用于回归。我们一般只讨论用于分类的决策树。决策树模型呈树形结构。在分类问题中,表示基于特征对实例进行分类的过程,它可以认为是if-then规则的集合。在决策树的结构中,每一个实例都被一条路径或者一条规则所覆盖。通常决策树学习包括三个步骤:特征选择、决策树的生成和决策树的修剪。
- 优点:计算复杂度不高,输出结果易于理解,对中间值的缺失不敏感,可以处理逻辑回归等不能解决的非线性特征数据。
- 缺点:可能产生过度匹配问题。
- 适用数据类型:数值型和标称型。
2 特征选择
- 特征选择在于选取对训练数据具有分类能力的特征。这样可以提高决策树学习的效率,如果利用一个特征进行分类的结果与随机分类的结果没有很大差别,则称这个特征是没有分类能力的。经验上扔掉这样的特征对决策树学习的京都影响不大。通常特征选择的准则是信息增益,这是个数学概念。
- 通过一个例子来了解特征选择的过程。
通过所给的训练数据学习一个贷款申请的决策树,用以对贷款申请进行分类,即当新的客户提出贷款申请,根据申请人的特征利用决策树决定是否批准贷款申请。特征选择其实是决定用那个特征来划分特征空间。
按照年龄划分:
按照有无工作划分:
问题是究竟选择哪个特征更好些呢?那么直观上,如果一个特征具有更好的分类能力,是的各个自己在当前的条件下有最好的分类,那么就更应该选择这个特征。信息增益就能很好的表示这一直观的准则。这样得到的一棵决策树只用了两个特征就进行了判断:
3 信息增益
- 信息和消除不确定性是相联系的。所以决策树的过程其实是在寻找某一个特征对整个分类结果的不确定减少的过程。那么这样就有一个概念叫做信息增益(information gain)。
- 那么信息增益表示得知特征X的信息而是的类Y的信息的不确定性减少的程度,所以我们对于选择特征进行分类的时候,当然选择信息增益较大的特征,这样具有较强的分类能力。
- 特征A对训练数据集D的信息增益g(D,A),定义为集合D的经验熵H(D)与特征A给定条件下D的经验条件熵H(D|A)之差,即公式为:g(D,A)=H(D)−H(D∣A)
- 根据信息增益的准则的特征选择方法是:对于训练数据集D,计算其每个特征的信息增益,并比较它们的阿笑,选择信息增益最大的特征。
- 信息增益的计算:
4 代码实现决策树算法
还是以贷款的例子,转换成CSV数据,如下图所示:
ID,年龄,有工作,有自己的房子,信贷情况,类别
1,青年,否,否,一般,否
2,青年,否,否,好,否
3,青年,是,否,好,是
4,青年,是,是,一般,是
5,青年,否,否,一般,否
6,中年,否,否,一般,否
7,中年,否,否,好,否
8,中年,是,是,好,是
9,中年,否,是,非常好,是
10,中年,否,是,非常好,是
11,老年,否,是,非常好,是
12,老年,否,是,好,是
13,老年,是,否,好,是
14,老年,是,否,非常好,是
15,老年,否,否,一般,否
代码如下:
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction import DictVectorizer
import pandas as pd
from sklearn.tree import DecisionTreeClassifier, export_graphviz
def decision():
# 获取数据
titan = pd.read_csv("data3.csv")
# 处理数据,找出特征值和目标值
x = titan[['有工作', '有自己的房子','信贷情况']]
y = titan['类别']
# 分割数据集到训练集合测试集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25) # x_train, x_test是特征值 y_train, y_test是目标值
# 特征工程处理
dict = DictVectorizer(sparse=False)
x_train_ = dict.fit_transform(x_train.to_dict(orient="records"))
# print(dict.get_feature_names())
x_test_ = dict.transform(x_test.to_dict(orient="records"))
# 用决策树进行预测
dec = DecisionTreeClassifier()
dec.fit(x_train_, y_train)
y_predict = dec.predict(x_test_)
for work,house,debat,rel,pre in zip(x_test["有工作"],x_test["有自己的房子"],x_test["信贷情况"],y_test,y_predict):
if rel == pre:
print("有工作:"+work," 有自己的房子:",house," 信贷情况:",debat," 是否成功:",rel," 预测是否:",pre,"---预测成功")
else:
print("有工作:" + work, " 有自己的房子:", house, " 信贷情况:", debat, " 是否成功:", rel, " 预测是否:", pre, "---预测失败")
# 预测准确率
print("总体预测的准确率:", dec.score(x_test_, y_test))
# 导出决策树的结构
export_graphviz(dec, out_file="./tree.dot", feature_names=['信贷情况=一般', '信贷情况=好', '信贷情况=非常好', '有工作=否', '有工作=是', '有自己的房子=否', '有自己的房子=是'])
if __name__ == '__main__':
decision()
导出决策树:
5 决策树优点缺点分析
- 决策树的一些优点是:
简单的理解和解释。树木可视化。
需要很少的数据准备。其他技术通常需要数据归一化,需要创建虚拟变量,并删除空值。但请注意,此模块不支持缺少值。
使用树的成本(即,预测数据)在用于训练树的数据点的数量上是对数的。 - 决策树的缺点包括:
决策树学习者可以创建不能很好地推广数据的过于复杂的树。这被称为过拟合。修剪(目前不支持)的机制,设置叶节点所需的最小采样数或设置树的最大深度是避免此问题的必要条件。
决策树可能不稳定,因为数据的小变化可能会导致完全不同的树被生成。通过使用合奏中的决策树来减轻这个问题。
6 随机森林
- 在机器学习中,随机森林是一个包含多个决策树的分类器,并且其输出的类别是由个别树输出的类别的众数而定。利用相同的训练数搭建多个独立的分类模型,然后通过投票的方式,以少数服从多数的原则作出最终的分类决策。例如, 如果你训练了5个树, 其中有4个树的结果是True, 1个数的结果是False, 那么最终结果会是True.
- 在前面的决策当中我们提到,一个标准的决策树会根据每维特征对预测结果的影响程度进行排序,进而决定不同的特征从上至下构建分裂节点的顺序,如此以来,所有在随机森林中的决策树都会受这一策略影响而构建的完全一致,从而丧失的多样性。所以在随机森林分类器的构建过程中,每一棵决策树都会放弃这一固定的排序算法,转而随机选取特征。
- 学习算法
根据下列算法而建造每棵树:
1)用N来表示训练用例(样本)的个数,M表示特征数目。
2)输入特征数目m,用于确定决策树上一个节点的决策结果;其中m应远小于M。
3)从N个训练用例(样本)中以有放回抽样的方式,取样N次,形成一个训练集(即bootstrap取样),并用未抽到的用例(样本)作预测,评估其误差。
4)对于每一个节点,随机选择m个特征,决策树上每个节点的决定都是基于这些特征确定的。根据这m个特征,计算其最佳的分裂方式。
7 代码实现随机森林算法
代码如下(还是以贷款为例):
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.feature_extraction import DictVectorizer
from sklearn.ensemble import RandomForestClassifier
import pandas as pd
def decision():
# 获取数据
titan = pd.read_csv("data3.csv")
# 处理数据,找出特征值和目标值
x = titan[['有工作', '有自己的房子', '信贷情况']]
y = titan['类别']
# 分割数据集到训练集合测试集
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25) # x_train, x_test是特征值 y_train, y_test是目标值
# 特征工程处理
dict = DictVectorizer(sparse=False)
x_train_ = dict.fit_transform(x_train.to_dict(orient="records"))
print(dict.get_feature_names())
x_test_ = dict.transform(x_test.to_dict(orient="records"))
# 随机森林进行预测 (超参数调优)
rf = RandomForestClassifier(n_jobs=-1)
param = {"n_estimators": [120, 200, 300, 500, 800, 1200], "max_depth": [5, 8, 15, 25, 30]}
# 网格搜索与交叉验证
gc = GridSearchCV(rf, param_grid=param, cv=2)
gc.fit(x_train_, y_train)
y_predict = gc.predict(x_test_)
for work, house, debat, rel, pre in zip(x_test["有工作"], x_test["有自己的房子"], x_test["信贷情况"], y_test, y_predict):
if rel == pre:
print("有工作:" + work, " 有自己的房子:", house, " 信贷情况:", debat, " 是否成功:", rel, " 预测是否:", pre, "---预测成功")
else:
print("有工作:" + work, " 有自己的房子:", house, " 信贷情况:", debat, " 是否成功:", rel, " 预测是否:", pre, "---预测失败")
# 预测准确率
print("总体预测的准确率:", gc.score(x_test_, y_test))
print("查看选择的参数模型:", gc.best_params_)
if __name__ == '__main__':
decision()
运行截图:
8 随机森林总结
- 在当前所有算法中,具有极好的准确率
- 能够有效地运行在大数据集上
- 能够处理具有高维特征的输入样本,而且不需要降维
- 能够评估各个特征在分类问题上的重要性
- 对于缺省值问题也能够获得很好得结果