0


了解大数据中的决策树

前言

决策树(Decision Tree)是一种类似于流程图的树形结构,每个内部节点表示在一个属性上的测试,每个分支代表一个属性输出,而每个叶节点代表类或类分布。决策树通过树状结构,基于数据特征与目标变量之间的关系,将数据集划分为不同的子集,以逐步构建决策规则。其工作原理是从根节点开始,根据输入特征的取值,沿着相应的分支向下移动,直到到达一个叶节点,叶节点的值即为最终分类或预测结果,递归地选择最优特征进行分裂,构建出完整的决策树。

一、决策树原理及构建

原理

决策树的概念来源于统计学和决策论,能够直观地模拟人类的决策过程。它通过递归地将数据集划分为多个子集,形成树状结构,以表示数据的分布和分类规则。每个内部节点代表一个特征的决策,每个叶子节点则是决策结果(分类或回归值)。决策树的构建主要基于“信息增益”(Information Gain)或“基尼不纯度”(Gini Impurity)等指标。其核心思想是逐步选择最佳的特征来划分数据集,从而构建出能够最好地分类或回归的树。

信息增益:表示某个特征对分类结果的不确定性的减少量。信息增益越大,表示该特征越能有效减少不确定性,从而更好地划分数据。

基尼不纯度:用于衡量一个数据集在某特征下的不纯度。基尼不纯度越低,数据集越“纯”。

构建步骤

决策树的构建过程是一个递归选择最优特征,并根据特征的不同取值对数据进行划分的过程,直到满足停止条件为止。以下是构建步骤:

①准备数据:将数据集划分成训练集和测试集,进行缺失值处理和特征选择。

②选择最优特征:对于数据集中的每个特征,计算其对数据集的信息增益或基尼不纯度,选择信息增益最大或基尼不纯度最小的特征作为本次分类的特征。

③划分数据集:根据选择的特征,将数据集划分成若干子集,每个子集包含特征一致的一部分数据。

④递归构建决策树:对于每个子集,重复上述选择最优特征和划分数据集的过程,直到子集中的数据属于同一类别或者到达一定的停止条件为止。常见的停止条件包括:所有样本属于同一类别、特征集为空、或者样本数量小于预设的阈值。

⑤测试模型:将测试集中的数据输入到构建好的模型中,计算模型的分类准确度和召回率等评估指标。

⑥优化模型:对于分类错误的样本,可以通过调整参数(如决策树的最大深度、最小样本数等)和增加样本来优化模型。此外,为了防止决策树过拟合,还可以进行剪枝操作,即去除不必要的分支,保留重要的决策节点,从而提高模型的泛化能力。

二、决策树的典型算法

ID3算法

概念:ID3(Iterative Dichotomiser 3)算法是决策树学习算法的一种经典方法,它根据信息增益来选择每个节点的分裂属性。

  • 步骤选择最佳特征:构建根节点,将所有训练数据都放在根节点,根据信息增益选择最能区分数据的特征作为当前节点的分割标准。
  • 数据分割:使用选定的最佳分裂属性将当前节点的数据集划分成多个子集,每个子集对应于分裂属性的不同取值。
  • 递归构建树:对于每个子集,递归地应用上述步骤,直到达到停止条件。停止条件可以是节点中样本的类别完全相同,或者节点中的样本数小于某个阈值。
  • 生成树:重复上述步骤,直到所有叶子节点都是纯的(即只包含同一类别的样本)或者达到停止条件。
  • 优点:简单易懂,生成的决策树易于解释。
  • 缺点:对缺失值敏感,不能处理连续型属性,容易过拟合。

C4.5算法

  • 概念:C4.5是ID3的改进版本,引入了能够处理连续属性和缺失值的机制,以及剪枝操作,能够更好地应对实际问题。
  • 改进:1. 处理连续属性:通过将连续属性离散化,C4.5能够处理连续属性。2. 处理缺失值:C4.5提供了处理缺失值的方法,使得算法在存在缺失值的情况下也能正常工作。3. 剪枝操作:C4.5引入了剪枝操作,通过剪除不必要的分支,提高了决策树的泛化能力。
  • 应用:C4.5算法既适合于分类问题,又适合于回归问题。

