天天看點

利用決策樹算法在鮑魚資料集上對年齡進行預測前言一、 資料集二、步驟三.預測總結參考文章:

在上一篇文章中,通過調取sklearn庫中的tree子產品來建構在鮑魚資料集上的決策樹,并對測試集鮑魚的年齡進行預測,但是,通過調庫的方式隻能處理數值型的屬性,若資料集中既包含連續型屬性和離散型屬性,則處理起來比較困難。而在本文中,将具體實作決策樹的建構過程,并能分别處理連續型屬性和離散型屬性,最後對 鮑魚資料集 中的鮑魚年齡進行預測。

目錄

前言

一、 資料集

二、步驟

 1.引入庫

 2.讀入資料

 3.資料預處理

 4.計算資訊增益

 5.劃分資料集

 6.計算最優劃分屬性

 7.建構決策樹

三.預測

總結

參考文章:

前言

 本文将具體實作決策樹的建構過程,并對 鮑魚資料集 中的鮑魚年齡進行預測。

以下是本篇文章正文内容

一、 資料集

訓練集:

利用決策樹算法在鮑魚資料集上對年齡進行預測前言一、 資料集二、步驟三.預測總結參考文章:

測試集:

利用決策樹算法在鮑魚資料集上對年齡進行預測前言一、 資料集二、步驟三.預測總結參考文章:

資料集下載下傳:

訓練集:https://pan.baidu.com/s/1f4yf9vlndVar2J4cLqfjDg         提取碼:U1S1

測試集:https://pan.baidu.com/s/1QQxqDsyoSrs529H49LLg2g         提取碼:U2S2

二、步驟

 1.引入庫

代碼如下:(當然有些沒有用到)

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics import precision_score
from scipy.stats import multivariate_normal
from mpl_toolkits.mplot3d import Axes3D
import copy
           

 2.讀入資料

代碼如下:

# 讀取資料
train_datas=pd.read_csv(path1,header=None)
test_datas=pd.read_csv(path2,header=None)
           

path為檔案路徑

 3.資料預處理

#轉換成清單
train_data=np.array(train_datas[1:][:]).tolist()
label=train_datas[:1][:]
labels=np.array(label).tolist()[0][:-1]
labelProperties = [0, 1, 1, 1, 1, 1, 1, 1]  # 屬性的類型,0表示離散,1表示連續

test_data=test_datas.drop(columns=[8])
#轉換成清單
testData=np.array(test_data[1:][:]).tolist()
           

 4.計算資訊增益

def cal_Ent(dataSet):
    # 計算Ent(D)
    
    # 訓練集大小
    length=len(dataSet)
    
    # 标簽字典
    Ent_D_dict={}
    for data in dataSet:
        label=data[-1]
        if label in Ent_D_dict:
            Ent_D_dict[label]+=1
        else:
            Ent_D_dict[label]=1
    Ent_D=0
    for i in Ent_D_dict.values():
        odd=i/length
        Ent_D-=odd*np.log2(odd)
    return Ent_D
           

 5.劃分資料集

(連續型屬性):

# 劃分資料集, axis:按第幾個特征劃分, value:劃分特征的值, LorR: value值左側(小于)或右側(大于)的資料集
def splitDataSet_c(dataSet, axis, value, LorR='L'):
    retDataSet = []
    featVec = []
    if LorR == 'L':
        for featVec in dataSet:
            if float(featVec[axis]) < value:
                retDataSet.append(featVec)
    else:
        for featVec in dataSet:
            if float(featVec[axis]) > value:
                retDataSet.append(featVec)
    return retDataSet
           

(離散型屬性):

def splitDataSet(dataSet, axis, value):
    retDataSet = []                                     #建立傳回的資料集清單
    for featVec in dataSet:                             #周遊資料集
        if featVec[axis] == value:
            reducedFeatVec = featVec[:axis]             #去掉axis特征
            reducedFeatVec.extend(featVec[axis+1:])     #将符合條件的添加到傳回的資料集
            retDataSet.append(reducedFeatVec)
    return retDataSet 
           

 6.計算最優劃分屬性

