1. 熵、经验条件熵、信息增益算法实现:

熵:$H(X)=-\sum_{i=1}^np_i\log_2p_i$

经验条件熵:$H(Y|X)=\sum_{i=1}^np_iH(Y|X=x_i)$

信息增益:$IG(Y,X)=H(Y)-H(Y|X)$

其中,$X$为特征,$Y$为分类结果,$p_i$为$X=x_i$的概率。

算法实现如下:

import numpy as np

def calc_entropy(y):
    """
    计算熵
    :param y: 分类结果
    :return: 熵
    """
    # 统计每个分类结果的出现次数
    value_count = np.unique(y, return_counts=True)[1]
    # 计算每个分类结果的概率
    value_prob = value_count / len(y)
    # 计算熵
    entropy = -np.sum(value_prob * np.log2(value_prob))
    return entropy

def calc_cond_entropy(y, x):
    """
    计算经验条件熵
    :param y: 分类结果
    :param x: 特征
    :return: 经验条件熵
    """
    # 统计特征x每个取值的出现次数
    value_count = np.unique(x, return_counts=True)[1]
    # 计算每个特征取值的概率
    value_prob = value_count / len(x)
    # 计算经验条件熵
    cond_entropy = np.sum([value_prob[i] * calc_entropy(y[x == np.unique(x)[i]]) for i in range(len(value_count))])
    return cond_entropy

def calc_info_gain(y, x):
    """
    计算信息增益
    :param y: 分类结果
    :param x: 特征
    :return: 信息增益
    """
    # 计算熵
    entropy = calc_entropy(y)
    # 计算经验条件熵
    cond_entropy = calc_cond_entropy(y, x)
    # 计算信息增益
    info_gain = entropy - cond_entropy
    return info_gain
  1. ID3算法实现:

ID3算法是基于信息增益的决策树算法,该算法的核心思想是选择信息增益最大的特征作为当前节点的分类依据,并递归地构建决策树。

算法实现如下:

import numpy as np

class Node:
    """
    决策树节点类
    """
    def __init__(self, feature=None, value=None, leaf=None, branches=None):
        """
        初始化节点
        :param feature: 分裂特征
        :param value: 特征取值
        :param leaf: 叶子节点分类结果
        :param branches: 分支节点
        """
        self.feature = feature
        self.value = value
        self.leaf = leaf
        self.branches = branches

class DecisionTree:
    """
    决策树类
    """
    def __init__(self, criterion='entropy', max_depth=None, min_samples_split=2):
        """
        初始化决策树
        :param criterion: 分裂特征的评判标准
        :param max_depth: 最大深度
        :param min_samples_split: 最小分裂样本数
        """
        self.criterion = criterion
        self.max_depth = max_depth
        self.min_samples_split = min_samples_split
        self.tree = None

    def fit(self, X, y):
        """
        训练决策树
        :param X: 特征
        :param y: 分类结果
        """
        self.tree = self.build_tree(X, y)

    def predict(self, X):
        """
        预测分类结果
        :param X: 特征
        :return: 分类结果
        """
        return np.array([self.predict_one(x, self.tree) for x in X])

    def predict_one(self, x, node):
        """
        预测单个样本的分类结果
        :param x: 特征
        :param node: 决策树节点
        :return: 分类结果
        """
        if node.leaf is not None:
            # 如果当前节点是叶子节点,则返回叶子节点的分类结果
            return node.leaf
        else:
            # 否则,根据分裂特征和特征取值选择下一个节点
            for branch in node.branches:
                if x[node.feature] == branch.value:
                    return self.predict_one(x, branch)

    def build_tree(self, X, y, depth=0):
        """
        递归地构建决策树
        :param X: 特征
        :param y: 分类结果
        :param depth: 当前深度
        :return: 决策树节点
        """
        num_samples, num_features = X.shape

        # 如果当前深度达到最大深度,则返回叶子节点,分类结果为样本中出现次数最多的分类结果
        if self.max_depth is not None and depth >= self.max_depth:
            leaf = np.argmax(np.bincount(y))
            return Node(leaf=leaf)

        # 如果样本数小于最小分裂样本数,则返回叶子节点,分类结果为样本中出现次数最多的分类结果
        if num_samples < self.min_samples_split:
            leaf = np.argmax(np.bincount(y))
            return Node(leaf=leaf)

        # 如果所有特征取值相同,则返回叶子节点,分类结果为样本中出现次数最多的分类结果
        if np.unique(y).shape[0] == 1:
            return Node(leaf=y[0])

        # 计算每个特征的信息增益,并选择信息增益最大的特征作为分裂特征
        if self.criterion == 'entropy':
            gains = [calc_info_gain(y, X[:, i]) for i in range(num_features)]
        elif self.criterion == 'gini':
            gains = [calc_gini_gain(y, X[:, i]) for i in range(num_features)]
        best_feature_index = np.argmax(gains)
        best_gain = gains[best_feature_index]
        if best_gain == 0:
            leaf = np.argmax(np.bincount(y))
            return Node(leaf=leaf)
        best_feature = best_feature_index

        # 根据分裂特征和特征取值构建分支节点
        branches = []
        for value in np.unique(X[:, best_feature]):
            X_subset = X[X[:, best_feature] == value]
            y_subset = y[X[:, best_feature] == value]
            branch = self.build_tree(X_subset, y_subset, depth=depth+1)
            branch.value = value
            branches.append(branch)

        # 返回分支节点
        return Node(feature=best_feature, branches=branches)
  1. sklearn库中的决策树算法:

sklearn库中的决策树算法有两种:CART和ID3。其中,CART算法使用基尼不纯度作为评判标准,ID3算法使用信息增益作为评判标准。

CART算法的实现类为sklearn.tree.DecisionTreeClassifier,ID3算法的实现类为sklearn.tree.ExtraTreeClassifier

  1. iris数据集预测分类:

iris数据集是一个常用的分类问题数据集,共有150个样本,每个样本有4个特征和1个分类结果。sklearn库中内置了iris数据集,可以直接使用。

实现代码如下:

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier

# 加载数据集
iris = load_iris()
X = iris.data
y = iris.target

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

# 建立决策树模型
clf = DecisionTreeClassifier()

# 训练模型
clf.fit(X_train, y_train)

# 预测测试集
y_pred = clf.predict(X_test)

# 输出准确率
print("Accuracy:", np.mean(y_pred == y_test))

实验结果分析:

使用sklearn库中的决策树算法训练iris数据集,得到的准确率为0.97。可以看出,决策树算法可以很好地解决分类问题。

1设计算法实现熵、经验条件熵、信息增益等方法。2实现ID3算法。3熟悉sklearn库中的决策树算法;4针对iris数据集应用sklearn的决策树算法进行类别预测。要求一:运行实验指导中的样例分析实验结果。要求二:调用scikit-learn库实现iris数据集预测分类

原文地址: http://www.cveoy.top/t/topic/4tJ 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录