《机器学习》-决策树源码解析

(1) 收集数据:可以使用任何方法。
(2) 准备数据:树构造算法只适用于标称型数据,因此数值型数据必须离散化。(离散跟随记)
(3) 分析数据:可以使用任何方法,构造树完成之后,我们应该检查图形是否符合预期。
(4) 训练算法:构造树的数据结构。
(5) 测试算法:使用经验树计算错误率。
(6) 使用算法:此步骤可以适用于任何监督学习算法,而使用决策树可以更好地理解数据
的内在含义。

构造数据
def create_dataset():
    dataSet = [[1, 1, 'yes'],
               [1, 1, 'yes'],
               [1, 0, 'no'],
               [0, 1, 'no'],
               [0, 1, 'no']]
    labels = ['no surfacing', 'flippers']#这两个代表是特征名称的集合,也就是特征1,特征2
    return dataSet, labels
计算信息期望
def calc_shannon_ent(dataSet):
    num_entries = len(dataSet)
    label_counts = {}
    # 为所有可能分类创建字典
    for featVec in dataSet:#统计是鱼的次数,统计不是鱼的次数
        current_label = featVec[-1]#拿到分类的值,是否鱼类
        if current_label not in label_counts.keys():
            label_counts[current_label] = 0
        label_counts[current_label] += 1
    shannoent = 0.0#信息期望值
    # 以二为底求对数
    for key in label_counts:
        prob = float(label_counts[key])/num_entries
        shannoent -= prob * math.log(prob, 2)#所有可能性的信息增益就是得到信息期望值
    return shannoent
切割数据急的函数
def split_dataset(dataSet, axis, value):#选择当前特征属性分类的情况,不懂的可以debug看一下
    # 创建新的list对象
    retdataSet = []
    for featVec in dataSet:
        if featVec[axis] == value:#如果第一行的三维数组第一个特征等于1的话
            reducedFeatVec = featVec[:axis]
            reducedFeatVec.extend(featVec[axis+1:])
            retdataSet.append(reducedFeatVec)
    return retdataSet
依次计算特征1跟特征2的信息增益,得出信息增益最大的特征
def choose_best(dataSet):
    numFeatures = len(dataSet[0]) - 1
    baseEntropy = calc_shannon_ent(dataSet)#最开始的信息期望值
    bestInfoGain = 0.0#最佳信息增益
    bestFeature = -1#最佳特征
    # 创建唯一分类标签
    for i in range(numFeatures):
        featList = [example[i] for example in dataSet]#每个特征属性组成的列表
        uniqueValis = set(featList)#看特征1区分成几种
        newEntropy = 0.0#最初的信息期望值
        # 计划每种划分的信息墒
        for value in uniqueValis:
            subDataSet = split_dataset(dataSet, i ,value)
            prob = len(subDataSet)/float(len(dataSet))
            newEntropy += prob * calc_shannon_ent(subDataSet)
            infoGain = baseEntropy - newEntropy
            # 计算最好的增益墒
            if infoGain > bestInfoGain:
                bestInfoGain = infoGain
                bestFeature = i
    return bestFeature
构建决策树
def majoritycnt(classList):
    classCount = {}
    for vote in 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
def create_tree(dataSet, labels):
    classList = [example[-1] for example in dataSet]#[yes,yes,no,no,no]
    if classList.count(classList[0]) == len(classList):#如果所有的数据只有一种类别,就直接停止分类了

        # 停止分类直至所有类别相等
        return classList[0]
    if len(dataSet[0]) == 1:#代表此时数据里只剩下最后一列,也就是我们的类别列,没有特征给我们继续往下分了,所以就采取投票法
        # 停止分割直至没有更多特征
        return majoritycnt(classList)
    bestfaet = choose_best(dataSet)#首先通过计算得根结点特征
    bestfaetlabel = labels[bestfaet]#拿到根结点的特征名称
    mytree = {bestfaetlabel:{}}
    del(labels[bestfaet])
    print(labels)

    # 得到包含所有属性的列表
    featvalues = [example[bestfaet] for example in dataSet]#拿到特征1的所有取值情况[1,1,1,0,0]
    uniquevalues = set(featvalues)#发现no surfacing特征只有两种选择,1,0
    for value in uniquevalues:#遍历这两种特征,其实也就是把这两种特征切割成两个子树出来,俗称递归
        sublables = labels[:]#剩下的就去切分第二个特征了
        mytree[bestfaetlabel][value] = create_tree(split_dataset(dataSet, bestfaet, value), sublables)

    return mytree
决策树的分类

def classify(inputtree, featlabels, testvec):#参数分别代表决策树,特征名称,特征向量[mytree,labels,[1,0]]
    firststr = list(inputtree.keys())[0]
    print(firststr)
    seconddict = inputtree[firststr]#看它下面还有没有字典可以分
    print(seconddict)
    featindex = featlabels.index(firststr)
    key = testvec[featindex]
    valueoffeat = seconddict[key]
    if isinstance(valueoffeat, dict):#isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()。
        classlabel = classify(valueoffeat, featlabels, testvec)
    else:
        classlabel = valueoffeat
    return classlabel
决策树模型的加载跟存储
def store_tree(inputtree, filename):#把模型存储起来
    fw = open(filename, 'w')
    pickle.dump(inputtree, fw)
    fw.close()


def grab_tree(filename):#加载模型
    import pickle
    fr = open(filename)
    return pickle.load(fr)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,039评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,426评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,417评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,868评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,892评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,692评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,416评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,326评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,782评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,957评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,102评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,790评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,442评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,996评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,113评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,332评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,044评论 2 355

推荐阅读更多精彩内容