我之前写过一篇关于决策树的文章,但在那篇文章里没有提及基尼系数,信息熵与信息增益等相关问题,所以我将在这篇文章中进行补充。
一、 决策树的一份python代码
首先,我先给出一份最基础的决策树代码,在这里,由于没有指定criterion系数,所有默认采用基尼系数,不过在之后我还将具体些地讲述基尼系数。
代码如下:
python
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
# 导入数据
iris = load_iris()
X = iris.data
y = iris.target
# 划分
X_train, X_test, y_train, y_test = train_test_split(X,y,random_state=42)
# 决策树实例化
clf = DecisionTreeClassifier(random_state=1024)
# 拟合
clf.fit(X_train,y_train)
# 预测
y_pre = clf.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test,y_pre)
print("The true target: {}".format(y_test))
print("The predict target: {}".format(y_pre))
print(accuracy)
它的输出为:
The true target: [1 0 2 1 1 0 1 2 1 1 2 0 0 0 0 1 2 1 1 2 0 2 0 2 2 2 2 2 0 0 0 0 1 0 0 2 1
0]
The predict target: [1 0 2 1 1 0 1 2 1 1 2 0 0 0 0 1 2 1 1 2 0 2 0 2 2 2 2 2 0 0 0 0 1 0 0 2 1
0]
1.0
二、 基尼系数
接下来,我们就详细些地来看下基尼系数。首先,我们要知道基尼系数是来 对于不确定性给出一个值的,也就是说基尼系数的含义就是不确定程度。它可以用符号表示为:
我们以iris数据集来解释下:
2.1 计算分割前的基尼系数
首先我们知道在数据集中有三种类别,每种类别都是50个,一共有150个,那么就有50/150=1/3,也就是:
2.2 计算分割后的基尼系数
假设我们有一阈值t,并且将根据这个阈值来将数据集分割为两个部分,那么我们就需要分别计算左侧和右侧的基尼系数,并加权。
我们假设左边有nL个,右边有nR个,并且总数为n个,那么就会产生两个基尼系数:GL与GR,
我们选择最小的阈值t,来作为最佳的分割点。
2.3 实际代码
python
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
# 导入数据
iris = load_iris()
X = iris.data
y = iris.target
# 划分
X_train, X_test, y_train, y_test = train_test_split(X,y,random_state=42)
# 选择花瓣长度作为特征
feature_index = 2 # 花瓣长度
thresholds = np.linspace(X[:, feature_index].min(), X[:, feature_index].max(), num=10)
# 计算
for threshold in thresholds:
left_indices = X[:, feature_index] < threshold
right_indices = ~left_indices
# 左侧子节点的样本
left_y = y[left_indices]
left_n = len(left_y)
# 右侧子节点的样本
right_y = y[right_indices]
right_n = len(right_y)
# 确保子节点中至少有一个样本
if left_n == 0 or right_n == 0:
continue
# 计算每个子节点的基尼系数
g_left = 1 - sum([(np.sum(left_y == c) / left_n) ** 2 for c in range(3)])
g_right = 1 - sum([(np.sum(right_y == c) / right_n) ** 2 for c in range(3)])
# 计算分割后的基尼系数
g_split = (left_n / (left_n + right_n)) * g_left + (right_n / (left_n + right_n)) * g_right
print(f"Threshold: {threshold}, Split Gini: {g_split}")
# 分割
clf = DecisionTreeClassifier(criterion='gini', random_state=1234)
clf.fit(X_train, y_train)
# 预测
y_pred = clf.predict(X_test)
# 计算
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy: {}".format(accuracy))
结果如下:
Threshold: 1.6555555555555554, Split Gini: 0.389937106918239
Threshold: 2.311111111111111, Split Gini: 0.3333333333333333
Threshold: 2.966666666666667, Split Gini: 0.3333333333333333
Threshold: 3.6222222222222222, Split Gini: 0.383485309017224
Threshold: 4.277777777777778, Split Gini: 0.4438118958666904
Threshold: 4.933333333333334, Split Gini: 0.40858416945373466
Threshold: 5.588888888888889, Split Gini: 0.5333333333333333
Threshold: 6.2444444444444445, Split Gini: 0.638888888888889
Threshold: 6.9, Split Gini: 0.6621923937360179
Accuracy: 1.0
不过,我们在使用时可以直接使用sklearn的基尼系数分类器,而不需要手动设置,并且效果也并不会差。sklearn使用基尼系数分类器的代码如下:
python
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
# 导入数据
iris = load_iris()
X = iris.data
y = iris.target
# 划分
X_train, X_test, y_train, y_test = train_test_split(X,y,random_state=42)
# 使用决策树分类器进行分割
clf = DecisionTreeClassifier(criterion='gini', random_state=1024)
clf.fit(X_train, y_train)
# 预测
y_pred = clf.predict(X_test)
# 计算
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy: {}".format(accuracy))
我们将这个代码与开头所给出的代码进行比较,不难发现唯一的不同之处就是在分割上有所不同,即:
python
# 使用决策树分类器进行分割
clf = DecisionTreeClassifier(criterion='gini', random_state=1234)
这一行代码中多了参数criterion。
我们还可以将基尼系数对于iris数据集的划分进行可视化,结果为:
三、 信息熵与信息增益
接下来,我们就要认识下信息熵与信息增益。
3.1 信息熵
信息熵是统计学的一个定义,用于表示一组数据的混乱程度与不确定性,在决策树中,其则用于展示一棵树的纯度。对于一个具有k个类别的数据集D,其信息熵H(D)为:
3.2 信息增益
信息增益是用于衡量某个数据集在分割后其不确定性与混乱程度减少了多少。它是决策树中选择分割特征的重要依据之一。对于特征A来说,其信息增益可以表示为:
3.3 举例
假如我们有一数据集如下,其有两个类比0与1。
我们计算信息熵会有:
计算信息增益会有:
3.4 实际代码
同样的,我们用实际的python代码来展示,代码如下:
python
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
# 加载数据集
iris = load_iris()
X = iris.data
y = iris.target
# 划分
X_train, X_test, y_train, y_test = train_test_split(X,y,random_state=42)
# 使用决策树分类器进行分割
clf = DecisionTreeClassifier(criterion='entropy', random_state=1234)
clf.fit(X_train, y_train)
# 预测测试集的结果
y_pred = clf.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy: {}".format(accuracy))
在决策树中,我往往只使用基尼系数与信息熵和信息增益之一来作为分类依据,而不会都使用。也同样的,我们要使用什么作为分类依据,我们就在criterion后填写什么,而不自行编写代码计算。
四、 多变量决策树
如果我们将每个属性看作坐标空间中的一个坐标轴,那么d个属性描述的样本就对应了d维空间的一个数据点,而对于样本的分类也就意味着在坐标空间中寻找不同类样本间的分类边界。在决策树中形成的分类边界会有一个明显的特征,就是轴平行,即它的分类边界由若干个与坐标轴平行的分段组成。但这样虽然对于最终的结果会有优秀的解释性,但复杂性也会很高,故而考虑采用斜的划分边界来对其进行简化。标题所说的"多变量决策树"就能实现。在这个多变量决策树中,我们不为每个非叶节点去寻找一个最优划分属性,而是试图建立一个合适的线性分类器。
还是用iris数据集来举例,首先是多变量的:
python
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
# 加载数据集
iris = load_iris()
X = iris.data
y = iris.target
# 划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 实例化
clf = DecisionTreeClassifier(criterion='gini', random_state=1234)
clf.fit(X_train, y_train)
# 预测
y_pred = clf.predict(X_test)
# 计算
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")
# 生成分类报告
print("\nClassification Report:")
print(classification_report(y_test, y_pred))
# 生成混淆矩阵
print("\nConfusion Matrix:")
print(confusion_matrix(y_test, y_pred))
然后是单个特征的:
python
import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
# 加载数据集
iris = load_iris()
X = iris.data[:, [2]] # 使用花瓣长度作为唯一特征
y = iris.target
# 划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 实例化
clf = DecisionTreeClassifier(criterion='gini', random_state=1234)
clf.fit(X_train, y_train)
# 预测
y_pred = clf.predict(X_test)
# 计算
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.2f}")
# 生成分类报告
print("\nClassification Report:")
print(classification_report(y_test, y_pred))
# 生成混淆矩阵
print("\nConfusion Matrix:")
print(confusion_matrix(y_test, y_pred))
其输出将分别是:
Accuracy: 1.00
Classification Report:
precision recall f1-score support
0 1.00 1.00 1.00 19
1 1.00 1.00 1.00 13
2 1.00 1.00 1.00 13
accuracy 1.00 45
macro avg 1.00 1.00 1.00 45
weighted avg 1.00 1.00 1.00 45
Confusion Matrix:
[[19 0 0]
[ 0 13 0]
[ 0 0 13]]
与
Accuracy: 0.96
Classification Report:
precision recall f1-score support
0 1.00 1.00 1.00 19
1 0.92 0.92 0.92 13
2 0.92 0.92 0.92 13
accuracy 0.96 45
macro avg 0.95 0.95 0.95 45
weighted avg 0.96 0.96 0.96 45
Confusion Matrix:
[[19 0 0]
[ 0 12 1]
[ 0 1 12]]
此上