掰开揉碎机器学习系列-决策树(2)-CART决策树

    xiaoxiao2021-12-14  22

    一、CART决策树和ID3决策树的区别在哪里:

    区别主要体现在对于连续型特征的处理方式,ID3决策树完全根据特征值等于几,做决策分支,这肯定容易出现很多很多分支,即所谓过拟合。

    CART决策树在一定程度上缓解了这个问题,比如对于样本S的特征A的特征值1、2、3、4、5、6,如果是ID3决策树,那么可能会有6个分支,而对于CART决策树,只会有2个分支,如"特征A是否大于3.5",这也就是所谓CART决策树是一个二叉树,他对于连续型特征,只做二分切分。

    CART和ID3的另一个区别是,CART使用基尼系数而不是熵,作为判断概率分布是否集中的标准。

    二、CART决策树实现:

    区别于ID3的主要是两个内容,一个是基尼系数,一个是连续型特征如何做分叉

    1、基尼系数:

    gini(A = AX) = 1 - sum(p(i) * p(i))

    即特征A在取值AX时,1减去各个结果i的概率p(i)的乘积

    基尼系数越小,反映概率分布越平稳,应优先作为分叉的特征。

    2、连续型特征如何分叉:

    对该特征A的所有特征值A1-AN排序,每两个特征值获取平均值,取得N-1个有序平均值,计算每个平均值的样本数据子集的基尼系数,取其中最小者,对所有特征均做此计算,基尼系数最小的特征及其最小基尼系数的平均值,作为分叉条件

    如样本S的特征A的特征值1、2、3、4、5、6,并计算得平均值3,.5的样本数据子集的基尼系数最低,特征B的特征值1、2、3、4、5、6,并计算得平均值1,.5的样本数据子集的基尼系数最低,特征C的特征值1、2、3、4、5、6,并计算得平均值2,.5的样本数据子集的基尼系数最低.........最后得出最低基尼系数为特征A的平均值3.5,那么特征A是否大于3.5,作为分叉特征条件。

    本例中,离散型特征同样计算基尼系数并和连续型特征一起参与比较,计算方式和ID3一样。

    3、实现

    #coding: utf8 from numpy import * import pandas as pd from math import log import operator from treeplot import * import sys def vote (dataset): map = {} for data in dataset: if map.has_key(data): map[data] += 1 else: map[data] = 1 max = -1 best = 0 for data in map: cnt = map[data] if max < cnt: max = cnt best = data return best def calcgini (dataset): results = [data[-1] for data in dataset] map = {} for result in results: if map.has_key(result): map[result] += 1 else: map[result] = 1 gini = 1.0 for result in map: cnt = map[result] p = float(cnt) / len(dataset) gini -= p * p return gini def splitdata_disper (dataset, i, value): splitdata = [] for data in dataset: curvalue = data[i] if curvalue == value: tmp = data[:i] tmp.extend(data[i + 1:]) splitdata.append(tmp) return splitdata def splitdata_contigus (dataset, i, value, flag): splitdata = [] for data in dataset: curvalue = data[i] if flag == 0: if curvalue > value: leftpart = data[:i] leftpart.extend(data[i + 1:]) splitdata.append(leftpart) else: if curvalue <= value: leftpart = data[:i] leftpart.extend(data[i + 1:]) splitdata.append(leftpart) return splitdata def getaverages (values): sorted_values = sorted(values) averages = [] for i in range(len(sorted_values) - 1): average = float(sorted_values[i] + sorted_values[i + 1]) / 2 averages.append(average) return averages def get_type (data): if type(data).__name__ in ['float', 'int', 'long']: return 1 else: return 0 def choose_bestfeature (dataset, labels): sum = len(dataset) bestgini = 100000.0 bestfeatureidx = -1 bestvalue_contigus = 0.0 type = 0 #遍历每一种特征 for i in range(len(labels)): values = [data[i] for data in dataset] type = get_type(values[0]) #如果是连续型,首先计算出所有连续特征值的排序后交叉均值 #然后按这些均值为界,依次计算不同拆分结果的基尼系数,取基尼系数最小者 if type == 1: averages = getaverages(values) mingini_contigus = 100000.0 bestvalue = 0.0 for average in averages: lesspart = splitdata_contigus(dataset, i, average, 0) lesspart_p = float(len(lesspart)) / sum leftpart_gini = lesspart_p * calcgini(lesspart) morepart = splitdata_contigus(dataset, i, average, 1) morepart_p = float(len(morepart)) / sum morepart_gini = morepart_p * calcgini(morepart) gini = leftpart_gini + morepart_gini if gini < mingini_contigus: mingini_contigus = gini bestvalue = average if mingini_contigus < bestgini: bestfeatureidx = i bestvalue_contigus = bestvalue type = 1 #如果是离散型,直接取基尼系数最小者的特征 else: mingini_disper = 100000.0 values = set(values) for value in values: otherpart = splitdata_disper(dataset, i, value) p = float(len(otherpart)) / len(dataset) gini = p * calcgini(otherpart) if gini < mingini_disper: mingini_disper = gini if mingini_disper < bestgini: bestfeatureidx = i type = 0 #如果是连续性特征作为最优特征,要做二值化,就是根据是否大于最优均值,将标签名称和数据,都做二值化 #为什么要做二值化,不是三值化,四值化?因为标准CART决策树是一个二叉树,就是根据每个连续型特征是否大于某值来分叉 if type == 1: labels[bestfeatureidx] = labels[bestfeatureidx] + " > " + str(bestvalue_contigus) for data in dataset: curvalue = data[bestfeatureidx] if data[bestfeatureidx] > bestvalue_contigus: data[bestfeatureidx] = 1 else: data[bestfeatureidx] = 0 return bestfeatureidx def createtree (dataset, labels): results = [data[-1] for data in dataset] #只剩下一种结果时, if len(results) == results.count(results[0]): return results[0] #只剩下结果没有特征了 if len(dataset[0]) == 1: return vote(results) bestfeatureidx = choose_bestfeature(dataset, labels) bestfeature = labels[bestfeatureidx] label = labels[bestfeatureidx] tree = {label:{}} del(labels[bestfeatureidx]) bestfeaturevalues = set(data[bestfeatureidx] for data in dataset) for value in bestfeaturevalues: splitdata = splitdata_disper(dataset, bestfeatureidx, value) splitlabels = labels[:] if splitdata == []: continue tree[label][value] = createtree(splitdata, splitlabels) return tree df = pd.read_table('nba.txt', sep = '\t') #数据源,第一行是标题略过,第一列是球员名字略过 dataset = df.values[0:,1:].tolist() labels = ['score', 'allscore', 'hitratio', 'threeratio', 'penaltyratio', 'time', 'count ', 'clublevel'] tree = createtree(dataset, labels) createPlot(tree)

    训练样本数据,以NBA球员当前的各方面数据(同时包括连续型和离散型特征),以及自设定的其球员档次等级:

    name score allscore hitratio threeratio penaltyratio time count clublevel tag 安东尼-戴维斯 31.6 537 51.9 28.2 81.3 37.2 17 Middle 1.5 拉塞尔-威斯布鲁克 31.2 561 43.5 33.7 81.3 35.4 18 Middleupper 1.5 德玛尔-德罗赞 30.2 483 48.8 25.8 80.9 36.8 16 Middle 2 詹姆斯-哈登 28.9 491 45.9 36.3 83.4 37 17 Middleupper 1.5 德马库斯-考辛斯 28.3 481 47.2 40.8 76.9 33.7 17 Middle 1.5 达米安-利拉德 28.2 536 46.3 36.6 89.6 35.7 19 Middle 2 凯文-杜兰特 27.2 462 57.4 44.6 83.8 34.4 17 upper 1 斯蒂芬-库里 26.7 454 50.2 42.5 92.9 33.3 17 upper 1 伊赛亚-托马斯 26.1 417 43.2 33.6 87.6 33.1 16 lower 2.5 吉米-巴特勒 25.8 413 49 42.6 88.7 35.2 16 Middleupper 1.5 考瓦伊-莱昂纳德 24.8 421 46.2 38.6 92.5 34.2 17 upper 1.5 凯里-欧文 24.8 372 49 43.3 84 33.9 15 upper 2 肯巴-沃克 24.5 392 46.9 41.1 79.6 33.4 16 Middle 2.5 勒布朗-詹姆斯 23.6 331 49.8 36.1 74.2 36.1 14 upper 1 安德鲁-维金斯 23.5 376 43 39.1 76.7 36.4 16 Middle 2.5 约翰-沃尔 23.5 305 45.4 38.1 81.6 34.2 13 Middle 2 卡梅罗-安东尼 23 368 45.4 34.7 86.8 33.8 16 Middle 1.5 凯文-勒夫 22.3 335 45.4 43 86.5 31.7 15 upper 1.5 C.J.-迈克科伦姆 22.3 424 47.3 44.5 91 34.6 19 Middle 2.5 吉安尼斯-安特托孔波 22 330 51.4 18.8 78.7 34.7 15 Middle 2 卡尔-安东尼-唐斯 21.1 338 49.1 39.4 71 34.7 16 Middle 2 布雷克-格里芬 21.1 380 48.7 22.2 77.4 33.1 18 upper 1.5 乔治-希尔 20.9 188 55.2 47.1 86.7 32.7 9 Middle 2 克里斯塔普斯-波尔津吉斯 20.9 335 49 40 78.6 33.3 16 Middle 2.5 哈里森-巴恩斯 20.8 332 46 28.6 87.1 37.3 16 Middle 2.5 保罗-乔治 20.8 249 43.9 37.2 93 34.9 12 Middleupper 1.5 运行结果如下:可以发现分叉还是比较多。

    转载请注明原文地址: https://ju.6miu.com/read-964041.html

    最新回复(0)