一、定义
CART(Classification and Regression Tree)即分类回归树算法。其决策树的生成就是递归的构建二叉决策树的过程。每次划分都把当前样本集划分为两个子样本集。对回归树用平方误差最小化准则,对分类树用基尼指数最小化准则,进行特征选择,生成二叉树。
二、分裂次数
假设某属性存在m个可取值,那么该属性作为分支属性时,生成两个分支的分裂方法共有 2 m − 1 − 1 \displaystyle 2^{m-1} -1 2m−1−1种。如果有n个属性,则分裂方法有 ( 2 m − 1 − 1 ) n \displaystyle \left( 2^{m-1} -1\right)^{n} (2m−1−1)n种。
三、CART分类树与回归树
1、CART分类树
1.1、分类树原理
(1)CART算法在分支时使用Gini系数作为树的生成方式。设
S
S
S为大小是n的样本集,其分类属性有m个不同的取值,用来定义m个不同分类
C
i
(
i
=
1
,
2
,
.
.
.
m
)
\displaystyle C_{i}(i=1,2,...m)
Ci(i=1,2,...m),则其Gini指数的计算公式为:
G
i
n
i
(
S
)
=
1
−
∑
i
=
1
m
(
∣
C
i
∣
S
)
\displaystyle Gini( S) \ =\ 1-\sum ^{m}_{i=1}\left(\frac{|C_{i} |}{S}\right)
Gini(S) = 1−i=1∑m(S∣Ci∣)
G
i
n
i
(
p
)
=
∑
k
=
1
k
p
k
(
1
−
p
k
)
=
1
−
∑
k
=
1
k
p
k
2
\displaystyle Gini( p) \ =\sum ^{k}_{k=1} p_{k}( 1-p_{k}) =1-\sum ^{k}_{k=1} p^{2}_{k}
Gini(p) =k=1∑kpk(1−pk)=1−k=1∑kpk2
其中,
S
S
S为样本总数量,
C
i
\displaystyle C_{i}
Ci为第
i
i
i分类里的样本数量。(在分类问题中,假设有K个类,样本点属于第k类的概率为
p
k
p_{k}
pk)
(2)CART算法中,针对样本集S,选取属性A作为分支属性,将样本S分类为A=a1的子样本S1,与其余也能根本组成的样本集S2,则在词情况下的
G
i
n
i
Gini
Gini系数为:如果样本集合D根据某个特征A被分割为D1,D2两个部分,那么在特征A的条件下,集合D的gini指数的定义为
G
i
n
i
(
S
∣
A
)
=
∣
S
1
∣
S
G
i
n
i
(
S
1
)
+
∣
S
2
∣
S
G
i
n
i
(
S
2
)
\displaystyle Gini( S|A) \ =\ \frac{|S_{1} |}{S} Gini( S_{1}) \ +\ \frac{|S_{2} |}{S} Gini( S_{2}) \ \
Gini(S∣A) = S∣S1∣Gini(S1) + S∣S2∣Gini(S2)
1.2、CART分类树的生成算法:
输入:训练数据集D,停止计算条件
输出:CART决策树
根据训练数据集,从根节点开始,递归的对每个节点进行一下操作,构建二叉决策树:
(1)设节点的训练数据集为S,计算现有也正对该数据集的基尼指数。此时,对每个特征A,对其每一个可能取值
a
i
\displaystyle a_{i}
ai,根据样本点
A
=
a
i
\displaystyle A=a_{i}
A=ai的测试为“是”或“否”,将S分割为S1和S2两部分,利用
G
i
n
i
(
S
∣
A
)
Gini( S|A)
Gini(S∣A)计算
A
=
a
i
\displaystyle A=a_{i}
A=ai时的基尼指数。
(2)在所有可能的特征A以及它们可能的切分点,选取基尼指数最小的特征及其对应的切分点作为最优特征与最优切分点,依最优特征与最优切分点,从现节点生成两个子节点,将训练数据根据特征分配到两个子节点中。
(3)对两个自建点递归调用(1)(2),知道满足停止条件
(4)生成CART决策树
算法的停止条件:节点中的样本个数小于预定阈值,或样本集的基尼指数小于预定阈值(样本基本属于同一类),或者没有更多特征。
1.3、CART分类树例子
样本与编码后样本:
解析:
首先计算各特征额基尼指数,选择最优特征及其最优切分点,分别以X[0]、X[1]、X[2]、X[3]表示年龄、有无工作、有无房子、信贷情况。先求X[0]、X[1]、X[2]、X[3]的基尼指数。如X[3]:??
1.4、CART分类树代码与决策树可视化
import numpy as np
import pandas as pd
import pydotplus
from sklearn import tree
from sklearn.model_selection import train_test_split
from graphviz import Source
from sklearn.preprocessing import LabelEncoder
data = pd.read_excel('cart_data.xlsx')
#对类别特征进行LabelEncoder编码
le = LabelEncoder()
for i in data.columns.values:
data[i] = le.fit_transform(data[i])
#确定训练样本和lable
X = data.drop(['类别'],axis=1)
y = data['类别']
#使用CART分类树构建树模型
clf = tree.DecisionTreeClassifier(criterion='gini',max_depth=4)
clf = clf.fit(X,y)
#画决策树
import os
os.environ["PATH"] += os.pathsep + 'C:/Users/Administrator/Anaconda3/Lib/graphviz-2.38/release/bin' #注意修改你的路径
graph = Source(tree.export_graphviz(clf,out_file=None))
graph.format = 'png'
graph.render('CART_tree',view=True)
#使用pydotplus
dot_data = tree.export_graphviz(clf,out_file=None)
graph = pydotplus.graph_from_dot_data(dot_data)
graph.write_png('entroy.png')
2、CART回归树
2.1、分类树原理
(1)遍历每一个特征
j
j
j,以及该特征的每个取值
s
s
s,计算每个特征和切分点
(
j
,
s
)
(j,s)
(j,s)的损失函数,选择最小损失函数,确定最优切分变量
j
j
j与切分点
s
s
s。求解最小平方误差((真实值-预测值)的平方)
m
i
n
j
,
s
[
m
i
n
c
1
∑
x
i
∈
R
1
(
j
,
s
)
(
y
i
−
c
1
)
2
+
m
i
n
c
2
∑
x
i
∈
R
2
(
j
,
s
)
(
y
i
−
c
2
)
2
]
\displaystyle min_{j,s}\left[ min_{c_{1}}\sum _{x_{i} \in R_{1}( j,s)}( y_{i} -c_{1})^{2} \ +\ min_{c_{2}}\sum _{x_{i} \in R_{2}( j,s)}( y_{i} -c_{2})^{2}\right]
minj,s⎣⎡minc1xi∈R1(j,s)∑(yi−c1)2 + minc2xi∈R2(j,s)∑(yi−c2)2⎦⎤
(2)用选定的对
(
j
,
s
)
(j,s)
(j,s),对区间进行划分并确定相应的输出值。
R
1
(
j
,
s
)
=
{
x
∣
x
(
j
)
⩽
s
}
,
R
2
(
j
,
s
)
=
{
x
∣
x
(
j
)
>
s
}
\displaystyle R_{1}( j,s) \ =\ \left\{x\ |\ x^{( j)} \ \leqslant \ s\right\} ,\ R_{2}( j,s) \ =\ \left\{x\ |\ x^{( j)} \ >\ s\right\}
R1(j,s) = {x ∣ x(j) ⩽ s}, R2(j,s) = {x ∣ x(j) > s}
c
m
∧
=
1
N
∑
x
i
∈
R
m
(
j
,
s
)
y
i
x
∈
R
m
,
m
=
1
,
2
\displaystyle c^{\land }_{m} \ =\ \frac{1}{N}\sum _{x_{i} \in R_{m}( j,s)} y_{i} \ \ \ \ \ \ \ x\in R_{m} \ ,m=1,2
cm∧ = N1xi∈Rm(j,s)∑yi x∈Rm ,m=1,2
(3)继续对两个子区域重复步骤1,知道满足停止条件
(4)遍历所有特征的所有切分点,就能找到最优的切分特征和切分点,最终得到一颗回归树。
2.2、CART回归树例子
训练数据中臂长、年龄、体重为特征变量X,身高为标签值Y。
1、首先将第一个特征的第一个值作为切割点(0.5),则划分的两个空间记为
R
1
,
R
2
R1,R2
R1,R2:
R
1
=
{
0.5
,
5
,
20
}
\displaystyle R1\ =\ \{0.5,5,20\}
R1 = {0.5,5,20}
R
2
=
{
(
0.7
,
7
,
30
)
,
(
0.9
,
21
,
70
)
}
\displaystyle R2\ =\ \{( 0.7,7,30) ,( 0.9,21,70)\}
R2 = {(0.7,7,30),(0.9,21,70)}
c
1
=
1.1
\displaystyle c1\ =\ 1.1
c1 = 1.1
c
2
=
1
2
(
1.3
+
1.7
)
=
1.5
\displaystyle c2\ =\ \frac{1}{2}( 1.3+1.7) =1.5
c2 = 21(1.3+1.7)=1.5
则平方误差为:
M
E
S
(
0.5
)
=
(
1.1
−
1.1
)
2
+
(
1.5
−
1.3
)
2
+
(
1.5
−
1.7
)
2
=
0.08
\displaystyle MES( 0.5) \ =\ ( 1.1-1.1)^{2} \ +\ ( 1.5-1.3)^{2} \ +\ ( 1.5-1.7)^{2} \ =\ 0.08
MES(0.5) = (1.1−1.1)2 + (1.5−1.3)2 + (1.5−1.7)2 = 0.08
2、首先将第一个特征的第二个值作为切割点(0.7),则划分的两个空间记为
R
1
,
R
2
R1,R2
R1,R2:
R
1
=
{
(
0.5
,
5
,
20
)
,
(
0.7
,
7
,
30
)
,
}
\displaystyle R1\ =\ \{(0.5,5,20),( 0.7,7,30) ,\}
R1 = {(0.5,5,20),(0.7,7,30),}
R
2
=
{
(
0.9
,
21
,
70
}
\displaystyle R2\ =\ \{(0.9,21,70\}
R2 = {(0.9,21,70}
c
1
=
1
2
(
1.1
+
1.3
)
=
1.2
\displaystyle c1\ =\ \frac{1}{2}(1.1 + 1.3) = 1.2
c1 = 21(1.1+1.3)=1.2
c
2
=
1.7
\displaystyle c2\ =1.7
c2 =1.7
则平方误差为:
M
E
S
(
0.7
)
=
0.2
+
0
=
0.02
\displaystyle MES( 0.7) \ =0.2 + 0 = 0.02
MES(0.7) =0.2+0=0.02
所以选取臂长=0.7作为切分点。同理对于年龄体重,采用同样的方法,遍历所有特征和特征取值,得到均方差最小的对
(
j
,
s
)
(j,s)
(j,s)。
j
j
j表示第
j
j
j个特征,
s
s
s表示第
j
j
j个特征的第
s
s
s个值。本例最佳切分点为0.7。
3、对于第二部的得到的
R
1
,
R
2
R1,R2
R1,R2,分别在计算最佳切分点,递归操作,过程同1-2步骤。
2.3、CART回归树代码与决策树可视化
import numpy as np
import pandas as pd
from sklearn import tree
from sklearn.model_selection import train_test_split
from graphviz import Source
import os
os.environ["PATH"] += os.pathsep + 'C:/Users/Administrator/Anaconda3/Lib/graphviz-2.38/release/bin' #注意修改你的路径
data = pd.read_csv('cart_re.csv',encoding='utf-8')
X = data[['臂长(m)', '年龄(岁)', '体重(kg)']]
y = data['身高(m)']
# 使用CART分类树构建树模型
clf = tree.DecisionTreeRegressor() #criterion='gini'报错
clf = clf.fit(X,y)
#画决策树
graph = Source(tree.export_graphviz(clf,out_file=None))
graph.format = 'png'
graph.render('CART_tree_re',view=True)