目录
一、基尼系数
二、决策树中的超参数
三、决策树解决回归问题
四、决策树的局限性
在决策树中,基尼系数是一种衡量数据集纯度的指标。在构建决策树时,基尼系数可以用来确定每个节点上哪个特征是最好的分割特征。基尼系数越小,表示数据集的纯度越高。 它和上一小节提到的信息熵类似。
代码示例:
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
iris = datasets.load_iris()
X = iris.data[:,2:]
y = iris.target
#创建决策树分类器
from sklearn.tree import DecisionTreeClassifier
dt_clf = DecisionTreeClassifier(max_depth=2, criterion="gini", random_state=42)
#此时criterion系数由entropy(信息熵)变为gini(基尼系数)
dt_clf.fit(X, y)
#使用基尼系数进行划分
from collections import Counter
from math import log
def split(X, y, d, value): #d为维度,value为该维度的值
index_a = (X[:,d] <= value)
index_b = (X[:,d] > value)
return X[index_a], X[index_b], y[index_a], y[index_b]
#计算基尼系数
def gini(y):
counter = Counter(y)
res = 1.0
for num in counter.values():
p = num / len(y)
res -= p ** 2
return res
#在所有数据上寻找维度和值
def try_split(X, y):
best_g = float('inf')
best_d, best_v = -1, -1
for d in range(X.shape[1]):
sorted_index = np.argsort(X[:,d])
for i in range(1, len(X)):
if X[sorted_index[i], d] != X[sorted_index[i-1], d]:
v = (X[sorted_index[i], d] + X[sorted_index[i-1], d])/2
X_l, X_r, y_l, y_r = split(X, y, d, v)
p_l, p_r = len(X_l) / len(X), len(X_r) / len(X)
g = p_l * gini(y_l) + p_r * gini(y_r)
if g < best_g:
best_g, best_d, best_v = g, d, v
return best_g, best_d, best_v
best_g, best_d, best_v = try_split(X, y)
X1_l, X1_r, y1_l, y1_r = split(X, y, best_d, best_v)
gini(y1_l)
#0.0
gini(y1_r)
#0.5
#对右子树继续进行划分
best_g2, best_d2, best_v2 = try_split(X1_r, y1_r)
X2_l, X2_r, y2_l, y2_r = split(X1_r, y1_r, best_d2, best_v2)
gini(y2_l)
gini(y2_r)
运行结果:
信息熵与基尼系数的区别在于:
超参数可以用来调节算法的性能和模型的复杂度,以下是一些常见的决策树超参数:
最大深度(max_depth):决策树的最大深度,用来控制决策树的复杂度和过拟合风险。
最小样本数(min_samples_split):决策树节点分裂的最小样本数,用来控制决策树的生长过程和过拟合风险。
最小叶子节点样本数(min_samples_leaf):叶子节点包含的最小样本数,用来控制决策树的生长过程和过拟合风险。
最大叶子节点数(max_leaf_nodes):限制决策树的最大叶子节点数,用来控制决策树的复杂度和过拟合风险。
代码示例:
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
X, y = datasets.make_moons(noise=0.25, random_state=666)
#绘制决策边界
def plot_decision_boundary(model, axis):
x0, x1 = np.meshgrid(
np.linspace(axis[0], axis[1], int((axis[1]-axis[0])*100)).reshape(-1, 1),
np.linspace(axis[2], axis[3], int((axis[3]-axis[2])*100)).reshape(-1, 1),
)
X_new = np.c_[x0.ravel(), x1.ravel()]
y_predict = model.predict(X_new)
zz = y_predict.reshape(x0.shape)
from matplotlib.colors import ListedColormap
custom_cmap = ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)
from sklearn.tree import DecisionTreeClassifier
dt_clf2 = DecisionTreeClassifier(max_depth=2) #最大深度
dt_clf2.fit(X, y)
'''
plot_decision_boundary(dt_clf2, axis=[-1.5, 2.5, -1.0, 1.5])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()
'''
dt_clf3 = DecisionTreeClassifier(min_samples_split=10) #最小样本数
dt_clf3.fit(X, y)
'''
plot_decision_boundary(dt_clf3, axis=[-1.5, 2.5, -1.0, 1.5])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()
'''
dt_clf4 = DecisionTreeClassifier(min_samples_leaf=6) #最小叶子节点样本数
dt_clf4.fit(X, y)
'''
plot_decision_boundary(dt_clf4, axis=[-1.5, 2.5, -1.0, 1.5])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()
'''
dt_clf5 = DecisionTreeClassifier(max_leaf_nodes=4) #最大叶子节点数
dt_clf5.fit(X, y)
plot_decision_boundary(dt_clf5, axis=[-1.5, 2.5, -1.0, 1.5])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()
运行结果:
以上代码是分别传入决策树中的各个参数得到的结果,同时我们也可以通过网格搜索的方式将这些参数组合起来,来调整模型结果。
使用sklearn中DecisionTreeRegressor来解决,它与DecisionTreeClassifier的超参数都是相同的,区别在于最后得到的结果是分类结果还是回归结果。
代码示例:
boston = datasets.load_boston()
X = boston.data
y = boston.target
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)
from sklearn.tree import DecisionTreeRegressor
dt_reg = DecisionTreeRegressor() #可以传入超参数进行调节
dt_reg.fit(X_train, y_train)
dt_reg.score(X_test, y_test)
根据前面的例子我们可以看出,决策树的决策边界都是与x轴和y轴平行的,对于这类决策边界,它具备一定的局限性。
假设现在有两类数据,分别为红色和蓝色。通过决策树的决策边界绘制如下,事实上这是不对的,因为我们可以直接通过一根斜线来进行区分。
另外,决策树边界也对个别数据特别敏感。当我们删除 X、Y 的一个数据时,会发现绘制出的决策边界发生了很大变化。这也是所有非参数学习普遍存在的缺点,高度依赖调整超参数。