随机森林 3(代码)

发布时间:2024年01月05日

?通过随机森林 1随机森林 2?的介绍,相信大家对理论已经了解的很透彻,接下来带大家敲一下代码,不懂得可以加我入群讨论。

第一份代码是比较原始的代码,第二份代码是第一段代码中引用的primitive_plot,第三份代码是使用 sklearn 包实现的代码,第四份代码是 sklearn 使用第一份代码数据集的实现代码。

import primitive_plot

from math import log
import operator


def createDataSet():
    """
    dataSet = [[0, 0, 0, 0, 'a'],
               [1, 0, 0, 0, 'b'],
               [1, 1, 0, 0, 'e'],
               [1, 2, 0, 0, 'f'],
               [2, 0, 0, 0, 'c'],
               [3, 0, 0, 0, 'd']]
    """
    labels = ['A', 'B', 'C', 'D']
    return dataSet, labels


# 创建树,参数分别是数据集,数据集对应的标签,特征标签(用于构建树,可以理解为当前的树结构)
def createTree(dataset, labels):
    classList = [example[-1] for example in dataset]
    if classList.count(classList[0]) == len(classList):
        # classList 全部是一个类别
        return classList[0]
    if len(dataset[0]) == 1:
        # dataset 只剩 label 标签,说明分类完成
        return majorityCnt(classList)
    # 选出最佳特征
    bestFeature = chooseBestFeatureToSplit(dataset)
    bestFeatureLabel = labels[bestFeature]

    myTree = {bestFeatureLabel: {}}
    print("A", myTree)
    # 在 labels 中删除最佳特征
    del labels[bestFeature]
    # 提取最佳特征在数据集中的取值
    featureList = [data[bestFeature] for data in dataset]
    # 去重
    uniqueFeatureList = set(featureList)

    #遍历最佳特征的每个取值,以上当做固定条件后,创建树
    for uniqueFeature in uniqueFeatureList:
        sublabels = labels[:]
        print("S", sublabels, uniqueFeature)
        myTree[bestFeatureLabel][uniqueFeature] = createTree(splitDataSet(dataset, bestFeature, uniqueFeature), sublabels)
        print("B", myTree)
    print("C", myTree)
    return myTree


# 返回分类数量最多类的数量值
def majorityCnt(classList):
    classCount = {}
    for vote in classList:
        if vote not in classCount.keys():
            classCount[vote] = 0
        classCount[vote] += 1
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    print(sortedClassCount)
    return sortedClassCount[0][0]


# 选出这个数据集中信息增益最大的特征
def chooseBestFeatureToSplit(dataset):
    numFeatures = len(dataset[0]) - 1
    baseEntropy = calcShannonEnt(dataset)
    bestinfoGain = 0
    bestFeature = -1
    for i in range(numFeatures):
        featureList = [data[i] for data in dataset]
        # 去重
        uniqueFeatureList = set(featureList)
        newEntropy = 0
        for uniqueFeature in uniqueFeatureList:
            # 两个 for 循环遍历每个特征的每个值,计算每个特征的信息增益
            subDataSet = splitDataSet(dataset, i, uniqueFeature)
            prob = len(subDataSet) / float(len(dataset))
            newEntropy += prob * calcShannonEnt(subDataSet)
        infoGain = baseEntropy - newEntropy
        if (infoGain > bestinfoGain):
            bestinfoGain = infoGain
            bestFeature = i
    return bestFeature


# 选取在某个特征上某个取值的数据集
def splitDataSet(dataset, axis, val):
    # 创建一个空列表,用于存储划分后的子集
    retDataSet = []
    # 遍历数据集中的每个特征向量(一行数据)
    for featVec in dataset:
        # 如果特征向量在指定轴上的值等于给定的特征值(val)
        if featVec[axis] == val:
            # 则将该特征向量在指定轴上的值剔除,形成新的特征向量
            reducedFeatVec = featVec[:axis]
            reducedFeatVec.extend(featVec[axis + 1:])
            # 将新的特征向量添加到划分后的子集中
            retDataSet.append(reducedFeatVec)

    return retDataSet


# 计算熵
def calcShannonEnt(dataset):
    datasize = len(dataset)
    labelCounts = {}
    for data in dataset:
        label = data[-1]
        if label not in labelCounts.keys():
            labelCounts[label] = 0
        labelCounts[label] += 1

    shannonEnt = 0
    for key in labelCounts:
        prop = float(labelCounts[key]) / datasize
        shannonEnt -= prop * log(prop, 2)
    return shannonEnt


if __name__ == '__main__':
    dataset, labels = createDataSet()
    myTree = createTree(dataset, labels)
    primitive_plot.createPlot(myTree)

import matplotlib.pyplot as plt

# 能够显示中文
#matplotlib.rcParams['font.sans-serif'] = ['SimHei']
#matplotlib.rcParams['font.serif'] = ['SimHei']

# 分叉节点,也就是决策节点  创建字典
decisionNode = dict(boxstyle="sawtooth", fc="0.8")