CART算法

  • 概念:CART(Classification and Regression Trees)算法是一种广泛使用的决策树算法,它可以用于分类问题和回归问题。
  • 特点:1. 二叉树结构:CART算法生成的决策树是二叉树,即每个节点最多有两个子节点。2. 基尼系数:CART算法使用基尼系数来衡量数据集的不纯度,并选择能够最大程度减少不纯度的特征作为分裂属性。3. 剪枝操作:CART算法也包含了剪枝操作,以提高决策树的泛化能力。
  • 应用:CART算法在分类和回归问题中都有广泛的应用。

ID3、C4.5和CART是决策树的典型算法,它们各有特点,适用于不同的应用场景。在实际应用中,可以根据具体问题的需求和数据的特性选择合适的算法。

三.决策树的算法实现示例

ID3算法代码示例

import numpy as np  
from collections import Counter  
  
class DecisionTree:  
    class Node:  
        def __init__(self):  
            self.value = None  # 内部叶节点属性  
            self.feature_index = None  
            self.children = {}  
  
        def __str__(self):  
            if self.children:  
                s = '内部节点<%s>:\n' % self.feature_index  
                for fv, node in self.children.items():  
                    ss = '[%s]-> %s' % (fv, node)  
                    s += '\t' + ss.replace('\n', '\n\t') + '\n'  
                s = s[:-1]  
            else:  
                s = '叶节点(%s)' % self.value  
            return s  
  
    def __init__(self, gain_threshold=1e-2):  # 信息增益阈值  
        self.gain_threshold = gain_threshold  
  
    def _entropy(self, y):  # 熵: -sum(pi*log(pi))  
        c = np.bincount(y)  
        p = c[np.nonzero(c)] / y.size  
        return -np.sum(p * np.log2(p))  
  
    def _conditional_entropy(self, feature, y):  # 条件熵  
        feature_values = np.unique(feature)  
        h = 0.  
        for v in feature_values:  
            y_sub = y[feature == v]  
            p = y_sub.size / y.size  
            h += p * self._entropy(y_sub)  
        return h  
  
    def _information_gain(self, feature, y):  # 信息增益 = 经验熵 - 经验条件熵  
        return self._entropy(y) - self._conditional_entropy(feature, y)  
  
    def _select_feature(self, X, y, features_list):  # 选择信息增益最大特征  
        if features_list:  
            gains = np.apply_along_axis(self._information_gain, 0, X[:, features_list], y)  
            index = np.argmax(gains)  
            if gains[index] > self.gain_threshold:  
                return index  
        return None  
  
    def _create_tree(self, X, y, features_list):  # 创建节点  
        node = DecisionTree.Node()  
        labels_count = np.bincount(y)  
        node.value = np.argmax(labels_count)  # 节点值总等于数据集中样本最多的类标记  
  
        if np.count_nonzero(labels_count) != 1:  # 判断类标记是否全部一致  
            index = self._select_feature(X, y, features_list)  
            if index is not None:  
                node.feature_index = features_list.pop(index)  
                feature_values = np.unique(X[:, node.feature_index])  
                for v in feature_values:  
                    idx = X[:, node.feature_index] == v  
                    X_sub, y_sub = X[idx], y[idx]  
                    node.children[v] = self._create_tree(X_sub, y_sub, features_list.copy())  
        return node  
  
    def train(self, X_train, y_train):  # 训练决策树  
        _, n = X_train.shape  
        self.tree_ = self._create_tree(X_train, y_train, list(range(n)))  
  
    def predict(self, X_test):  # 对每一个测试样本, 调用_predict_one, 将收集到的结果数组返回  
        return np.apply_along_axis(self._predict_one, axis=1, arr=X_test)  
  
    def _predict_one(self, x_test):  # 搜索决策树, 对单个样本进行预测  
        node = self.tree_  
        while node.children:  
            child = node.children.get(x_test[node.feature_index])  
            if not child:  
                break  
            node = child  
        return node.value  
  
    def __str__(self):  
        if hasattr(self, 'tree_'):  
            return str(self.tree_)  
        return ''  
  
# 使用示例数据集进行分类  
# 数据集加载和数据预处理部分略...  
# 假设X_train和y_train是已经准备好的训练数据集  
# 假设X_test是待预测的测试数据集  
  
tree = DecisionTree()  
tree.train(X_train, y_train)  
predictions = tree.predict(X_test)  
print(predictions)

C4.5算法代码示例

import numpy as np  
from collections import Counter  
  
