前言
上一篇我们了解了什么是决策树,知道了决策树构建的过程,同时聊了构建决策树的两种算法,那么我们今天来看下如何使用代码实现决策树的构建。
数据分析整体流程
数据分析一般是以下的分析流程
1、加载数据集
首先我们构建数据,提供训练数据集
序号,经济,身高,长相,其他优点,是否见面
1,有钱,低,不帅,有,否
2,有钱,低,不帅,无,否
3,一般,低,帅,有,是
4,没钱,低,帅,有,是
5,没钱,高,帅,有,否
6,有钱,一般,不帅,无,是
将数据进行加载,主要用来读取数据集,将其加载到内存
train_data = pd.read_csv('../source/data/survival_prediction/train_1.csv')
2、数据探索
# 数据探索
print(train_data.info())
print('-'*30)
print(train_data.describe())
print('-'*30)
print(train_data.describe(include=['O']))
print('-'*30)
print(train_data.head())
print('-'*30)
print(train_data.tail())
了解数据的特性,更好的帮助我们做数据清洗、特征选择。了解下以下几个方法
info() | 查看数据行数、列数、每列的数据类型、数据完整度 |
describe() | 了解数据表的统计情况:总数、平均值、标准差、最小值、最大值等 |
describe(include=[‘O’]) | 查看字符串类型(非数字)的整体情况 |
head | 查看前几行数据(默认是前 5 行) |
tail | 查看后几行数据(默认是最后 5 行) |
打印数据信息
如果存在数据确实或者数据异常,那么我们其实可以通过其他策略进行数据的修正。当前数据集比较完整。
3、特征选择
分析数据字段,通过数据集分析,除了序号不影响相亲结果,‘经济’, ‘身高’, ‘长相’, '其他优点‘都会影响到结果。因此定义如下:
features = ['经济', '身高', '长相', '其他优点'] #特征集字段
train_features = train_data[features] #训练数据
train_labels = train_data['是否见面'] #训练结果
在归类特征值时我们发现,存在一些特征字段是字符串的,这个不利于我们后期的运算,需要转成数值类型。
特征向量化
比如经济字段,有 有钱 和 没钱,一般三种取值。我们可以把它变成 经济=有钱、经济=一般和经济=没钱三个字段,并且每个值用0和1来表示。
其他枚举字段也同样处理。这种字段的变换我们称之为特征向量化
Python中使用DictVectorizer来对字段进行向量化
dvec=DictVectorizer(sparse=False)
train_features=dvec.fit_transform(train_features.to_dict(orient='record'))
print(dvec.feature_names_)
字段释义如下:
dtype:callable, 可选参数, 默认为float。特征值的类型,传递给Numpy.array或者Scipy.sparse矩阵构造器作为dtype参数。
separator: string, 可选参数, 默认为"="。当构造One-hot编码的特征值时要使用的分割字符串。分割传入字典数据的键与值的字符串,生成的字符串会作为特征矩阵的列名。
PS:One-Hot编码,又称为一位有效编码,主要是采用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候只有一位有效。
sparse: boolearn, 可选参数,默认为True。transform是否要使用scipy产生一个sparse矩阵。DictVectorizer的内部实现是将数据直接转换成sparse矩阵,如果sparse为False, 再把sparse矩阵转换成numpy.ndarray型数组。
sort:boolearn,可选参数,默认为True。在拟合时是否要多feature_names和vocabulary_进行排序。
打印后的特征列如下:
4、决策树模型训练
当数据清洗完成并且特征值也确定之后,那么就需要开始构建决策树了。Python中,可以使用sklearn 这个库进行构建决策树模型。
sklearn 是python中支持决策树模型的一个机器学习库,支持ID3 与 CART 决策树。使用方法如下:
# 构造 ID3 决策树
clf = DecisionTreeClassifier(criterion='entropy')
在构造 DecisionTreeClassifier 类时,其中有一个参数是 criterion,它决定了构造的分类树是采用 ID3 分类树,还是 CART 分类树,对应的取值分别是 entropy 或者 gini;
entropy: 基于信息熵,也就是 ID3 算法,实际结果与 C4.5 相差不大;
gini:默认参数,基于基尼系数。CART 算法是基于基尼系数做属性划分的,所以 criterion=gini 时,实际上执行的是 CART 算法。
DecisionTreeClassifier构造器其他参数说明
def __init__(self, *,
criterion="gini",
splitter="random",
max_depth=None,
min_samples_split=2,
min_samples_leaf=1,
min_weight_fraction_leaf=0.,
max_features="auto",
random_state=None,
max_leaf_nodes=None,
min_impurity_decrease=0.,
min_impurity_split=None,
class_weight=None,
ccp_alpha=0.0):
我们使用ID3算法,进行构建决策树
# 构造 ID3 决策树
clf = DecisionTreeClassifier(criterion='entropy')
决策树模型选择完毕后,传入需要训练的数据,以及输出的结果集
# 决策树训练
clf.fit(train_features, train_labels)
从而得到我们数据训练出的决策树模型。
5、决策树模型评估
决策树提供了 score 函数可以直接得到准确率,但是我们并不知道真实的预测结果,所以无法用预测值和真实的预测结果做比较。我们只能使用训练集中的数据进行模型评估,可以使用决策树自带的 score 函数计算下得到的结果
# 得到决策树准确率
acc_decision_tree = round(clf.score(train_features, train_labels),6)
print(u'score 准确率为 %.4lf' % acc_decision_tree)
得到输出结果: score 准确率为 1.0000
因为是通过训练模型的数据和训练模型的结果做的对比,所以分值比较高,但这个并不能代表决策树分类器的真实准确性。那么我们该如何对测试数据进行准确性校验呢?
模型预测和评估-K-Fold交叉验证
在机器学习建模过程中,通行的做法通常是将数据分为训练集和测试集。测试集是与训练独立的数据,完全不参与训练,用于最终模型的评估。在训练过程中,经常会出现过拟合的问题,就是模型可以很好的匹配训练数据,却不能很好在预测训练集外的数据。如果此时就使用测试数据来调整模型参数,就相当于在训练时已知部分测试数据的信息,会影响最终评估结果的准确性。通常的做法是在训练数据再中分出一部分做为验证(Validation)数据,用来评估模型的训练效果。
它将原始数据分成K组(K-Fold),将每个子集数据分别做一次验证集,其余的K-1组子集数据作为训练集,这样会得到K个模型。这K个模型分别在验证集中评估结果,最后的误差MSE(Mean Squared Error)加和平均就得到交叉验证误差。交叉验证有效利用了有限的数据,并且评估结果能够尽可能接近模型在测试集上的表现,可以做为模型优化的指标使用。
**交叉验证主要用于防止模型过于复杂而引起的过拟合,是一种评价训练数据的数据集泛化能力的统计方法。其基本思想是将原始数据进行划分,分成训练集和测试集,训练集用来对模型进行训练,测试集用来测试训练得到的模型,以此来作为模型的评价指标。
下面举一个具体的例子来说明K-Fold的过程,比如如下的数据
[0.1, 0.2, 0.3, 0.4, 0.5, 0.6]
分为K=3组后
Fold1: [0.5, 0.2] Fold2: [0.1, 0.3] Fold3: [0.4, 0.6]
交叉验证的时会使用如下三个模型,分别进行训练和测试,每个测试集误差MSE加和平均就得到了交叉验证的总评分
Model1: Trained on Fold1 + Fold2, Tested on Fold3
Model2: Trained on Fold2 + Fold3, Tested on Fold1
Model3: Trained on Fold1 + Fold3, Tested on Fold2
K折交叉验证原理
1、将数据集平均分割成 K 个等份;
2、使用 1 份数据作为测试数据,其余作为训练数据;
3、计算测试准确率;使用不同的测试集,
4、重复 2、3 步骤。
在 sklearn 的 model_selection 模型选择中提供了 cross_val_score 函数。用于我们进行交叉验证。
test_decision_tree = np.mean(cross_val_score(clf, train_features, train_labels, cv=3))
print(u'cross_val_score准确率为 %.4lf' % test_decision_tree)
下图可以看到,测试数据被分为3份进行验证,得到了3个结果,然后求平均值
得到结果为cross_val_score准确率为 0.3333。因为我们数据集比较少,因此差距还是比较大的。
6、决策树模型可视化
整个决策树模型虽然已经创建了,但对于我们来讲还是比较抽象的,那么我们如果想看到具体训练出来的决策树是什么样子的该怎么做呢?
可以通过安装Graphviz 插件进行决策树的可视化。
1、官网下载Graphviz :http😕/www.graphviz.org/download/
2、添加环境变量
Graphviz安装目录\bin
Graphviz安装目录\bin\dot.exe
3、python 编译环境添加graphviz库
4、重启电脑,这样就可以在程序中使用Graphviz了。
Python中,执行以下方法,即可将训练的决策树模型clf进行可视化
dot_data = tree.export_graphviz(clf, out_file=None)
graph = graphviz.Source(dot_data)
graph.view()
你可以看下输出的决策树的图形,主要含义如下:
比如类似 X[2]<=0.5 这种就是告诉你这个节点,选择的属性是X[2],阈值是0.5。当属性<=0.5的时候,决策进入到左子树,当>0.5的时候,决策进入到右子树。
entropy实际上代表了信息不纯度,这个数值越大,代表纯度越低。 samples代表的是这个节点的样本数,比如samples=6,就代表这个节点一般有6个样本。
value这个数组会告诉你这个样本集是如何分布的,比如value=[3,3],即6个样本,有3个为True,也就是X[7]<=0.5,还有3个样本为False,即这些样本的X[7]>0.5
然后继续上面的分裂过程,直到叶子节点,纯度越来越高,最终归为同一个类别时,纯度最高,entropy=0,此时样本都为同一个类别,也就是按照这条线路可以得到的最终分类结果。
所以你能看到:决策树的使用,就是从根节点开始,然后属性划分,当<=阈值时走左子树,>阈值时走右子树,最终在叶子节点可以得到分类的结果。你指的每个方框里的entropy, samples, vale都是中间的计算结果。