# 叶子节点
leafNode = dict(boxstyle="round4", fc="0.8")

# 箭头样式
arrow_args = dict(arrowstyle="<-")


def plotNode(nodeTxt, centerPt, parentPt, nodeType):
    """
    绘制一个节点
    :param nodeTxt: 描述该节点的文本信息
    :param centerPt: 文本的坐标
    :param parentPt: 点的坐标,这里也是指父节点的坐标
    :param nodeType: 节点类型,分为叶子节点和决策节点
    :return:
    """
    createPlot.ax1.annotate(nodeTxt, xy=parentPt, xycoords='axes fraction',
                            xytext=centerPt, textcoords='axes fraction',
                            va="center", ha="center", bbox=nodeType, arrowprops=arrow_args)


def getNumLeafs(myTree):
    """
    获取叶节点的数目
    :param myTree:
    :return:
    """
    # 统计叶子节点的总数
    numLeafs = 0

    # 得到当前第一个key,也就是根节点
    firstStr = list(myTree.keys())[0]

    # 得到第一个key对应的内容
    secondDict = myTree[firstStr]

    # 递归遍历叶子节点
    for key in secondDict.keys():
        # 如果key对应的是一个字典,就递归调用
        if type(secondDict[key]).__name__ == 'dict':
            numLeafs += getNumLeafs(secondDict[key])
        # 不是的话,说明此时是一个叶子节点
        else:
            numLeafs += 1
    return numLeafs


def getTreeDepth(myTree):
    """
    得到树的深度层数
    :param myTree:
    :return:
    """
    # 用来保存最大层数
    maxDepth = 0

    # 得到根节点
    firstStr = list(myTree.keys())[0]

    # 得到key对应的内容
    secondDic = myTree[firstStr]

    # 遍历所有子节点
    for key in secondDic.keys():
        # 如果该节点是字典,就递归调用
        if type(secondDic[key]).__name__ == 'dict':
            # 子节点的深度加1
            thisDepth = 1 + getTreeDepth(secondDic[key])

        # 说明此时是叶子节点
        else:
            thisDepth = 1

        # 替换最大层数
        if thisDepth > maxDepth:
            maxDepth = thisDepth

    return maxDepth


def plotMidText(cntrPt, parentPt, txtString):
    """
    计算出父节点和子节点的中间位置,填充信息
    :param cntrPt: 子节点坐标
    :param parentPt: 父节点坐标
    :param txtString: 填充的文本信息
    :return:
    """
    # 计算x轴的中间位置
    xMid = (parentPt[0] - cntrPt[0]) / 2.0 + cntrPt[0]
    # 计算y轴的中间位置
    yMid = (parentPt[1] - cntrPt[1]) / 2.0 + cntrPt[1]
    # 进行绘制
    createPlot.ax1.text(xMid, yMid, txtString)


def plotTree(myTree, parentPt, nodeTxt):
    """
    绘制出树的所有节点,递归绘制
    :param myTree: 树
    :param parentPt: 父节点的坐标
    :param nodeTxt: 节点的文本信息
    :return:
    """
    # 计算叶子节点数
    numLeafs = getNumLeafs(myTree=myTree)

    # 计算树的深度
    depth = getTreeDepth(myTree=myTree)

    # 得到根节点的信息内容
    firstStr = list(myTree.keys())[0]

    # 计算出当前根节点在所有子节点的中间坐标,也就是当前x轴的偏移量加上计算出来的根节点的中心位置作为x轴(比如说第一次:初始的x偏移量为:-1/2W,计算出来的根节点中心位置为:(1+W)/2W,相加得到:1/2),当前y轴偏移量作为y轴
    cntrPt = (plotTree.xOff + (1.0 + float(numLeafs)) / 2.0 / plotTree.totalW, plotTree.yOff)

    # 绘制该节点与父节点的联系
    plotMidText(cntrPt, parentPt, nodeTxt)

    # 绘制该节点
    plotNode(firstStr, cntrPt, parentPt, decisionNode)

    # 得到当前根节点对应的子树
    secondDict = myTree[firstStr]

    # 计算出新的y轴偏移量,向下移动1/D,也就是下一层的绘制y轴
    plotTree.yOff = plotTree.yOff - 1.0 / plotTree.totalD

    # 循环遍历所有的key
    for key in secondDict.keys():
        # 如果当前的key是字典的话,代表还有子树,则递归遍历
        if isinstance(secondDict[key], dict):
            plotTree(secondDict[key], cntrPt, str(key))
        else:
            # 计算新的x轴偏移量,也就是下个叶子绘制的x轴坐标向右移动了1/W
            plotTree.xOff = plotTree.xOff + 1.0 / plotTree.totalW
            # 打开注释可以观察叶子节点的坐标变化
            # print((plotTree.xOff, plotTree.yOff), secondDict[key])
            # 绘制叶子节点
            plotNode(secondDict[key], (plotTree.xOff, plotTree.yOff), cntrPt, leafNode)
            # 绘制叶子节点和父节点的中间连线内容
            plotMidText((plotTree.xOff, plotTree.yOff), cntrPt, str(key))

    # 返回递归之前,需要将y轴的偏移量增加,向上移动1/D,也就是返回去绘制上一层的y轴
    plotTree.yOff = plotTree.yOff + 1.0 / plotTree.totalD


def createPlot(inTree):
    """
    需要绘制的决策树
    :param inTree: 决策树字典
    :return:
    """
    # 创建一个图像
    fig = plt.figure(1, facecolor='white')
    fig.clf()
    axprops = dict(xticks=[], yticks=[])
    createPlot.ax1 = plt.subplot(111, frameon=False, **axprops)
    # 计算出决策树的总宽度
    plotTree.totalW = float(getNumLeafs(inTree))
    # 计算出决策树的总深度
    plotTree.totalD = float(getTreeDepth(inTree))
    # 初始的x轴偏移量,也就是-1/2W,每次向右移动1/W,也就是第一个叶子节点绘制的x坐标为:1/2W,第二个:3/2W,第三个:5/2W,最后一个:(W-1)/2W
    plotTree.xOff = -0.5 / plotTree.totalW
    # 初始的y轴偏移量,每次向下或者向上移动1/D
    plotTree.yOff = 1.0
    # 调用函数进行绘制节点图像
    plotTree(inTree, (0.5, 1.0), '')
    # 绘制
    plt.show()

# 导入所需的库
from sklearn.datasets import load_iris             # 用于加载鸢尾花数据集
from sklearn.model_selection import train_test_split # 用于拆分数据集为训练集和测试集
from sklearn.ensemble import RandomForestClassifier  # 随机森林分类器
from sklearn.metrics import accuracy_score           # 用于计算分类准确性

# 加载鸢尾花数据集
iris = load_iris()
X = iris.data  # 特征矩阵
y = iris.target  # 目标标签

# 将数据集拆分为训练集和测试集
# train_test_split: 这是 scikit-learn 库中用于将数据集划分为训练集和测试集的函数。
# X: 特征矩阵,包含了所有的样本和特征。
# y: 目标标签,包含了样本的类别信息。
# test_size: 测试集的比例。在这个例子中,test_size=0.3 表示将 30% 的数据用作测试集,而 70% 的数据用作训练集。
# random_state: 随机数生成器的种子。设置了 random_state=42 可以使每次运行代码时都得到相同的随机划分,保证结果的可重复性。
# 返回的四个变量:
# X_train: 训练集的特征矩阵。
# X_test: 测试集的特征矩阵。
# y_train: 训练集的目标标签。
# y_test: 测试集的目标标签。
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 创建随机森林分类器模型
rf_model = RandomForestClassifier(n_estimators=10, random_state=42)
# 参数说明:
# - n_estimators: 决策树的数量,这里设置为 10
# - random_state: 随机数生成器的种子,用于保证结果的可重现性

# 在训练集上训练模型
rf_model.fit(X_train, y_train)

# 在测试集上进行预测
y_pred = rf_model.predict(X_test)

# 计算模型的准确性
accuracy = accuracy_score(y_test, y_pred)
print(f"Model Accuracy: {accuracy}")

# 输出每个特征的重要性
feature_importances = rf_model.feature_importances_
print("\nFeature Importances:")
for feature, importance in zip(iris.feature_names, feature_importances):
    print(f"{feature}: {importance:.4f}")
# 解释:
# zip(iris.feature_names, feature_importances): 这个函数将两个可迭代对象(iris.feature_names 和 feature_importances)逐一配对,创建一个由元组组成的迭代器。
# 在这里,它将每个特征的名称与其对应的重要性值配对在一起。
# - feature_importances_: 随机森林模型中每个特征的重要性
# - iris.feature_names: 鸢尾花数据集中特征的名称

# 导入所需的库
from sklearn.model_selection import train_test_split # 用于拆分数据集为训练集和测试集
from sklearn.ensemble import RandomForestClassifier  # 随机森林分类器
from sklearn.metrics import accuracy_score           # 用于计算分类准确性

# 加载鸢尾花数据集
X = [[0, 0, 0, 0],
     [1, 0, 0, 0],
     [1, 1, 0, 0],
     [1, 2, 0, 0],
     [2, 0, 0, 0],
     [3, 0, 0, 0]]  # 特征矩阵
y = ['a', 'a', 'c', 'a', 'a', 'f']  # 目标标签

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=42)

# 创建随机森林分类器模型
rf_model = RandomForestClassifier(n_estimators=10, random_state=42)


# 在训练集上训练模型
rf_model.fit(X_train, y_train)

# 在测试集上进行预测
y_pred = rf_model.predict(X_test)

# 计算模型的准确性
accuracy = accuracy_score(y_test, y_pred)
print("Model Accuracy:", accuracy)

想加微信算法交流群的朋友可以先扫码加我微信,我拉你进群。

文章来源:https://blog.csdn.net/u014182497/article/details/135388136
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。