def calc_entropy(labels):  
    counter = Counter(labels)  
    probs = [counter[c] / len(labels) for c in counter]  
    entropy = -np.sum(probs * np.log2(probs))  
    return entropy  
  
def calc_info_gain(data, labels, feature_idx):  
    feature_values = set(data[:, feature_idx])  
    entropy_before = calc_entropy(labels)  
    gain = entropy_before  
    for value in feature_values:  
        subset = data[data[:, feature_idx] == value]  
        subset_labels = labels[data[:, feature_idx] == value]  
        weight = len(subset_labels) / len(labels)  
        gain -= weight * calc_entropy(subset_labels)  
    return gain  
  
def choose_best_feature(data, labels):  
    num_features = data.shape[1]  
    best_feature = None  
    best_gain = 0  
    for i in range(num_features):  
        info_gain = calc_info_gain(data, labels, i)  
        if info_gain > best_gain:  
            best_gain = info_gain  
            best_feature = i  
    return best_feature  
  
def create_decision_tree(data, labels):  
    if len(set(labels)) == 1:  
        return labels[0]  
    if data.shape[1] == 0:  
        return Counter(labels).most_common(1)[0][0]  
    best_feature = choose_best_feature(data, labels)  
    tree = {best_feature: {}}  
    feature_values = set(data[:, best_feature])  
    for value in feature_values:  
        subset = data[data[:, best_feature] == value]  
        subset_labels = labels[data[:, best_feature] == value]  
        tree[best_feature][value] = create_decision_tree(subset, subset_labels)  
    return tree  
  
# 使用示例数据集进行分类  
data = np.array([[1, 1, 1], [1, 1, 0], [0, 1, 1], [0, 0, 1]])  
labels = np.array([1, 1, 0, 0])  
decision_tree = create_decision_tree(data, labels)  
print(decision_tree)

CART算法代码示例(回归树)

import numpy as np  
import pickle  
import matplotlib.pyplot as plt  
from sklearn.datasets import load_boston  
  
def loadDataSet(fileName):  
    dataMat = []  
    fr = open(fileName)  
    for line in fr.readlines():  
        curLine = line.strip().split('\t')  
        fltLine = list(map(float, curLine))  
        dataMat.append(fltLine)  
    return dataMat  
  
def binSplitDataSet(dataSet, feature, value):  
    mat0 = dataSet[dataSet[:, feature] > value]  
    mat1 = dataSet[dataSet[:, feature] <= value]  
    return mat0, mat1  
  
def regLeaf(dataSet):  
    return np.mean(dataSet[:, -1])  
  
def regErr(dataSet):  
    return np.var(dataSet[:, -1]) * len(dataSet)  
  
def chooseBestSplit(dataSet, leafType=regLeaf, errType=regErr, ops=(1, 4)):  
    tolS = ops[0]; tolN = ops[1]  
    if len(set(dataSet[:, -1].T.tolist()[0])) == 1:  
        return None, leafType(dataSet)  
    m, n = dataSet.shape  
    S = errType(dataSet)  
    bestS = float('inf'); bestIndex = 0; bestValue = 0  
    for featIndex in range(n - 1):  
        for splitVal in set(dataSet[:, featIndex].T.A.tolist()[0]):  
            mat0, mat1 = binSplitDataSet(dataSet,

总结

大数据决策树是一种基于树形结构的机器学习算法,特别适用于处理和分析大规模数据集。它通过递归地将数据集分割成更小的子集,以构建出一个类似于树状的预测模型。在树的每个节点上,算法会根据某个特征属性的值来判断数据应该流向哪个分支,直到到达叶子节点,给出最终的预测结果或分类标签。

大数据决策树的优势在于其直观易懂、易于实现,并且能够有效地处理高维数据和具有缺失值的数据集。此外,它还能够自动进行特征选择和交互效应的识别,为决策过程提供有价值的洞察。然而,随着数据量的增加,决策树可能会变得过于复杂,导致过拟合问题。因此,在实际应用中,常需要结合剪枝、集成学习等技术来优化模型性能。

总之,大数据决策树是一种强大且灵活的工具,能够帮助我们从海量数据中挖掘出有价值的规律和模式,为决策提供有力支持。


本文转载自: https://blog.csdn.net/youganma/article/details/143286889
版权归原作者 什么又不懂了? 所有, 如有侵权,请联系我们删除。

“了解大数据中的决策树”的评论:

还没有评论