의사 결정 트리 - 과일 특성에 따른 분류

1. 데이터 세트 가져오기

과일 중에서 사과와 카람볼라가 상대적으로 뚜렷한 외형적 특징을 가지고 있는데, 예를 들어 다음 두 개의 사과와 카람볼라 사진에서 사과는 붉고 모양이 대략 타원형이며 모서리가 없이 매끈하고 잎이 있다. 오각형 모양이며 모서리가 있다. , 잎이 없다.
여기에 이미지 설명 삽입
위의 특성을 사용하여 일부 사과 및 카람볼라 데이터를 계산합니다.

  • 색상: 1-빨간색 0-노란색
  • 모양: 1-타원 0-오각형
  • 에지: 1-에지 포함 0-에지 없음
  • 잎 있음: 1-잎 있음 0-잎 없음

여기에 이미지 설명 삽입

1. 데이터 추출


여기에 이미지 설명 삽입
CSV 라이브러리를 이용하여 지정된 특징을 분류하고, 첫 번째 행을 제외한 데이터를 추출하여 본 실험의 데이터셋으로 사용한다. 각각의 상황에 대응하여 라벨에 저장됩니다.
여기에 이미지 설명 삽입

# 获取数据集
def createDataSet(filename):
    # 读取文件
    data = open(filename, 'rt', encoding='gbk')
    reader = csv.reader(data)
    # 获取标签列
    handlers = next(reader)
    lables = handlers[:-1]
    # 数据列表
    dataSet = []

    for row in reader:
        # 读取除第一行的数据
        dataSet.append(row[:])
        
    # 特征对应的所有可能的情况
    labels_full = {
    
    }
    for i in range(len(lables)):
        labelList = [example[i] for example in dataSet]
        uniqueLabel = set(labelList)
        labels_full[lables[i]] = uniqueLabel
    return dataSet, lables, labels_full

2. 데이터 분할

dataSet에 의해 입력된 데이터의 경우 axis는 레이블의 해당 좌표이고 value는 해당 속성 아래의 속성 값입니다.

# 划分数据集  
def splitDataSet(dataSet, axis, value):
    retDataSet = []
    for featVec in dataSet:
        # 给定特征值等于想要的特征值
        if featVec[axis] == value:
            reducedFeatVec = featVec[:axis]
            # 将该特征值后面的内容保存起来
            reducedFeatVec.extend(featVec[axis + 1:])
            retDataSet.append(reducedFeatVec)

    return retDataSet
print(splitDataSet(dataSet, 1, '0'))

다수의Cnt 메소드를 사용하여 컬렉션에서 가장 많이 발생하는 레이블을 가져옵니다.

# 获取出现次数最多的类别
def majorityCnt(classList):
    classCount = collections.defaultdict(int)
    # 遍历所有的类别
    for vote in classList:
        classCount[vote] += 1
    # 降序排序,第一行第一列就是最多的
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

둘째, 정보 이득을 계산

1. 정보 엔트로피

먼저 모든 데이터 길이를 가져온 다음 사전을 만들고 키 값은 마지막 열 값입니다. 각 키 값은 현재 카테고리의 발생 횟수를 기록하고 마지막으로 모든 클래스 레이블의 발생률을 계산하여 해당 카테고리의 발생률을 계산하고 최종적으로 엔트로피 값을 계산합니다.

# 获取水果信息熵
def calcShannonEnt(dataSet):
    # 总数
    numEntries = len(dataSet)
    # 用来统计标签
    labelCounts = collections.defaultdict(int)
    # 循环整个数据集,得到数据的分类标签
    for featVec in dataSet:
        # 得到当前的标签
        currentLabel = featVec[-1]
        labelCounts[currentLabel] += 1
    # 计算信息熵
    shannonEnt = 0.0
    for key in labelCounts:
        prob = float(labelCounts[key]) / numEntries
        shannonEnt -= prob * log(prob, 2)
    return shannonEnt

2. 정보 이득 계산

정보 획득량을 계산하기 위해서는 먼저 최종 과일 분류를 제외한 모든 특징의 수를 구한 다음 각 특징에 해당하는 정보 엔트로피를 계산하고 최종적으로 정보 획득인 특징의 정보 엔트로피에서 분류의 정보 엔트로피를 뺍니다. 해당 기능의. 각 특징의 정보이득을 구한 후 최대값에 해당하는 레이블 첨자를 반환하고 의사결정트리 구축 시 수의 루트 노드로 사용한다.
각 기능에 해당하는 정보 획득, 마지막으로 가장 큰 레이블에 해당하는 첨자를 반환합니다.
여기에 이미지 설명 삽입

