기사 디렉토리
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