文章目录
算法原理分析
什么是决策树
分类决策树模型是一种基于特征对实例进行分类的树形结构。决策树可以转化成if-then规则的集合,也可以看作是定义在特征空间划分上的条件概率分布
决策树如何学习
决策树学习旨在创建一个与训练数据拟合很好,并且复杂度小的决策树,由于直接从所有可能的决策树中找到最有的决策树是NP完全问题,于是现实中我们采用启发式算法来学习次优的决策树
决策树的学习算法包括三部分:特征选择,树的生成和树的剪枝,常用算法有ID3,C4.5,CART
假定给定训练数据集 D = ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x n , y n ) D={(x_1,y_1),(x_2,y_2),...,(x_n,y_n)} D=(x1,y1),(x2,y2),...,(xn,yn)
名词解释
熵:是随机变量不确定性地度量
熵越大,随机变量越不确定
条件熵H(X|Y):表示已知随机变量X的条件下随机变量Y地不确定性
而H(D|A)表示在特征A给定地条件下对数据集D进行分类地不确定性
信息增益:信息增益越大表示使用特征A来划分所得到的”纯度提升越大“
决策树的特征选择
特征选择的目的在于选取能够对训练数据进行分类的特征。特征选择的关键是其准则,常用的准则如下
- 样本集合D对特征A的信息增益(ID3)
- g ( D , A ) = H ( D ) − H ( A ) g(D,A)=H(D)-H(A) g(D,A)=H(D)−H(A)
- H ( D ) = − ∑ k = 1 K ∣ C k ∣ ∣ D ∣ l o g 2 ∣ C k ∣ ∣ D ∣ H(D)=-\sum^{K}_{k=1}\frac{|C_k|}{|D|}log_2\frac{|C_k|}{|D|} H(D)=−∑k=1K∣D∣∣Ck∣log2∣D∣∣Ck∣
-
H
(
D
∣
A
)
=
∑
i
=
1
n
∣
D
i
∣
∣
D
∣
H
(
D
i
)
H(D|A)=\sum^{n}_{i=1}\frac{|D_i|}{|D|}H(D_i)
H(D∣A)=∑i=1n∣D∣∣Di∣H(Di)
其中, 𝐻(𝐷) 是数据集 𝐷 的熵, 𝐻(𝐷𝑖) 是数据集 𝐷𝑖 的熵, 𝐻(𝐷|𝐴) 是数据集 𝐷 对特征 𝐴 的条件熵。 𝐷𝑖 是 𝐷 中特征 𝐴 取第 𝑖 个值的样本子集, 𝐶𝑘 是 𝐷 中属于第 𝑘 类的样本子集。 𝑛 是特征 𝐴 取 值的个数, 𝐾 是类的个数。
- 样本集合D对特征A的信息增益比(C4.5)
-
g
R
(
D
,
A
)
=
g
(
D
,
A
)
H
(
D
)
g_R(D,A)=\frac{g(D,A)}{H(D)}
gR(D,A)=H(D)g(D,A)
其中, 𝑔(𝐷,𝐴) 是信息增益, 𝐻(𝐷) 是数据集 𝐷 的熵。
-
g
R
(
D
,
A
)
=
g
(
D
,
A
)
H
(
D
)
g_R(D,A)=\frac{g(D,A)}{H(D)}
gR(D,A)=H(D)g(D,A)
- 样本D的基尼指数(CART)
-
G
i
n
i
(
D
)
=
1
−
∑
k
=
1
K
(
∣
C
k
∣
∣
D
∣
)
2
Gini(D)=1-\sum^{K}_{k=1}(\frac{|C_k|}{|D|})^2
Gini(D)=1−∑k=1K(∣D∣∣Ck∣)2
特征A条件下的基尼指数 - G i n i ( D ) = ∣ D 1 ∣ ∣ D ∣ G i n i ( D 1 ) + ∣ D 2 ∣ ∣ D ∣ G i n i ( D 2 ) Gini(D)=\frac{|D_1|}{|D|}Gini(D_1)+\frac{|D_2|}{|D|}Gini(D_2) Gini(D)=∣D∣∣D1∣Gini(D1)+∣D∣∣D2∣Gini(D2)
-
G
i
n
i
(
D
)
=
1
−
∑
k
=
1
K
(
∣
C
k
∣
∣
D
∣
)
2
Gini(D)=1-\sum^{K}_{k=1}(\frac{|C_k|}{|D|})^2
Gini(D)=1−∑k=1K(∣D∣∣Ck∣)2
决策树的生成
决策树的生成通常使用
- 信息增益最大
- 信息增益比最大
- 基尼指数最小
来作为特征选择的准则,从根节点开始,递归地产生决策树。
这就相当于用信息增益等准则来不断地选取局部最优地特征,将训练集分割为能够基本正确分类地子集
决策树的剪枝
由于生成的决策树存在过拟合问题,需要对它进行剪枝,以简化学到的决策树。
决策树的剪枝,往往从已生成的树上剪掉一些叶结点或叶结点以上的子树,并将其父结点或根结点作为新的叶结点,从而简化生成的决策树。
决策树地剪枝往往通过极小化决策树整体地损失函数来实现的
设
- 树T的叶节点个数为|T|
- t是树T的叶节点
- 叶节点t有 N t N_t Nt个样本点
- 属于k类的样本呢点有 N t k N_tk Ntk个
- H t ( T ) 为 叶 节 点 t 上 的 经 验 熵 H_t(T)为叶节点t上的经验熵 Ht(T)为叶节点t上的经验熵
则决策树的损失函数可以定义为
C
α
(
T
)
=
∑
t
=
1
∣
T
∣
N
t
H
t
(
T
)
+
α
∣
T
∣
C_\alpha(T)=\sum^{|T|}_{t=1}N_tH_t(T)+\alpha|T|
Cα(T)=t=1∑∣T∣NtHt(T)+α∣T∣
其中经验熵为
H
t
(
T
)
=
−
∑
k
N
t
k
N
t
l
o
g
N
t
k
N
t
H_t(T)=-\sum_{k}\frac{N_{tk}}{N_t}log\frac{N_{tk}}{N_t}
Ht(T)=−k∑NtNtklogNtNtk
故损失函数即为树T所有叶节点上的经验熵乘以叶节点的样本呢个数
损失函数可表示为 C α = C ( T ) + α ∣ T ∣ C_\alpha=C(T)+\alpha|T| Cα=C(T)+α∣T∣
-
C(T)表示模型和训练数据的拟合度
-
|T|表示模型复杂度
-
较大的α促使模型选择简单的树
-
较小的α促使模型选择复杂的树
(就相当于正则化)
算法流程
设一组叶节点回缩到父节点后产生的树为
T
B
T_B
TB,之前整体的树为
T
A
T_A
TA,损失函数分别为
C
α
(
T
A
)
C_\alpha(T_A)
Cα(TA)和
C
α
(
T
B
)
C_\alpha(T_B)
Cα(TB)
若
C
α
(
T
A
)
<
C
α
(
T
B
)
C_\alpha(T_A)<C_\alpha(T_B)
Cα(TA)<Cα(TB)
则进行剪枝
ID3,C4.5算法的优缺点
ID3
- ID3没有剪枝策略,容易过拟合
- 单纯的信息增益准则对可取值数目较多的特征有所偏好,不利于选择最优特征
- 只能用于处理离散分布的特征
- 没有考虑缺失值
C4.5的改进
- 将连续特征离散化,采用特定算法求出信息增益最大的点作为该连续特征的二元离散分类点
- 引入了剪枝策略
- 引入了处理缺失值的办法
C4.5的缺点
- C4.5用的是多叉树,用二叉树的效率更高
- C4.5只能用于分类
CART算法
CART算法是在给定输入随机变量X条件下输出随机变量Y的条件概率分布的学习方法
CART算法由以下两步组成
- 决策树生成:基于训练集生成的决策树,尽量要大
- 决策树剪枝:用验证数据集对已生成的树进行剪枝并选择最优子树,这时用损失函数最小作为剪枝的标准
CART的生成
- 回归树的生成用平方误差最小化准则
- 分类树用基尼指数最小化准则
回归树的生成
给定一个数据集 D = ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x i , y i ) , . . . , ( x n , y n ) D={(x_1,y_1),(x_2,y_2),...,(x_i,y_i),...,(x_n,y_n)} D=(x1,y1),(x2,y2),...,(xi,yi),...,(xn,yn),其中 xi 是一个 m 维的向量,即 xi 含有 m 个 features
回归问题的目标就是构建一个函数
f
(
x
)
f(x)
f(x)可以很好拟合训练集中的所有元素,使得均方误差最小
m
i
n
1
n
∑
i
=
1
n
(
f
(
x
i
)
−
y
i
)
2
min\frac{1}{n}\sum^{n}_{i=1}(f(x_i)-y_i)^2
minn1i=1∑n(f(xi)−yi)2
回归树的目标也一样
假设一棵构建好的 CART 回归树有 M 片叶子,这说明 CART 将输入空间 x 划分成了 M 个单元 R1,R2,…,RM,同时意味着 CART 至多会有 M 个不同的预测值。CART 最小化 mse 公式如下:
m
i
n
1
n
∑
m
=
1
M
∑
x
i
∈
R
m
(
c
m
−
y
i
)
2
min\frac{1}{n}\sum^{M}_{m=1}\sum_{x_i\in R_m}(c_m-y_i)^2
minn1m=1∑Mxi∈Rm∑(cm−yi)2
其中,
c
m
c_m
cm 表示第 m 片叶子的预测值。
想要最小化 CART 总体的 mse,只需要最小化每一片叶子的 mse ,即只需要将预测值设定为叶子中含有的训练集元素的均值,即:
c
m
=
a
v
e
(
y
i
∣
x
i
∈
l
e
a
f
m
)
c_m=ave(y_i|x_i\in leaf_m)
cm=ave(yi∣xi∈leafm)
所以,在每一次的划分中,选择切分变量和切分点时(也就是选择 feature 和将该 feature space 一分为二的 split),使得模型在训练集上的 mse 最小,也就是每片叶子的 mse 之和最小。
这里采用启发式的方法,遍历所有的切分变量和切分点,然后选出 叶子节点 mse 之和最小的那种情况作为划分
选择第 j 个 特征 x ( j ) x(j) x(j) 和它取的值 s,作为切分变量和切分点,
则切分变量和切分点将父节点的输入空间一分为二:
R
1
{
j
,
s
}
=
{
x
∣
x
(
j
)
≤
s
}
R_1\{j,s\}=\{x|x^{(j)}\le s\}
R1{j,s}={x∣x(j)≤s}
R
2
{
j
,
s
}
=
{
x
∣
x
(
j
)
>
s
}
R_2\{j,s\}=\{x|x^{(j)}> s\}
R2{j,s}={x∣x(j)>s}
CART 选择切分变量 j 和 切分点 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
]
\mathop{min}\limits_{j,s}[\mathop{min}\limits_{c_1}\sum_{x_i\in R_1\{j,s\}}(y_i-c_1)^2+\mathop{min}\limits_{c_2}\sum_{x_i\in R_2\{j,s\}}(y_i-c_2)^2]
j,smin[c1minxi∈R1{j,s}∑(yi−c1)2+c2minxi∈R2{j,s}∑(yi−c2)2]
我们可以用遍历的方式将j和s找出来:
for all features:
先固定特征j,选出该特征下的最优化分s
这样我们就能得到m个特征的最佳划分,再从这m个特征中取最小值即可得到全局最优的(j,s)
然后继续对两个子区间进行同样的操作,就可以得到回归树
分类树的生成
分类树用基尼指数选择最优特征,同时决定该特征的最优二值切分点
分类问题的基尼指数
分类问题中,假设有K个类,样本点属于第k个类的概率为
p
k
p_k
pk,则概率分布的基尼指数的定义为
G
i
n
i
(
p
)
=
∑
k
=
1
K
p
k
(
1
−
p
k
)
=
1
−
∑
k
=
1
K
p
k
2
Gini(p)=\sum^{K}_{k=1}p_k(1-p_k)=1-\sum^{K}_{k=1}p_k^2
Gini(p)=k=1∑Kpk(1−pk)=1−k=1∑Kpk2
对于给定的样本集合D,其给定的基尼指数为
G
i
n
i
(
D
)
=
1
−
∑
k
=
1
K
(
∣
C
k
∣
∣
D
∣
)
2
Gini(D)=1-\sum^{K}_{k=1}(\frac{|C_k|}{|D|})^2
Gini(D)=1−k=1∑K(∣D∣∣Ck∣)2
C
k
C_k
Ck是属于第k类的样本子集,K是类的个数
若样本集合D根据特征A是否取某一可能值a被分割为D1,D2
则在特征A的条件下,集合D的基尼指数定义为
G
i
n
i
(
D
,
A
)
=
∣
D
1
∣
∣
D
∣
G
i
n
i
(
D
1
)
+
∣
D
2
∣
∣
D
∣
G
i
n
i
(
D
2
)
Gini(D,A)=\frac{|D_1|}{|D|}Gini(D_1)+\frac{|D_2|}{|D|}Gini(D_2)
Gini(D,A)=∣D∣∣D1∣Gini(D1)+∣D∣∣D2∣Gini(D2)
Gini指数表示集合D的不确定性,GIni指数越大,样本集合的不确定性也越大
生成分类树的算法流程
设结点的训练数据集为D
- 遍历特征A和其所有可能取值a,根据A=a将数据集D分割为D1和D2,计算基尼指数
- 选择基尼指数最小的特征及其对应的切分点作为最优特征和最优切分点,并以此为根据从现结点中生成两个子结点,将训练数据集依特征分配到两个子节点去
- 对两个子节点递归调用(1),(2)
- 生成CART决策树
CART的剪枝
CART模型越复杂,越容易导致过拟合,所以需要进行剪枝处理
CART剪枝算法由两部分组成
- 由之前生成的决策树 T 0 T_0 T0的底端开始不断剪枝,直到 T 0 T_0 T0的根节点,每减一次枝就生成一个子树 T i T_i Ti,形成一个子树序列 T 0 , T 1 , . . . , T n {T_0,T_1,...,T_n} T0,T1,...,Tn
- 通过交叉验证对这一子树序列进行测试,从中选择最优子树
1.生成子树序列
剪枝过程中,子树的损失函数为
C
α
(
T
)
=
C
(
T
)
+
α
∣
T
∣
C_\alpha(T)=C(T)+\alpha|T|
Cα(T)=C(T)+α∣T∣
T
T
T为任意子树,
C
(
T
)
C(T)
C(T)为T对训练集的预测误差,
∣
T
∣
|T|
∣T∣为子树的叶节点个数,
α
>
=
0
\alpha>=0
α>=0为参数
其实这就相当于在损失函数上加上了一个正则项,这个正则项对树的结点进行限制
下图为一个决策树剪枝前后的情况
未剪枝前,设以t为根节点的子树为
T
t
T_t
Tt,其损失函数为
C
α
(
T
t
)
=
C
(
T
t
)
+
α
∗
∣
T
t
∣
C_\alpha(T_t)=C(T_t)+\alpha *|T_t|
Cα(Tt)=C(Tt)+α∗∣Tt∣
剪枝后,t为叶子结点,此时以t为根节点的单节点树的损失函数为
C
α
(
t
)
=
C
(
t
)
+
α
∗
1
C_\alpha(t)=C(t)+\alpha *1
Cα(t)=C(t)+α∗1
由于
∣
T
t
∣
>
1
|T_t|>1
∣Tt∣>1,于是总会存在一个
α
\alpha
α使得
C
α
(
T
t
)
=
C
α
(
t
)
C_\alpha(T_t)=C_\alpha(t)
Cα(Tt)=Cα(t)
这个
α
\alpha
α为
α
=
C
(
t
)
−
C
(
T
t
)
∣
T
t
∣
−
1
\alpha=\frac{C(t)-C(T_t)}{|T_t|-1}
α=∣Tt∣−1C(t)−C(Tt)
此时由于
C
α
(
T
t
)
=
C
α
(
t
)
C_\alpha(T_t)=C_\alpha(t)
Cα(Tt)=Cα(t),这两个损失函数大小相等,我们肯定选择模型简单的那个,于是对
T
t
T_t
Tt进行剪枝,如下图所示
对于决策树
T
0
T_0
T0中的每一个内部节点
t
t
t来说,都可以计算
g
(
t
)
=
C
(
t
)
−
C
(
T
t
)
∣
T
t
∣
−
1
g(t)=\frac{C(t)-C(T_t)}{|T_t|-1}
g(t)=∣Tt∣−1C(t)−C(Tt)
如下图所示,对于CART树,我们可以对
t
0
,
t
1
,
t
2
,
t
3
t_0,t_1,t_2,t_3
t0,t1,t2,t3计算
g
(
t
)
g(t)
g(t),然后选择
g
(
t
)
g(t)
g(t)最小的节点进行剪枝,不断进行这个步骤,可以得到从复杂到简单的子树序列
T
0
,
T
1
,
T
2
,
.
.
.
,
T
n
T_0,T_1,T_2,...,T_n
T0,T1,T2,...,Tn
为什么要先选择 g ( t ) g(t) g(t)最小的子树进行剪枝呢?
我们知道 α i = g ( t i ) \alpha_i=g(t_i) αi=g(ti),所以最小的 g ( t ) g(t) g(t)即对应着最下层的子树,我们希望剪枝是慢慢来的,不要一下子减去大量信息,所以每次都选择 g ( t ) g(t) g(t)最小的子树进行剪枝,最后得到子树序列 T 0 , T 1 , T 2 , . . . , T n T_0,T_1,T_2,...,T_n T0,T1,T2,...,Tn
2.交叉验证选择最优子树
T
α
T_\alpha
Tα
通过上一步我们便可以得到一系列的子树序列
T
0
,
T
1
,
T
2
,
.
.
.
,
T
n
T_0,T_1,T_2,...,T_n
T0,T1,T2,...,Tn
然后便可以通过交叉验证来选取最优的决策树
T
α
T_\alpha
Tα。
参考链接
底层代码实现
导入所需的类库
import numpy as np
import pandas as pd
import matplotlib as plt
from sklearn.datasets import load_iris#数据集
from sklearn.model_selection import train_test_split#数据集分割
%matplotlib inline
scikit-learn分类树实例1
#创建数据X,y
def create_data():
iris=load_iris()
#创建表
df=pd.DataFrame(iris.data,columns=iris.feature_names)
df['label']=iris.target
df.columns=[
'sepal length','sepal width','petal length','petal width','label'
]
#提取df的前100行的0,1,-1列
data=np.array(df.iloc[:100,[0,1,-1]])
#返回X,y
return data[:,:2],data[:,-1]
X, y = create_data()
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import export_graphviz
import graphviz
clf=DecisionTreeClassifier()
clf.fit(X_train,y_train,)
clf.score(X_test,y_test)
输出:1.0
scikit-learn分类树实例2
from sklearn.tree import DecisionTreeClassifier
from sklearn import preprocessing
import numpy as np
import pandas as pd
from sklearn import tree
import graphviz
#数据
features = ["年龄", "有工作", "有自己的房子", "信贷情况"]
X_train = pd.DataFrame([
["青年", "否", "否", "一般"],
["青年", "否", "否", "好"],
["青年", "是", "否", "好"],
["青年", "是", "是", "一般"],
["青年", "否", "否", "一般"],
["中年", "否", "否", "一般"],
["中年", "否", "否", "好"],
["中年", "是", "是", "好"],
["中年", "否", "是", "非常好"],
["中年", "否", "是", "非常好"],
["老年", "否", "是", "非常好"],
["老年", "否", "是", "好"],
["老年", "是", "否", "好"],
["老年", "是", "否", "非常好"],
["老年", "否", "否", "一般"]
])
y_train = pd.DataFrame(["否", "否", "是", "是", "否",
"否", "否", "是", "是", "是",
"是", "是", "是", "是", "否"])
#数据预处理,将文字数字化
le_x=preprocessing.LabelEncoder()
le_x.fit(np.unique(X_train))
X_train=X_train.apply(le_x.transform)
le_y = preprocessing.LabelEncoder()
le_y.fit(np.unique(y_train))
y_train = y_train.apply(le_y.transform)
#模型
model_tree=DecisionTreeClassifier()
model_tree.fit(X_train,y_train)
# 可视化
dot_data = tree.export_graphviz(model_tree, out_file=None,
feature_names=features,
class_names=[str(k) for k in np.unique(y_train)],
filled=True, rounded=True,
special_characters=True)
graph = graphviz.Source(dot_data)
graph
利用平方误差损失准则生成CART回归树
解答:
决策树的生成就是递归地构建二叉决策树的过程,对回归树用平方误差最小化准则,对分类树用基尼指数(Gini index)最小化准则,进行特征选择,生成二叉树。
算法5.5(最小二乘回归树生成算法)
输入:训练数据集 D D D
输出:回归树 f ( x ) f(x) f(x)
在训练数据集所在的输入空间中,递归地将每个区域划分为两个子区域并决定每个子区域上的输出值,构建二叉决策树;
(1)选择最优切分变量 j j j与切分点 s s s,求解 min j , s [ min c 1 ∑ x i ∈ R 1 ( j , s ) ( y i − c 1 ) 2 + min c 2 ∑ x i ∈ R 2 ( j , s ) ( y i − c 2 ) 2 ] \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] j,smin⎣⎡c1minxi∈R1(j,s)∑(yi−c1)2+c2minxi∈R2(j,s)∑(yi−c2)2⎦⎤遍历变量 j j j,对固定的切分变量 j j j扫描切分点 s s s,选择使得上式达到最小值的对 ( j , s ) (j,s) (j,s)
(2)用选定的对 ( j , s ) (j,s) (j,s)划分区域并决定相应的输出值: R 1 ( j , s ) = { x ∣ x ( j ) ⩽ s } , R 2 ( j , s ) = { x ∣ x ( j ) > s } c m ^ = 1 N m ∑ x i ∈ R m ( j , s ) y i , x ∈ R m , m = 1 , 2 R_1(j,s)=\{x|x^{(j)}\leqslant s\}, R_2(j,s)=\{x|x^{(j)} > s\} \\ \hat{c_m} = \frac{1}{N_m} \sum_{x_i \in R_m(j,s)} y_i, x \in R_m, m=1,2 R1(j,s)={x∣x(j)⩽s},R2(j,s)={x∣x(j)>s}cm^=Nm1xi∈Rm(j,s)∑yi,x∈Rm,m=1,2
(3)继续对两个子区域调用步骤(1),(2),直至满足停止条件
(4)将输入空间划分为 M M M个区域 R 1 , R 2 , ⋯ , R M R_1,R_2,\cdots,R_M R1,R2,⋯,RM,生成决策树: f ( x ) = ∑ m = 1 M c m ^ I ( x ∈ R m ) f(x)=\sum_{m=1}^M \hat{c_m} I(x \in R_m) f(x)=m=1∑Mcm^I(x∈Rm)
class LeastSqRTree:
def __init__(self,train_X,y,epsilon):
#训练集特征值,(id,feature)
self.x=train_X
#类别
self.y=y
#损失阈值
self.epsilon=epsilon
#特征总数
self.feature_count=train_X.shape[1]
#回归树
self.tree=None
def _fit(self,x,y,feature_count,epsilon):
#选择最优切分点变量j和切分点s
(j,s,minval,c1,c2)=self._divide(x,y,feature_count)
#初始化树,递归建树
tree={"feature":j,"value":x[s,j],"left":None,"right":None}
if minval < self.epsilon or len(y[np.where(x[:, j] <= x[s, j])]) <= 1:
tree["left"] = c1
else:
tree["left"] = self._fit(x[np.where(x[:, j] <= x[s, j])],
y[np.where(x[:, j] <= x[s, j])],
self.feature_count, self.epsilon)
if minval < self.epsilon or len(y[np.where(x[:, j] > s)]) <= 1:
tree["right"] = c2
else:
tree["right"] = self._fit(x[np.where(x[:, j] > x[s, j])],
y[np.where(x[:, j] > x[s, j])],
self.feature_count, self.epsilon)
return tree
def fit(self):
self.tree = self._fit(self.x, self.y, self.feature_count, self.epsilon)
@staticmethod
#选择最优切分点变量j和切分点s
def _divide(x,y,feature_count):
#初始化损失矩阵
cost=np.zeros((feature_count,len(x)))
#李航《统计学习方法》公式5.21
#遍历特征
for i in range(feature_count):
#遍历x
for k in range(len(x)):
#k行i列的特征值
value=x[k,i];
#切割数据集
y1=y[np.where(x[:,i]<=value)]
c1=np.mean(y1)
y2=y[np.where(x[:,i]>value)]
c2=np.mean(y2)
#均值归一化
y1[:]=y1[:]-c1
y2[:]=y2[:]-c2
cost[i,k]=np.sum(y1*y1)+np.sum(y2*y2)
#选取最优损失误差点
cost_index = np.where(cost == np.min(cost))
#最优特征值
j=cost_index[0][0]
#最优切分点
s=cost_index[1][0]
#切分区间
c1 = np.mean(y[np.where(x[:,j]<=x[s,j])])
c2 = np.mean(y[np.where(x[:, j] > x[s, j])])
return j, s, cost[cost_index], c1, c2
train_X = np.array([[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]).T
y = np.array([4.50, 4.75, 4.91, 5.34, 5.80, 7.05, 7.90, 8.23, 8.70, 9.00])
model_tree = LeastSqRTree(train_X, y, .2)
model_tree.fit()
model_tree.tree
根据上面程序的输出,可得到用平方误差损失准则生成一个二叉回归树:
f
(
x
)
=
{
4.72
x
≤
3
5.57
3
<
x
≤
5
7.05
5
<
x
≤
6
7.9
6
<
x
≤
7
8.23
7
<
x
≤
8
8.85
x
>
8
f(x)=\begin{cases} 4.72 & x \le 3\\ 5.57 & 3 < x \le 5\\ 7.05 & 5 < x \le 6\\ 7.9 & 6 < x \le 7 \\ 8.23 & 7 < x \le 8\\ 8.85 & x > 8\\ \end{cases}
f(x)=⎩⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎧4.725.577.057.98.238.85x≤33<x≤55<x≤66<x≤77<x≤8x>8