# 计算每个特征信息增益
def chooseBestFeatureToSplit(dataSet, labels):
    # 特征数 总的列数减去最后的一列
    numFeatures = len(dataSet[0]) - 1
    baseEntropy = calcShannonEnt(dataSet)
    bestInfoGain = 0.0
    bestFeature = -1
    # 对每个特征值进行求信息熵
    for i in range(numFeatures):
        # 得到数据集中所有的当前特征值列表
        featList = [example[i] for example in dataSet]
        # 当前特征值中共有多少种
        uniqueVals = set(featList)
        newEntropy = 0.0

        # 遍历现在有的特征的可能性
        for value in uniqueVals:
            subDataSet = splitDataSet(dataSet=dataSet, axis=i, value=value)
            prob = len(subDataSet) / float(len(dataSet))
            newEntropy += prob * calcShannonEnt(subDataSet)
        infoGain = baseEntropy - newEntropy

        print( labels[i] + '信息增益值为:' + str(infoGain))
        # 找出最大的值
        if infoGain > bestInfoGain:
            bestInfoGain = infoGain
            bestFeature = i
    return bestFeature
print(chooseBestFeatureToSplit(dataSet, lables))

3. 의사 결정 트리 그리기

사전과 같은 의사 결정 트리를 얻으려면 데이터 세트와 레이블 배열을 입력하십시오.
먼저 모든 데이터 세트의 분류 레이블을 가져온 다음 첫 번째 레이블의 발생 횟수를 세고 총 레이블 수와 비교합니다. 첫 번째 줄에 몇 개의 데이터가 있는지 계산합니다. 하나만 있으면 모든 피처 속성이 통과되었음을 의미하고 나머지 하나는 범주 레이블이거나 모든 샘플이 모든 속성에서 일치한다는 의미이며 숫자를 반환합니다. majorityCnt더 많은 레이블을 사용 하여 나머지 레이블의 발생 수 . 가장 좋은 분할 기능을 선택한 후 chooseBestFeatureToSplit기능의 첨자를 루트 노드로 가져옵니다. 마지막으로 재귀적으로 호출하여 데이터셋에서 현재의 특징값과 같은 특징을 가진 모든 데이터를 현재 노드로 나누는데, 재귀적으로 호출할 때는 현재 특징을 먼저 제거해야 한다.

# 绘制决策树
def createTree(dataSet, labels):
    classList = [example[-1] for example in dataSet]
    print(classList)
    # 统计第一个标签出现的次数,与总标签个数比较
    if classList.count(classList[0]) == len(classList):
        return classList[0]

    if len(dataSet[0]) == 1 :
        # 返回剩下标签中出现次数较多的那个
        return majorityCnt(classList)

    bestFeat = chooseBestFeatureToSplit(dataSet=dataSet, labels=labels)
    bestFeatLabel = labels[bestFeat]

    myTree = {
    
    bestFeatLabel: {
    
    }}

    # 将本次划分的特征值从列表中删除掉
    del(labels[bestFeat])
    featValues = [example[bestFeat] for example in dataSet]
    uniqueVals = set(featValues)

    # 遍历所有的特征值
    for value in uniqueVals:
        subLabels = labels[:]
        subTree = createTree(splitDataSet(dataSet=dataSet, axis=bestFeat, value=value), subLabels)
        # 递归调用
        myTree[bestFeatLabel][value] = subTree
    return myTree
print(createTree(dataSet, lables))

사전 모양의 결정 트리를 가져옵니다.

{'带叶': 
    {'1': {'形状': 
            {'1': '苹果', 
            '0': {'棱角': 
                {'1': '杨桃', 
                 '0': '苹果'}}}}, 
     '0': {'棱角': 
            {'1': '杨桃', 
             '0': {'颜色': 
                {'1': {'形状': {'杨桃': '杨桃', '苹果': '苹果'}}, 
                 '0': {'形状': {'杨桃': '杨桃', '苹果': '苹果'}}}}}}}}

4. 분류 예측

클래스 예측은 인덱스 메서드를 사용하여 현재 목록에서 firstStr 변수와 일치하는 첫 번째 요소를 찾는 재귀 함수이기도 합니다. 그런 다음 전체 트리를 재귀적으로 순회하고 testVec 변수의 값을 트리 노드의 값과 비교하고 리프 노드에 도달하면 분류 레이블을 반환합니다.

# 预测
def classify(inTree, featLabel, testVec):
    # 获取第一个节点
    firstStr = list(inTree.keys())[0]
    secondDict = inTree[firstStr]
    # 节点对应下标
    featIndex = featLabel.index(firstStr)
    for key in secondDict.keys():
        if testVec[featIndex] == key:
            # 递归判断
            if type(secondDict[key]).__name__ == 'dict':
                classLabel = classify(secondDict[key], featLabel, testVec)
            else: classLabel = secondDict[key]
    # 返回预测
    return classLabel

시험 결과:
여기에 이미지 설명 삽입

코드:
링크: https://pan.baidu.com/s/1gjbXKDworG7ejzS6cCTvgQ?pwd=kupj
추출 코드: kupj

추천

출처blog.csdn.net/chenxingxingxing/article/details/127837664