决策树是一种非常成熟的算法,它是一种自上而下,对样本数据进行树形分类的过程,由结点和有向边组成。结点分为内部结点和叶结点,其中每个内部结点表示一个特征或属性,叶节点表示类别。从顶部根节点开始,所有样本聚在一起。经过根节点的划分,样本被分到不同的子节点中。再根据子节点的特征进一步划分,直至所有样本都被归到某一类别(即叶节点)中。
也可以把它视作一系列的决策或回答问题的过程,最常见的决策树算法是ID3、C4.5、CART
。
特征选择:从训练数据的特征中选择一个特征作为当前节点的分裂标准(特征选择的标准不同产生了不同的特征决策树算法)。
决策树生成:根据所选特征评估标准,从上至下递归地生成子节点,直到数据集不可分则停止决策树停止生长。
剪枝:决策树容易过拟合,需要剪枝来缩小树的结构和规模(包括预剪枝和后剪枝)。
决策树的生成是一个递归的过程,在决策树的基本算法中,有三种情况会导致递归返回:
- 当前节点包含的样本全属于同一类别,无需划分;
- 当前属性集为空,或是所有样本在所有属性上取值相同,无法划分;
- 当前节点包含的样本集为空,不能划分。
I D 3 ID3 ID3 算法以信息论为基础,以信息熵和信息增益为衡量标准,从而实现对数据的归纳分类。其建立在奥卡姆剃刀的基础上:越是小型的决策树越优于大的决策树( b e s i m p l e be \; simple besimple简单理论)。
I D 3 ID3 ID3 算法的核心思想:以信息增益度量属性选择,选择分裂后信息增益最大的属性进行分裂。
A l g o r i t h m : Algorithm: Algorithm:
1、初始化属性集合和数据集合。
2、计算数据集合信息熵 S S S 和所有属性的信息熵,选择信息增益最大的属性作为当前决策节点。
3、更新数据集合和属性集合(删除掉上一步中使用的属性,并按照属性值来划分不同分支的数据集合)。
4、依次对每种取值情况下的子集重复第二步。
5、若子集只包含单一属性,则为分支为叶子节点,根据其属性值标记。
6、完成所有属性集合的划分。
信息熵,是用来衡量一个随机变量出现的期望值。如果信息的不确定性越大,熵的值也就越大,出现的各种情况也就越多。
例:如果确定一件事情的发生概率为100%,我们就认为这件事的信息量为0(既然确定了,自然就没有未知的信息量了)。
信息熵与事件的概率分布有关,概率分布越均匀,信息熵越大。当所有概率均等的情况下,信息熵最大。
对于样本集合 D D D ,类别数为 K K K,数据集 D D D 的经验熵表示为
H ( D ) = − ∑ k = 1 K ∣ C k ∣ ∣ D ∣ log 2 ∣ C k ∣ ∣ D ∣ (1) H(D) = -\sum\limits^K_{k=1}\frac{|C_k|}{|D|}\log_2\frac{|C_k|}{|D|} \tag{1} H(D)=−k=1∑K∣D∣∣Ck∣log2∣D∣∣Ck∣(1)
其中 C k C_k Ck 是样本集合 D D D 中属于第 k k k 类的样本子集, ∣ C k ∣ |C_k| ∣Ck∣ 表示该子集的元素个数, ∣ D ∣ |D| ∣D∣ 表示样本集合的元素个数。
然后计算某个特征 A A A 对于数据集 D D D 的经验条件熵 H ( D ∣ A ) H(D | A) H(D∣A) 为:
H ( D ∣ A ) = ∑ i = 1 n D i D H ( D i ) = ∑ i = 1 n D i D ( − ∑ k = 1 K ∣ D i k ∣ ∣ D ∣ log 2 ∣ D i k ∣ ∣ D ∣ ) (2) H(D|\;A) = \sum\limits^{n}_{i=1}\frac{D_i}{D}H(D_i) = \sum\limits^n_{i=1}\frac{D_i}{D}(-\sum\limits^K_{k=1}\frac{|D_{ik}|}{|D|}\log_2\frac{|D_{ik}|}{|D|}) \tag{2} H(D∣A)=i=1∑nDDiH(Di)=i=1∑nDDi(−k=1∑K∣D∣∣Dik∣log2∣D∣∣Dik∣)(2)
信息增益 ( I n f o r m a t i o n G a i n ) (Information \; Gain) (InformationGain): 用来衡量特征区分样本的能力,特征的信息增益越大,以该特征为节点建立的树就越简洁。因此在 I D 3 ID3 ID3中具有最高信息增益率的属性会被作为分类属性。于是信息增益可以表示为两者之差,可得:
I G ( X ) = H ( c ) − H ( c ∣ X ) = − ∑ i = 1 n p ( c i ) log 2 p ( c i ) + ∑ i = 1 n p ( x = x i ) H ( c ∣ x = x 1 ) p ( i ) = ∣ C i D ∣ ∣ D ∣ (3) IG(X) = H(c) - H(c|X) = -\sum\limits^n_{i=1}p(c_i)\log_2p(c_i) + \sum\limits^n_{i=1}p(x=x_i)H(c|x = x_1) \\ p(i) = \frac{|C_{iD}|}{|D|} \tag{3} IG(X)=H(c)−H(c∣X)=−i=1∑np(ci)log2p(ci)+i=1∑np(x=xi)H(c∣x=x1)p(i)=∣D∣∣CiD∣(3)
以 《百面机器学习》 中的示例为例:
年龄 | 长相 | 工资 | 写代码 | 类别 | |
---|---|---|---|---|---|
A | 老 | 帅 | 高 | 不会 | 不见 |
B | 年轻 | 一般 | 中等 | 会 | 见 |
C | 年轻 | 丑 | 高 | 不会 | 不见 |
D | 年轻 | 一般 | 高 | 会 | 见 |
E | 年轻 | 一般 | 低 | 不会 | 不见 |
在这个问题中:
H ( D ) = 3 5 log 2 3 5 − 2 5 log 2 2 5 = 0.971 (4) H(D) = \frac35\log_2\frac35 - \frac25\log_2\frac25 = 0.971 \tag{4} H(D)=53log253−52log252=0.971(4)
根据 式 ( 2 ) 式(2) 式(2) 可计算出四个分支节点的信息熵为:
H ( D ∣ 年 龄 ) = 1 5 ( 老 ) + 4 5 ( 年 轻 ) = 1 5 ( − 0 ) + 4 5 ( − 2 4 log 2 2 4 − 2 4 log 2 24 ) = 0.8 H ( D ∣ 长 相 ) = 1 5 H ( 帅 ) + 3 5 H ( 一 般 ) + 1 5 H ( 丑 ) = 0 + 3 5 ( − 2 3 log 2 2 3 − 1 3 log 2 1 3 ) + 0 = 0.551 H ( D ∣ 工 资 ) = 3 5 H ( 高 ) + 1 5 H ( 中 等 ) + 1 5 H ( 低 ) = 3 5 ( − 2 3 log 2 2 3 − 1 3 log 2 1 3 ) + 0 + 0 = 0.551 H ( D ∣ 写 代 码 ) = 3 5 H ( 不 会 ) + 2 5 H ( 会 ) = 3 5 ( 0 ) + 2 5 ( 0 ) = 0 (5) \begin{aligned} H(D|\; 年龄) &= \frac15(老) + \frac45(年轻) \\ &=\frac15(-0) + \frac45(-\frac24\log_2\frac24 - \frac24\log_224) = 0.8 \\ H(D|\; 长相) &= \frac15H(帅) + \frac35H(一般) + \frac15H(丑) \\ &= 0 + \frac35(-\frac23\log_2\frac23 - \frac13\log_2\frac13) + 0 = 0.551 \\ H(D|\; 工资) &= \frac35H(高) + \frac15H(中等) + \frac15H(低) \\ &= \frac35(-\frac23\log_2\frac23 - \frac13\log_2\frac13) + 0 + 0 = 0.551 \\ H(D|\; 写代码) &= \frac35H(不会) + \frac25H(会) \\ &= \frac35(0) + \frac25(0) = 0 \end{aligned} \tag{5} H(D∣年龄)H(D∣长相)H(D∣工资)H(D∣写代码)=51(老)+54(年轻)=51(−0)+54(−42log242−42log224)=0.8=51H(帅)+53H(一般)+51H(丑)=0+53(−32log232−31log231)+0=0.551=53H(高)+51H(中等)+51H(低)=53(−32log232−31log231)+0+0=0.551=53H(不会)+52H(会)=53(0)+52(0)=0(5)
综合 公 式 ( 5 ) 公式(5) 公式(5) 和 公 式 ( 3 ) 公式(3) 公式(3) ,可得各个特征的信息增益为:
I G ( D , 年 龄 ) = 0.171 I G ( D , 长 相 ) = 0.42 I G ( D , 工 资 ) = 0.42 I G ( D , 写 代 码 ) = 0.971 IG(D, 年龄) = 0.171 \\ IG(D, 长相) = 0.42 \\ IG(D, 工资) = 0.42 \\ IG(D, 写代码) = 0.971 IG(D,年龄)=0.171IG(D,长相)=0.42IG(D,工资)=0.42IG(D,写代码)=0.971
显然,特征“写代码”的信息增益最大,所有的样本根据此特征,可以直接被分到叶节点(即见或不见)中,完成决策树生长。当然,在实际应用中,决策树往往不能通过一个特征就完成构建,需要在经验熵非0类别中继续生长。
优点:
缺点:
可能会产生过度匹配的问题(决策树过深,容易导致过拟合,泛华能力差,因此需要剪枝);
信息缺失时处理起来比较困难,忽略数据集中属性的相关性;
信息增益来度量会偏向于取值较多的属性(有缺失值的会受影响)作为分类属性。
I D 3 ID3 ID3 算法属性只能是离散的,当然属性值可以是连续的数值型,但是需要对这些数据进行预处理,变为离散型的,才可以运用 I D 3 ID3 ID3 算法, C 4.5 C4.5 C4.5 是继承了 I D 3 ID3 ID3 算法的优点,并在此基础上做出改进的一个算法,它可以处理连续数据。
改进1:用信息增益率代替信息增益来选择属性,克服了用信息增益选择属性时偏向选择取值多的属性不足:
g r = H ( c ) − H ( c ∣ X ) H ( X ) (6) g_r = \frac{H(c) - H(c | X)}{H(X)} \tag{6} gr=H(X)H(c)−H(c∣X)(6)
改进2:能够完成对连续值属性的离散化处理。
改进3:能处理属性值缺失的情况。
改进4:在决策树构造完成之后进行剪枝。
特征 A A A 对于数据集 D D D 的信息增益比定义为:
g R ( D , A ) = I G ( G , A ) H A ( D ) (7) g_R(D, A) = \frac{IG(G, A)}{H_A(D)} \tag{7} gR(D,A)=HA(D)IG(G,A)(7)
其中
H A ( D ) = − ∑ i = 1 n ∣ D i ∣ ∣ D ∣ log 2 D i D (8) H_A(D) = -\sum\limits^n_{i=1}\frac{|D_i|}{|D|} \log_2\frac{D_i}{D} \tag{8} HA(D)=−i=1∑n∣D∣∣Di∣log2DDi(8)
根据 公 式 ( 8 ) 公式(8) 公式(8) 求解上述问题,可以得出
H 年 龄 ( D ) = − 1 5 log 2 1 5 − 4 5 log 2 4 5 = 0.722 H 长 相 ( D ) = − 1 5 log 2 1 5 − 3 5 log 2 3 5 − 1 5 log 2 1 5 = 1.371 H 工 资 ( D ) = − 3 5 log 2 3 5 − 1 5 log 2 1 5 − 1 5 log 2 1 5 = 1.371 H 写 代 码 ( D ) = − 3 5 log 2 3 5 − 2 5 log 2 2 5 = 0.971 (9) \begin{aligned} H_{年龄}(D) &= -\frac15\log_2\frac15 - \frac45\log_2\frac45 &= 0.722 \\ H_{长相}(D) &= -\frac15\log_2\frac15 - \frac35\log_2\frac35 - \frac15\log2\frac15 &= 1.371 \\ H_{工资}(D) &= -\frac35\log_2\frac35 - \frac15\log_2\frac15 - \frac15\log2\frac15 &= 1.371 \\ H_{写代码}(D) &= -\frac35\log_2\frac35 - \frac25\log_2\frac25 &= 0.971 \end{aligned} \tag{9} H年龄(D)H长相(D)H工资(D)H写代码(D)=−51log251−54log254=−51log251−53log253−51log251=−53log253−51log251−51log251=−53log253−52log252=0.722=1.371=1.371=0.971(9)
根据 公 式 ( 7 ) 公式(7) 公式(7) 可以算出各个特征的信息增益比为
g R ( D , 年 龄 ) = 0.236 , g R ( D , 长 相 ) = 0.402 g R ( D , 工 资 ) = 0.402 , g R ( D , 写 代 码 ) = 1 g_R(D, 年龄) = 0.236, \qquad g_R(D, 长相) = 0.402 \\ g_R(D, 工资) = 0.402, \qquad g_R(D, 写代码) = 1 gR(D,年龄)=0.236,gR(D,长相)=0.402gR(D,工资)=0.402,gR(D,写代码)=1
信息增益比最大的仍是特征写代码,但通过信息增益比,特征年龄对应的指标上升了,而特征“长相”和特征“工资”却有所下降。
对于离散型属性描述, C 4.5 C4.5 C4.5 的处理方法与 I D 3 ID3 ID3 相同,按照该属性本身的取值个数进行计算;按照属性值大小从小到大排序,取每对相邻值的重点作为可能的分裂点 s p l i t _ p o i n t split\_point split_point。假设一连续值属性共有 N N N 个不同的属性,则可找到 N − 1 N-1 N−1 个可能的分裂点。
例如:对于连续型属性描述 A c A_c Ac, 假设在某个节点上的数据集数量为 t o t a l total total , C 4.5 C4.5 C4.5 将作以下处理:
将该节点的所有数据样本按照连续型描述属性的具体数值,由小到大进行排序,得到属性值的取值序列 { A 1 , A 2 , … , A t o t a l } \{A_1, A_2,…,A_total\} {A1,A2,…,Atotal}。
在取值序列中生成 t o t a l − 1 total-1 total−1个分割点。第 i ( 0 < i < t o t a l i(0i(0<i<total个分割点的取值设置为 V i = ( A i + A ( i + 1 ) ) / 2 V_i=(A_i+A_(i+1))/2 Vi=(Ai+A(i+1))/2 , 它可以将该节点上的数据集划分为两个子集。
从 t o t a l − 1 total-1 total−1个分割点钟选择最佳分割点。 C 4.5 C4.5 C4.5 对于每一个分割点划分数据集的方式是,计算它的信息增益比,并且从中选择信息增益比最大的分割点来划分数据集。
I D 3 ID3 ID3 决策树算法增长树的每一个分支的深度,直到恰好能对训练样例比较完美地分类。
实际应用中,当训练样本中有噪声或训练样例的数量太少以至于不能产生目标函数的有代表性的采样时,该策略可能会遇到困难。
在以上情况发生时,这个简单的算法产生的树会过度拟合训练样例 (过度拟合: O v e r f i t t i n g Over \; fitting Overfitting)。
过度拟合产生的原因:
剪枝:是决策树后期处理的重要步骤,也被视为必不可少的一个步骤。其根本目的就是为了去掉一些不必要的节点使得决策树模型具有更好的泛化能力,以解决过拟合问题。
决策树的剪枝有两中主要方法:
预剪枝:如果我们预先设定树的深度为 3 3 3 ,则第四层树不会被保留 (决策树“是否会写代码”层会被删除)。
- 当树到达一定的深度时,停止树的生长;
- 当到达当前结点的样本数量小于某个阈值的时候,停止树的生长;
- 计算每次分裂对测试集的准确度提升,当小于某个阈值时,不再继续扩展。
预剪枝具有思想直接、算法简单、效率高等特点,适合解决大规模问题。但如何准确的估计何时停止树的生长(即上述的深度或阈值),针对不同问题会有很大差别,需要一定的经验判断。且预剪枝具有一定的局限性,有欠拟合的风险,虽然当前的划分会导致测试集准确率降低,但在之后的划分中,准确率可能会显著上升。
后剪枝:是由完全生长完的树剪去子树。
常见的后剪枝方法包括 错误率降低剪枝( R E P REP REP)、悲观剪枝( P E P PEP PEP)、代价复杂剪枝( C C P CCP CCP)、最小误差剪枝( M E P MEP MEP)、 C V P CVP CVP、 O P P OPP OPP 等方法。
其本质都是在测试集上定义损失函数 C C C,我们的目标是通过剪枝使得在测试集上 C C C 的值下降。例如通过剪枝使在测试集上误差率降低。
自底向上的遍历每一个非叶节点(除了根节点),将当前的非叶节点从树中减去,其下所有的叶节点合并成一个节点,代替原来被剪掉的节点。
计算剪去节点前后的损失函数,如果剪去节点之后损失函数变小了,则说明该节点是可以剪去的,并将其剪去;如果发现损失函数并没有减少,说明该节点不可剪去,则将树还原成未剪去之前的状态。
重复上述过程,直到所有的非叶节点(除了根节点)都被尝试了。
CART( C l a s s i f c a t i o n A n d R e g r e s s i o n T r e e Classifcation \; And \; Regression \;Tree ClassifcationAndRegressionTree) 分类回归树,是在 I D 3 ID3 ID3 的基础上 进行优化的决策树,它既是分类树,也是回归树,当 C A R T CART CART 是分类树时,采用 G I N I GINI GINI 值作为节点分裂的依据;当 C A R T CART CART 是回归树时,采用样本的最小方差作为节点分裂的依据。同时,每一颗 C A R T CART CART 树都是一颗 二叉树(学过数据结构的应该不陌生)。
G I N I GINI GINI 的计算公式为:
G I N I = 1 − ∑ i = I p i 2 (10) GINI = 1 - \sum\limits_{i=I}p_i^2 \tag{10} GINI=1−i=I∑pi2(10)
节点越不纯, G I N I GINI GINI 值越大,以二分类为例,如果节点的所有数据只有一个类别,则:
G I N I = 1 − ∑ i = I p i 2 = 0 GINI = 1 - \sum\limits_{i=I}p_i^2 =0 GINI=1−i=I∑pi2=0
如果两类数量相同,则:
G I N I = 1 − ∑ i = I p i 2 = 1 2 GINI=1 - \sum_{i=I}p_i^2 =\frac12 GINI=1−i=I∑pi2=21
回归树则是采用样本方差衡量节点纯度,节点越不纯,节点分类或者预测的效果就越差。
回归方差计算公式:
σ = ∑ i = I ( x i − μ ) 2 = ∑ i = I x i 2 − n μ 2 (11) \sigma= \sqrt{\sum\limits_{i=I}(x_i - \mu)^2} = \sqrt{\sum\limits_{i=I}x_i^2 - n\mu^2} \tag{11} σ=i=I∑(xi−μ)2=i=I∑xi2−nμ2(11)
如果两类数量相同,则方差越大,表示该节点的数据越分散,预测的效果就越差。
如果一个节点的所有数据都相同,那么方差就为 0 0 0 ,此时可以很肯定得认为该节点的输出值;如果节点的数据相差很大,那么输出的值有很大的可能与实际值相差较大。
因此,无论是分类树还是回归树,CART都要选择使子节点的GINI值或者回归方差最小的属性作为分裂的方案。
最小化分类树:
G a i n = ∑ i ∈ I p i G i n i i (12) Gain= \sum\limits_{i\in I}p_i Gini_i \tag{12} Gain=i∈I∑piGinii(12)
最小化回归树:
G a i n = ∑ i ∈ I σ i (13) Gain = \sum\limits_{i\in I}\sigma_i \tag{13} Gain=i∈I∑σi(13)
C A R T CART CART 采用 C C P CCP CCP(代价复杂度)剪枝方法。
代价复杂度选择节点表面误差率增益值最小的非叶子节点,删除该非叶子节点的左右子节点。
令决策树的非叶子节点为 T 1 , T 2 , T 3 , … . . , T n {T_1, T_2, T_3,….., T_n} T1,T2,T3,…..,Tn
表面误差率增益值的计算公式:
α R ( t ) − R ( T ) N ( T ) − 1 (14) \alpha \frac{R(t)−R(T)}{N(T)}−1 \tag{14} αN(T)R(t)−R(T)−1(14)
其中 R ( t ) R(t) R(t) 表示以t为根节点的误差代价,即判断t节点要不要被剪掉:
R ( T ) R(T) R(T) 表示以t为根节点的叶子节点误差代价:
R ( T ) = ∑ i m r i ( t ) . p i ( t ) (15) R(T) = \sum\limits_i^m r_i(t).p_i(t) \tag{15} R(T)=i∑mri(t).pi(t)(15)
其中 r i ( t ) r_i(t) ri(t) 为子节点的错误率, p i ( t ) p_i(t) pi(t) 表示节点i的数据节点占比。
I D 3 ID3 ID3: I D 3 ID3 ID3决策树可以有多个分支,但是不能处理特征值为连续的情况。在 I D 3 ID3 ID3 中,每次根据“最大信息增益”选取当前最佳的特征来分割数据,并按照该特征的所有取值来切分,也就是说如果一个特征有 4 种取值,数据将被切分 4 份,一旦按某特征切分后,该特征在之后的算法执行中,将不再起作用,所以有观点认为这种切分方式过于迅速。
C 4.5 C4.5 C4.5 : 针对 I D 3 ID3 ID3 采用的信息增益度量存在一个缺点,它一般会优先选择有较多属性值的特征,因为属性值多的特征会有相对较大的信息增益。 C 4.5 C4.5 C4.5 中是用信息增益比率(gain ratio)来作为选择分支的准则。信息增益比率通过引入一个被称作分裂信息 ( S p l i t i n f o r m a t i o n (Split \; information (Splitinformation)的项来惩罚取值较多的 F e a t u r e Feature Feature ,在候选属性中选择基尼系数最小的属性作为最优划分属性。除此之外, C 4.5 C4.5 C4.5 还弥补了 I D 3 ID3 ID3 中不能处理特征属性值连续的问题。
C A R T CART CART : 分类回归树。 C A R T CART CART分类时,使用基尼指数 ( G i n i ) (Gini) (Gini) 来选择最好的数据分割的特征, g i n i gini gini 描述的是纯度,与信息熵的含义相似。 C A R T CART CART 中每一次迭代都会降低 G I N I GINI GINI 系数。当 C A R T CART CART 是分类树时,采用 G I N I GINI GINI 值作为节点分裂的依据;当 C A R T CART CART 是回归树时,采用样本的最小方差作为节点分裂的依据。
今年华数杯 C 题是预测购车意向,数据以调查问卷的形式呈现,而调查问卷则是一种很典型的决策过程,例如通过问卷中出现的单身
、未婚独居
等特征可以明显推出此人无子女,而调查问卷中填写此类答案的人群,在子女个数选项中缺失率超过了百分之八十,同时,子女选项中没有出现0,因此可以推断出子女选项中的0项由于某种原因缺失了,另外百分之十几则可以判作异常值。
填充之后,我们就可以根据 B5、B7
的决策过程来平滑 B6
的异常值了
(决策树不仅可以用来分类,也可以用来回归,做特征选择,填充缺失值、平滑异常值等,是一种非常强大且基础的算法,关于这些用法可以参考我的过往文章)
ps: 源码没保存,这是从本人论文上的部分关于决策树的代码,仅供参考。
group = data.groupBy('B6')
g1 = group.get_group(1)
for i in range(4):
g = group.get_group(i + 1)
print(i + 1, g.query('B7 != 0').shape[0])
# In[27]:
g1 = group.get_group(1) g1.query('B7 != 0')
# In[28]:
g1.query('B7 != 0')
# In[29]:
g2 = group.get_group(2)
g2.query('B7 != 0')
# In[30]:
g3 = group.get_group(3)
g3.query('B7 != 0')
# In[31]:
g4 = group.get_group(4) g4.query('B7 != 0')
# In[32]:
g5 = group.get_group(5)
g5.query('B7 == 0')
# In[33]:
g6 = group.get_group(6)
dataset = pd.concat([g1, g2, g3, g4, g5, g6], axis=0) dataset
# In[34]:
noise = pd.concat([g1.query('B7 != 0'), g2.query('B7 !=0'), g3.query('B7 != 0'), g4.query('B7 != 0'), g5.query('B7 == 0')], axis=0)
normal = pd.merge(dataset, noise, how='left', indicator=True).query("_merge=='left_only'").drop('_merge', 1)
# In[35]:
X, y = normal[['B5', 'B7']].values, normal['B6'].values.reshape(-1, )
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
# In[36]:
ds = DecisionTreeClassifier(criterion='gini')
ds.fit(X_train, y_train)
score = ds.score(X_test, y_test)
, noise, how=‘left’, indicator=True).query("_merge==‘left_only’").drop(’_merge’, 1)
X, y = normal[[‘B5’, ‘B7’]].values, normal[‘B6’].values.reshape(-1, )
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
ds = DecisionTreeClassifier(criterion=‘gini’)
ds.fit(X_train, y_train)
score = ds.score(X_test, y_test)