Decision Tree
从根开始,按照决策树的分类属性,从上往下,逐层划分。直到叶子节点,便能获得结果。所以决策树算法的核心在于如何构造一颗决策树?
最常见核心的决策树算法有三个——ID3、C4.5、CART
条件熵H(D|A):已知A条件下的熵。A是训练集中除标签外的一个属性,即根据A属性的不同取值将原训练集D划分成若干子集(D1,D2,D3…)。条件熵是各子集所占比重×子集的信息熵 的加和得出。
条件给的越好,划分出子集的信息熵就越小(因为每个子集基本都是同一分类),条件熵就越小,信息增益就越大。所以信息增益最大的属性即当前最好的属性。
预剪枝使得决策树的很多分支都没有“展开”,不仅降低了过拟合的风险,还显著减少了决策树的训练时间开销和测试时间开销。但可能导致欠拟合。
后剪枝通常比预剪枝决策树保留了更多的分支,欠拟合风险很小,泛化性能优于预剪枝。但要自底向上对非叶节点进行逐一考察,因此训练时间开销比未剪枝决策树和预剪枝决策树都要大得多。
# 构造决策树
def createTree(dataSet, labels):
classList = [example[-1] for example in dataSet] # 所有分类的数组
if classList.count(classList[0]) == len(classList): # 所有标签都属于一个分类
return classList[0]
if len(dataSet[0]) == 1: # 使用完了所有特征,仍不能将数据集划分成仅包含唯一类别的分组
return majorityCnt(classList) # 若所有属性都被考虑,仍无法划分标签,采用多数表决决定该叶子结点的分类
bestFeat = chooseBestFeatureToSplit(dataSet) # 选取信息增益最大的特征作为下一次分类的依据
bestFeatLabel = labels[bestFeat] # 选取特征对应的标签
myTree = {bestFeatLabel:{}} # 创建tree字典,紧跟现阶段最优特征,下一个特征位于第二个大括号内,循环递归
del(labels[bestFeat]) # 使用过的特征从中删除
featValues = [example[bestFeat] for example in dataSet]
uniqueValues = set(featValues)
for value in uniqueValues:
subLabels = labels[:] # 复制labels列表,避免每次调用createTree()函数将原始列表改变,因为有的调用在前有的调用在后
myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value), subLabels) # 循环递归生成树
return myTree
# 使用决策树的分类函数
def classify(inputTree,featLabels,testVec):
firstStr = list(inputTree.keys())[0] # 第一个按照其分类的属性
secondDict = inputTree[firstStr] # 第一个属性下的节点字典,也就是子树
featIndex = featLabels.index(firstStr) # 将标签换为索引
key = testVec[featIndex]
valueOfFeat = secondDict[key]
if isinstance(valueOfFeat, dict): # 如果还是个字典,说明没到叶子结点,继续递归
classLabel = classify(valueOfFeat, featLabels, testVec)
else: # 如果到达叶子结点,直接返回分类标签
classLabel = valueOfFeat
return classLabel
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.tree import DecisionTreeClassifier
iris = datasets.load_iris() # 加载鸢尾花数据集
X = iris.data[:, 2:] # 只取后两个维度特征
y = iris.target
dt_clf = DecisionTreeClassifier(max_depth=2, criterion="entropy") # 最大深度2,使用信息熵作为划分标准
dt_clf.fit(X, y)
"""
sklearn的决策树实现: CART算法
DecisionTreeClassifier部分参数(默认值)
criterion='gini': 划分标准.默认gini,也可以改成entropy等
max_depth=2: 限制整棵树的最大深度.越大越容易过拟合
max_leaf_nodes=None: 最多有几个叶子结点.越大越容易归你和
min_samples_leaf=1: 对于一个叶子结点,最少应该有几个样本.越小越容易过拟合
min_samples_split=2: 对于一个节点,至少有多少个样本数据,才继续拆分.越小越容易过拟合
"""
# 绘制决策边界
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, cmap=custom_cmap)
plot_decision_boundary(dt_clf, axis=[0.5, 7.5, 0, 3])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.scatter(X[y==2,0], X[y==2,1])
plt.show()
clf = KNeighborsClassifier(n_neighbors=5,weights=’uniform’, algorithm=’auto’, leaf_size=30, p=2,
metric=’minkowski’,metric_params=None, n_jobs=1, **kwargs)
criterion='gini'
: 划分标准.默认gini,也可以改成entropy等max_depth=2
: 限制整棵树的最大深度.越大越容易过拟合max_leaf_nodes=None
: 最多有几个叶子结点.越大越容易归你和min_samples_leaf=1
: 对于一个叶子结点,最少应该有几个样本.越小越容易过拟合min_samples_split=2
: 对于一个节点,至少有多少个样本数据,才继续拆分.越小越容易过拟合import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
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)
# Decision Tree Regressor
from sklearn.tree import DecisionTreeRegressor
dt_reg = DecisionTreeRegressor()
dt_reg.fit(X_train, y_train)
dt_reg.score(X_test, y_test)
# 0.58605479243964098
dt_reg.score(X_train, y_train)
# 1.0
1. 优点
2. 缺点