目录
一、决策树简介
在机器学习中,决策树是一个预测模型,它代表的是对象属性与对象值之间的一种映射关系。树中每个节点表示某个对象,而每个分叉路径则代表某个可能的属性值,每个叶节点则对应从根节点到该叶节点所经历的路径所表示的对象的值。
在构建决策树的过程中,关键步骤包括特征选择和递归构建。特征选择是通过选择最具有区分度的特征作为树的节点,以提高模型的准确性。递归构建则是将数据集划分为不同的子集,直到满足某个终止条件,比如信息增益、信息增益比或基尼系数等不再提升,或者达到预设的树的最大深度等。
为了避免决策树出现过拟合问题,通常需要进行剪枝处理。剪枝处理可以在构建决策树的过程中进行(预剪枝),也可以在构建完整棵决策树之后再进行(后剪枝)。预剪枝在构建过程中就提前停止树的生长,而后剪枝则是在树构建完成后,通过删除一些子树来简化模型。
决策树算法有多种变体,如ID3、C4.5和CART等,它们在特征选择、树构建和剪枝等方面可能存在一些差异。这些算法的选择取决于具体的应用场景和需求。
二、生成算法
2.1 ID3算法(信息增益)
特点:
1.使用信息增益作为选择划分属性的标准。
2.只能处理离散型属性,对于连续型属性需要进行离散化处理。
3.倾向于选择取值较多的属性作为划分标准,可能导致过拟合。
计算方法:
计算熵(Entropy):衡量数据集的无序程度。
计算信息增益(Information Gain):用于选择最优特征的指标。通过计算父节点和子节点的熵的差值来得到。
选择最优特征:选择信息增益最大的特征作为当前节点的划分特征。
熵的计算:
信息增益 = 信息熵 - 条件熵:也可以表示为H0 - H1。
2.2 C4.5算法(信息增益率)
特点:
C4.5算法最大的特点是克服了ID3对特征数目的偏重这一缺点,引入信息增益率来作为分类标准。
计算方法:
信息增益率=信息增益/特征本身的熵
信息增益率的计算:
2.3 CART算法(基尼指数)
基尼指数(基尼不纯度):表示在样本集合中一个随机选中的样本被分错的概率。
基尼系数越小,不纯度越低,特征越好。这和信息增益(率)正好相反。基尼指数可以用来度量任何不均匀分布,是介于0-1之间的数,0是完全相等,1是完全不相等。
基尼指数计算方法:
三、对决策树的剪枝操作
在决策树中,剪枝操作是一个重要的步骤,用于防止模型过拟合,提高其在未知数据上的泛化能力。剪枝操作主要通过移除决策树中的一些分支或子树来实现,从而降低模型的复杂度。
剪枝操作主要分为两种:预剪枝和后剪枝。
3.1预剪枝:
预剪枝是在决策树构建过程中进行的剪枝操作。在决策树的每个节点进行划分之前,先进行评估,如果划分不能带来决策树泛化性能的提升,就停止划分并将该节点标记为叶节点。
常见的预剪枝方法包括:
1.设置一个阈值,当节点的信息增益(或基尼指数)小于这个阈值时,停止划分。
2.限制决策树的深度或叶子节点的数量。
3.提前停止树的增长,例如使用交叉验证等方法评估决策树的性能,并在性能开始下降时停止构建。
优缺点:
预剪枝的优点是简单高效,但可能导致决策树欠拟合,因为它提前停止了树的生长。
3.2后剪枝:
后剪枝是在决策树构建完成后进行的剪枝操作。它通常从树的底部开始,将子树替换为叶节点,或者移除一些分支,以提高决策树的泛化能力。
常见的后剪枝方法包括:
错误率降低剪枝(REP):使用一个新的数据集来评估剪枝前后的错误率,如果剪枝后的错误率没有上升,则进行剪枝。
悲观剪枝(PEP):根据剪枝前后的误差率来评估剪枝的效果。如果剪枝后的误差率小于剪枝前误差率的上限,则进行剪枝。
代价复杂度剪枝(Cost Complexity Pruning):通过定义一个代价函数(如树的复杂度与错误率的加权和),选择使代价函数最小的子树作为剪枝后的决策树。
优缺点:
后剪枝的优点是能够得到一个更精简的决策树,降低过拟合的风险,但计算复杂度相对较高。
四、算法实现
4.1 ID3算法代码实现
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from collections import Counter
import math
# 创建数据集
data = {
'年龄段': [1, 2, 2, 0, 1, 2, 0, 1, 2, 2],
'有工作': [0, 1, 1, 0, 1, 0, 1, 1, 0, 1],
'有自己的房子': [0, 0, 1, 1, 1, 1, 0, 1, 1, 1],
'信贷情况': [0, 1, 1, 0, 1, 1, 2, 1, 1, 1],
'是否给贷款': [0, 0, 1, 1, 1, 1, 0, 1, 1, 1]
}
df = pd.DataFrame(data)
X = df.drop('是否给贷款', axis=1)
y = df['是否给贷款']
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 计算熵的函数
def calc_entropy(y):
hist = Counter(y)
ps = [hist[val] / len(y) for val in hist.keys()]
return -sum([p * math.log2(p) for p in ps if p > 0])
# 计算信息增益的函数
def calc_information_gain(X, y, feature):
values = X[feature].unique()
weighted_entropy = sum((X[feature] == val).sum() / len(X) * calc_entropy(y[X[feature] == val]) for val in values)
orig_entropy = calc_entropy(y)
return orig_entropy - weighted_entropy
# 计算每个特征的信息增益
feature_gains = {feature: calc_information_gain(X_train, y_train, feature) for feature in X_train.columns}
# 输出每个特征的信息增益
print("ID3算法中\n每个特征的信息增益:")
for feature, gain in feature_gains.items():
print(f"{feature}: {gain:.4f}")
# 选择信息增益最大的特征作为划分属性
best_feature = max(feature_gains, key=feature_gains.get)
print(f"最佳划分特征: {best_feature}")
# 由于scikit-learn的DecisionTreeClassifier默认使用CART算法,我们需要手动实现ID3的划分逻辑
# 这里我们仅展示如何计算信息增益,并不完整实现ID3算法
# 完整的ID3算法实现需要递归地构建决策树,处理连续属性、缺失值等复杂情况
# 使用scikit-learn的DecisionTreeClassifier作为替代,虽然它默认使用CART算法
from sklearn.tree import DecisionTreeClassifier
# 使用信息增益作为划分标准(虽然scikit-learn的DecisionTreeClassifier默认使用基尼指数)
clf_id3_like = DecisionTreeClassifier(criterion='entropy', random_state=42)
clf_id3_like.fit(X_train, y_train)
# 预测测试集结果
y_pred_id3 = clf_id3_like.predict(X_test)
# 输出测试数据的预测结果及准确率
print("\n测试数据预测结果:")
print(y_pred_id3)
print(f"ID3算法准确率: {accuracy_score(y_test, y_pred_id3)}")
4.2 CART算法代码实现
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.tree import DecisionTreeClassifier
# 创建贷款数据集
data = {
'年龄段': [1, 2, 2, 0, 1, 2, 0, 1, 2, 2],
'有工作': [0, 1, 1, 0, 1, 0, 1, 1, 0, 1],
'有自己的房子': [0, 0, 1, 1, 1, 1, 0, 1, 1, 1],
'信贷情况': [0, 0, 1, 0, 1, 1, 2, 1, 1, 1],
'是否给贷款': [0, 0, 1, 1, 1, 1, 0, 1, 1, 1]
}
# 转换为DataFrame
df = pd.DataFrame(data)
# 分离特征和标签
X = df[['年龄段', '有工作', '有自己的房子', '信贷情况']]
y = df['是否给贷款']
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1)
# 初始化并训练决策树分类器,使用基尼不纯度作为分割标准
clf = DecisionTreeClassifier(criterion='gini', max_depth=3, random_state=1)
clf.fit(X_train, y_train)
# 预测测试集的标签
y_pred = clf.predict(X_test)
# 计算准确率
score = accuracy_score(y_test, y_pred)
print("CART分类树的准确率: %.4f" % score)