# 選擇最好的資料集劃分方式
def chooseBestFeatureToSplit_c(dataSet, labelProperty):
    numFeatures = len(labelProperty)  # 特征數
    baseEntropy = cal_Ent(dataSet)  # 計算根節點的資訊熵
    bestInfoGain = 0.0
    bestFeature = -1
    bestPartValue = None  # 連續的特征值,最佳劃分值
    for i in range(numFeatures):  # 對每個特征循環
        featList = [example[i] for example in dataSet]
        uniqueVals = set(featList)  # 該特征包含的所有值
        newEntropy = 0.0
        bestPartValuei = None
        if labelProperty[i] == 0:  # 對離散的特征
            for value in uniqueVals:  # 對每個特征值,劃分資料集, 計算各子集的資訊熵
                subDataSet = splitDataSet(dataSet, i, value)
                prob = len(subDataSet) / float(len(dataSet))
                newEntropy += prob * cal_Ent(subDataSet)
        else:  # 對連續的特征
            sortedUniqueVals = list(uniqueVals)  # 對特征值排序
            sortedUniqueVals.sort()
            listPartition = []
            minEntropy = float("inf")
            for j in range(len(sortedUniqueVals) - 1):  # 計算劃分點
                partValue = (float(sortedUniqueVals[j]) + float(
                    sortedUniqueVals[j + 1])) / 2
                # 對每個劃分點,計算資訊熵
                dataSetLeft = splitDataSet_c(dataSet, i, partValue, 'L')
                dataSetRight = splitDataSet_c(dataSet, i, partValue, 'R')
                probLeft = len(dataSetLeft) / float(len(dataSet))
                probRight = len(dataSetRight) / float(len(dataSet))
                Entropy = probLeft * cal_Ent(
                    dataSetLeft) + probRight * cal_Ent(dataSetRight)
                if Entropy < minEntropy:  # 取最小的資訊熵
                    minEntropy = Entropy
                    bestPartValuei = partValue
            newEntropy = minEntropy
        infoGain = baseEntropy - newEntropy  # 計算資訊增益
        print("第%d個特征的增益為%.3f" % (i, infoGain))             #列印每個特征的資訊增益
        if infoGain > bestInfoGain:  # 取最大的資訊增益對應的特征
            bestInfoGain = infoGain
            bestFeature = i
            bestPartValue = bestPartValuei
    return bestFeature, bestPartValue
           
def majorityCnt(classList):
    classCount = {}
    for vote in classList:                                        #統計classList中每個元素出現的次數
        if vote not in classCount.keys():
            classCount[vote] = 0
        classCount[vote] += 1
    sortedClassCount = sorted(classCount.items(), key = operator.itemgetter(1), reverse = True)        #根據字典的值降序排序
    return sortedClassCount[0][0]
           

 7.建構決策樹

# 建立樹, 樣本集 特征 特征屬性(0 離散, 1 連續)
def createTree_c(dataSet, labels, labelProperty):
    print("---------------------------------------------")
    # print dataSet, labels, labelProperty
    classList = [example[-1] for example in dataSet]  # 類别向量
    if classList.count(classList[0]) == len(classList):  # 如果隻有一個類别,傳回
        return classList[0]
    if len(dataSet[0]) == 1:  # 如果所有特征都被周遊完了,傳回出現次數最多的類别
        return majorityCnt(classList)
    bestFeat, bestPartValue = chooseBestFeatureToSplit_c(dataSet,
                                                        labelProperty)  # 最優分類特征的索引
    if bestFeat == -1:  # 如果無法選出最優分類特征,傳回出現次數最多的類别
        return majorityCnt(classList)
    if labelProperty[bestFeat] == 0:  # 對離散的特征
        bestFeatLabel = labels[bestFeat]
        myTree = {bestFeatLabel: {}}
        labelsNew = copy.copy(labels)
        labelPropertyNew = copy.copy(labelProperty)
        del (labelsNew[bestFeat])  # 已經選擇的特征不再參與分類
        del (labelPropertyNew[bestFeat])
        featValues = [example[bestFeat] for example in dataSet]
        uniqueValue = set(featValues)  # 該特征包含的所有值
        for value in uniqueValue:  # 對每個特征值,遞歸建構樹
            subLabels = labelsNew[:]
            subLabelProperty = labelPropertyNew[:]
            myTree[bestFeatLabel][value] = createTree_c(
                splitDataSet(dataSet, bestFeat, value), subLabels,
                subLabelProperty)
    else:  # 對連續的特征,不删除該特征,分别建構左子樹和右子樹
        bestFeatLabel = labels[bestFeat] + '<' + str(bestPartValue)
        myTree = {bestFeatLabel: {}}
        subLabels = labels[:]
        subLabelProperty = labelProperty[:]
        # 建構左子樹
        valueLeft = '是'
        myTree[bestFeatLabel][valueLeft] = createTree_c(
            splitDataSet_c(dataSet, bestFeat, bestPartValue, 'L'), subLabels,
            subLabelProperty)
        # 建構右子樹
        valueRight = '否'
        myTree[bestFeatLabel][valueRight] = createTree_c(
            splitDataSet_c(dataSet, bestFeat, bestPartValue, 'R'), subLabels,
            subLabelProperty)
    return myTree
           
