欢迎访问宙启技术站
智能推送

用Python实现一个决策树算法函数

发布时间:2023-05-22 20:17:10

决策树是一种基本的分类和回归方法,其本质是一种树形结构,其中每个内部节点表示一个特征或属性,每个分支代表该特征的一个取值,每个叶节点表示一个类别。决策树学习的本质是构建一个树形结构的分类器或回归器。在构建决策树时,算法会选择最优的特征来作为节点,然后将数据集划分为不同的子集,使得每个子集尽量纯净,即同一个子集中的样本尽量属于同一个类别。构建决策树的过程可以使用递归的方式来实现。本文将使用Python实现一个基本的决策树算法函数。

我们将使用Iris数据集作为分类的例子。Iris数据集是一个标准的机器学习数据集,其中包含了三个类别的花卉,分别是山鸢尾(Iris Setosa)、变色鸢尾(Iris Versicolour)和维吉尼亚鸢尾(Iris Virginica)。数据集中包含了150个样本,每个样本有四个特征,分别是花瓣长度、花瓣宽度、花萼长度和花萼宽度。我们的目标是根据这四个特征来预测花卉的类别。

数据集下载链接:https://archive.ics.uci.edu/ml/datasets/iris

首先,我们需要将数据集读入程序中,并将其拆分为训练集和测试集。代码如下:

import csv
import random
import math
 
# 读取数据集
def loadDataset(filename, split, trainingset=[], testset=[]):
    with open(filename, 'rt') as csvfile:
        lines = csv.reader(csvfile)
        dataset = list(lines)
        for x in range(len(dataset)-1):
            for y in range(4):
                dataset[x][y] = float(dataset[x][y])
            if random.random() < split:
                trainingset.append(dataset[x])
            else:
                testset.append(dataset[x])

接下来,我们需要实现一个函数来计算数据集的熵。熵是衡量样本集合的"纯度"的指标,可以用来选择最优的特征来作为节点。如果一个样本集合中包含的样本属于同一个类别,那么这个样本集合的熵为0;如果样本集合中包含的样本属于不同的类别,那么这个样本集合的熵越大,表示其"纯度"越低。代码如下:

# 计算数据集的熵
def entropy(dataset):
    n = len(dataset)
    classes = {}
    for sample in dataset:
        c = sample[-1]
        if c not in classes:
            classes[c] = 0
        classes[c] += 1
    e = 0
    for c in classes:
        p = classes[c] / n
        e -= p * math.log2(p)
    return e

然后,我们需要实现一个函数来选择最优的特征来作为节点。我们使用信息增益来衡量特征对样本集合的分类的"贡献度",信息增益越大,表示该特征对分类的影响越大,应该选择该特征作为节点。代码如下:

# 选择最优的特征
def selectFeature(dataset):
    n = len(dataset[0]) - 1
    avgE = entropy(dataset)
    maxGain = 0
    bestFeature = -1
    for f in range(n):
        classes = {}
        for sample in dataset:
            c = sample[f]
            if c not in classes:
                classes[c] = []
            classes[c].append(sample)
        e = 0
        for c in classes:
            p = len(classes[c]) / len(dataset)
            e += p * entropy(classes[c])
        gain = avgE - e
        if gain > maxGain:
            maxGain = gain
            bestFeature = f
    return bestFeature

下一步是构建决策树。我们使用递归的方式来实现。在构建决策树时,算法会选择最优的特征来作为节点,然后将数据集划分为不同的子集,使得每个子集尽量纯净,即同一个子集中的样本尽量属于同一个类别。代码如下:

# 构建决策树
def decisionTree(dataset, features):
    classes = [sample[-1] for sample in dataset]
    if len(set(classes)) == 1:
        return classes[0]
    if len(dataset[0]) == 1:
        return max(set(classes), key=classes.count)
    bestFeature = selectFeature(dataset)
    node = features[bestFeature]
    tree = {node:{}}
    del(features[bestFeature])
    classes = {}
    for sample in dataset:
        c = sample[bestFeature]
        if c not in classes:
            classes[c] = []
        classes[c].append(sample)
    for c in classes:
        subtree = decisionTree(classes[c], features)
        tree[node][c] = subtree
    return tree

最后,我们需要实现一个函数来测试决策树的性能。代码如下:

# 测试决策树的准确率
def testTree(tree, testset):
    n = len(testset)
    correct = 0
    for sample in testset:
        c = classify(tree, sample)
        if c == sample[-1]:
            correct += 1
    return correct / n
 
# 使用决策树进行分类
def classify(tree, sample):
    if type(tree) != dict:
        return tree
    node = list(tree.keys())[0]
    value = sample[features.index(node)]
    subtree = tree[node][value]
    return classify(subtree, sample)

完整代码如下:

`python

import csv

import random

import math

# 读取数据集

def loadDataset(filename, split, trainingset=[], testset=[]):

with open(filename, 'rt') as csvfile:

lines = csv.reader(csvfile)

dataset = list(lines)

for x in range(len(dataset)-1):

for y in range(4):

dataset[x][y] = float(dataset[x][y])

if random.random() < split:

trainingset.append(dataset[x])

else:

testset.append(dataset[x])

# 计算数据集的熵

def entropy(dataset):

n = len(dataset)

classes = {}

for sample in dataset:

c = sample[-1]

if c not in classes:

classes[c] = 0

classes[c] += 1

e = 0

for c in classes:

p = classes[c] / n

e -= p * math.log2(p)

return e

# 选择最优的特征

def selectFeature(dataset):

n = len(dataset[0]) - 1

avgE = entropy(dataset)

maxGain = 0

bestFeature = -1

for f in range(n):

classes = {}

for sample in dataset:

c = sample[f]

if c not in classes:

classes[c] = []

classes[c].append(sample)

e = 0

for c in classes:

p = len(classes[c]) / len(dataset)

e += p * entropy(classes[c])

gain = avgE - e

if gain > maxGain:

maxGain = gain

bestFeature = f

return bestFeature

# 构建决策树

def decisionTree(dataset, features):

classes = [sample[-1] for sample in dataset]

if len(set(classes)) == 1:

return classes[0]

if len(dataset[0]) == 1:

return max(set(classes), key=classes.count)

bestFeature = selectFeature(dataset)

node = features[bestFeature]

tree = {node:{}}

del(features[bestFeature])

classes = {}

for sample in dataset:

c = sample[bestFeature]

if c not in classes:

classes[c] = []

classes[c].append