决策树python实现,,不需要掉包2

H.  为了进行数据集的测试,需要知道每个测试集分类过后的标签,因此使用find()方法,递归的找到每个枝杈上的叶子节点,叶子节点的Value值就是当前的分类情况。因为在创建树的时候已经将每个叶子节点的dim设置为了-1,因此只需要判断tree.getdim是否为-1就可以知道是否为叶子节点,如果不是则分别在左右子树上找,直到找到叶子节点:

   def find(node, data):

    if node.getdim() == -1:

        return node.getValue()

    else:

        reducedFeatVec1 = []

        reducedFeatVec1 = data[:node.getdim()]

        reducedFeatVec1.extend(data[node.getdim() + 1:])

        if data[node.getdim()] > node.getValue():

            return find(node.getLeft(), reducedFeatVec1)

        elif data[node.getdim()] <= node.getValue():

            return find(node.getRight(), reducedFeatVec1)

I.  找到了每个测试集的分类之后就可以进行正确率的判断,如果预测的类和真实标签相同则+1:

  

def classify(dataset, tree):

    cout = 0

    for example in dataset:

        a = find(tree, example)

        b = example[-1]

        if a == b:

            cout += 1

return cout

 

J.  通过预剪枝的方法建造一棵树,首先判断停止的条件与上面的相同,传入的参数多了一个测试集。用count1和count2分别表示在这个特征上不分开和分开的正确的个数。首先获得当前节点的value值,就是通过投票而获得的当前节点的类标签,通过这个值和真实标签作比较。之后对训练集在这个节点处进行划分,有得到一个划分后的正确率,如果前者大,则停止划分,将其的dim设置为-1,如果前者小则继续分叉,在其左子树和右子树上进行同样的操作:

  # 预剪枝

def precutting(dataset, tree, testdata):

    count1 = 0

    count2 = 0

 

    classList = [example[-1] for example in dataset]

    if (classList.count(classList[0]) == len(classList)):

        tree.setValue(classList[0])

        return tree.setdim(-1)

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

        tree.setValue(majorityCnt(classList))

        return tree.setdim(-1)

    bestvalue1 = tree.getValue()

    for dt in testdata:

        if (dt[-1] == bestvalue1):

            count1 += 1

 

    bestDim, bestValue = ChooseBestBranch(dataset)

    tree.setdim(bestDim)

    tree.setValue(bestValue)

    leftTree = TreeNode()

    rightTree = TreeNode()

    LeftData, RightData = splitContinuousDataSet(dataset, bestDim, bestValue)

    LeftTData, RightTData = splitContinuousDataSet(testdata, bestDim, bestValue)

 

    # left

    if (len(LeftTData) > 0 and len(LeftTData[0]) > 0):

        classListleft = [example[-1] for example in LeftTData]

        leftValue = majorityCnt(classListleft)

        for dt in LeftTData:

            if (dt[-1] == leftValue):

                count2 += 1

 

    # right

    if (len(RightTData) > 0 and len(RightTData[0]) > 0):

        classListright = [example[-1] for example in RightTData]

        rightValue = majorityCnt(classListright)

        for dt in RightTData:

            if (dt[-1] == rightValue):

                count2 += 1

 

    if (count1 < count2):

        if (len(LeftData) > 0):

            precutting(LeftData, leftTree, LeftTData)

        if (len(RightData) > 0):

            precutting(RightData, rightTree, RightTData)

        tree.setLeft(leftTree)

        tree.setRight(rightTree)

K.  后剪枝操作,首先是用create方法生成一个树,然后进行后剪枝。从底层节点向上开始考虑,如果该节点的dim值为-1 则返回,之后对上一层进行正确率的判断。在找叶子节点的同时,也将测试集分成了两个部分。然后计算这个节点分支后的正确率和不让这个节点分支的正确率,如果前者的正确率大,则将该节点的dim设置为-1,也就是直接把这个节点变成了叶子:

   def posttree(tree, testdata):

    # 找到叶子节点

    if (tree.getdim() == -1):

        return

    else:

        lefttest, righttest = splitContinuousDataSet(testdata, tree.getdim(), tree.getValue())

        if len(lefttest) > 0:

            posttree(tree.getRight(), lefttest)

        if len(righttest) > 0:

            posttree(tree.getRight(), righttest)

        cout1 = 0

        cout2 = 0

 

        classlist1 = [example[-1] for example in testdata]

        Value = majorityCnt(classlist1)

        for ex in testdata:

            if (ex[-1] == Value):

                cout1 += 1

        # left

        if (len(lefttest) > 0 and len(lefttest[0]) > 0):

            classListleft = [example[-1] for example in lefttest]

            leftValue = majorityCnt(classListleft)

            for dt in lefttest:

                if (dt[-1] == leftValue):

                    cout2 += 1

 

 

        # right

        if (len(righttest) > 0 and len(righttest[0]) > 0):

            classListright = [example[-1] for example in righttest]

            leftValue = majorityCnt(classListright)

            for dt in righttest:

                if (dt[-1] == righttest):

                    cout2 += 1

        if (cout1 < cout2):

            return tree.setdim(-1)

L.  进行5折交叉验证。首先使用了random.shuffle方法,将数据集打乱顺序。之后从0-30,30-60,60-90,90-120,120-150,分别作为测试集,用remove方法的到训练集。分别生成树,比较其中的正确率:

    random.shuffle(dataset)

   

    train1 =dataset[:121]

    test1 =dataset[121:]

    train2 =dataset[31:]

    test2 =dataset[:31]

   

    test3=[]

    train3 =dataset[:]

    test4=[]

    train4=dataset[:]

    test5=[]

    train5=dataset[:]

    for i in range(30,60):

        test3.append(dataset[i])

        train3.remove(dataset[i])

    print(len(dataset))

    for i in range(60,90):

        test4.append(dataset[i])

        train4.remove(dataset[i])

    for i in range(90,120):

        test5.append(dataset[i])

        train5.remove(dataset[i])、

实验结果截图:

 

一共测试了四次次,其中第一行为正常构造决策树,第二行为使用后剪枝,第三行为使用预剪枝分别得到的正确的样本个数。总的测试集大小为30。倒数第二行为在测试集和训练集上测试的结果,发现训练集的结果高于测试集。(第一行为训练集本身,第二三行为测试集)

 

实验结果分析:

在原来树的准确率和后剪枝后和预剪枝的准确率上来看(第一行为正常构建的树,第二行为后剪枝后,第三行为预剪枝构造树):这棵树存在过拟合的情况。通过5折交叉验证可以使这棵树的准确率为基本为100%

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值