Trees = createTree_c(train_data, labels, labelProperties)
           

 運作結果:

利用決策樹算法在鮑魚資料集上對年齡進行預測前言一、 資料集二、步驟三.預測總結參考文章:

三.預測

# 測試算法
def classify_c(inputTree, featLabels, featLabelProperties, testVec):
    firstStr = list(inputTree.keys())[0]  # 根節點
    firstLabel = firstStr
    lessIndex = str(firstStr).find('<')
    if lessIndex > -1:  # 如果是連續型的特征
        firstLabel = str(firstStr)[:lessIndex]
    secondDict = inputTree[firstStr]
    featIndex = featLabels.index(firstLabel)  # 跟節點對應的特征
    classLabel = None
    for key in secondDict.keys():  # 對每個分支循環
        if featLabelProperties[featIndex] == 0:  # 離散的特征
            if testVec[featIndex] == key:  # 測試樣本進入某個分支
                if type(secondDict[key]).__name__ == 'dict':  # 該分支不是葉子節點,遞歸
                    classLabel = classify_c(secondDict[key], featLabels,
                                           featLabelProperties, testVec)
                else:  # 如果是葉子, 傳回結果
                    classLabel = secondDict[key]
        else:
            partValue = float(str(firstStr)[lessIndex + 1:])
#             print(testVec[featIndex],partValue)
            if float(testVec[featIndex]) < partValue:  # 進入左子樹
                if type(secondDict['是']).__name__ == 'dict':  # 該分支不是葉子節點,遞歸
                    classLabel = classify_c(secondDict['是'], featLabels,
                                           featLabelProperties, testVec)
                else:  # 如果是葉子, 傳回結果
                    classLabel = secondDict['是']
            else:
                if type(secondDict['否']).__name__ == 'dict':  # 該分支不是葉子節點,遞歸
                    classLabel = classify_c(secondDict['否'], featLabels,
                                           featLabelProperties, testVec)
                else:  # 如果是葉子, 傳回結果
                    classLabel = secondDict['否']
    return classLabel
           
for i in range(len(testData)):
    testClass = classify_c(Trees, labels, labelProperties, testData[i])
    print("第",i,"條測試資料的預測ring為:",testClass)
           
利用決策樹算法在鮑魚資料集上對年齡進行預測前言一、 資料集二、步驟三.預測總結參考文章:

 與調庫的方法進行對比:

參考上一篇文章:

https://blog.csdn.net/qq_53644346/article/details/125101128?spm=1001.2014.3001.55yixai

利用決策樹算法在鮑魚資料集上對年齡進行預測前言一、 資料集二、步驟三.預測總結參考文章:

https://blog.csdn.net/qq_53644346/article/details/125101128?spm=1001.2014.3001.5501

調庫預測的結果:

利用決策樹算法在鮑魚資料集上對年齡進行預測前言一、 資料集二、步驟三.預測總結參考文章:

 發現結果一樣!

總結

以上就是實作決策樹算法的所有内容,當然以上算法也可以處理其他的資料集,無論是離散屬性和連續屬性都可以處理。

參考文章: