机器学习算法原理总结系列---算法基础之(2)决策树(Decision Tree)

来源:互联网 发布:淘宝头条 编辑:程序博客网 时间:2024/05/22 12:45

一、原理详解

决策树是一个类似于流程图的树结构。其中,每个内部结点表示在一个属性上的测试,每个分支代表一个属性输出,而每个树叶结点代表类或类分布。树的最顶层是根结点。
这里写图片描述
机器学习中分类方法中的一个重要算法

构造决策树的基本算法:

  1. 熵(entropy)的概念:
    信息和抽象,如何度量?
    1948年,香农提出了”信息熵(entropy)”的概念。
    一条信息的信息量大小和它的不确定性有直接的关系,要搞清楚一件非常非常不确定的事情,或者是我们一无所知的事情,需要了解大量信息==>信息量的度量就等于不确定性的多少

    比特(bit)来衡量信息的多少,信息的不确定性越大,熵也就越大;反过来说也是一样的,熵越大,信息的不确定性就越大。
    那到底是怎么度量的呢?数学家永远喜欢用一个等式表达他们的思想,计算熵的公式为:这里写图片描述

  2. 决策树归纳算法 (ID3)
    根据entropy来确定的决策树算法其实也被叫做ID3算法。
    1970-1980, J.Ross. Quinlan, ID3算法

    选择属性判断结点

    信息获取量(Information Gain):Gain(A) = Info(D) - Infor_A(D)
    通过A来作为节点分类获取了多少信息

    实战例子:
    这里写图片描述
    任务:现在有14个人买电脑的实际数据,数据中体现的特征有每个人的年龄,收入,是否为学生,信用度。现在根据这些信息和属性来构建一个决策树,然后进行分类预测。再来一个人的话,可以有科学依据的进行预测到底买不买电脑。

    那么根据entropy来计算的过程是这样的:
    这里写图片描述
    这里写图片描述
    这里写图片描述
    类似,Gain(income) = 0.029, Gain(student) = 0.151, Gain(credit_rating)=0.048

    所以,选择age作为第一个根节点:
    这里写图片描述

    然后重复这个求entropy的过程,接着继续去画分支,最后在终止条件下结束,也就画成了决策树。

  3. 算法步骤归纳

    1. 树以代表训练样本的单个结点开始(步骤1)。

    2. 如果样本都在同一个类,则该结点成为树叶,并用该类标号(步骤2 和3)。

    3. 否则,算法使用称为信息增益的基于熵的度量作为启发信息,选择能够最好地将样本分类的属性(步骤6)。该属性成为该结点的“测试”或“判定”属性(步骤7)。
    4. 在算法的该版本中,所有的属性都是分类的,即离散值。连续属性必须离散化。
    5. 对测试属性的每个已知的值,创建一个分枝,并据此划分样本(步骤8-10)。
    6. 算法使用同样的过程,递归地形成每个划分上的样本判定树。一旦一个属性出现在一个结点上,就不必该结点的任何后代上考虑它(步骤13)。
    7. 递归划分步骤仅当下列条件之一成立停止:
      (a) 给定结点的所有样本属于同一类(步骤2 和3)。
      (b) 没有剩余属性可以用来进一步划分样本(步骤4)。在此情况下,使用多数表决(步骤5)。这涉及将给定的结点转换成树叶,并用样本中的多数所在的类标记它。替换地,可以存放结点样本的类分布。
      (c) 分枝
      test_attribute = a i 没有样本(步骤11)。在这种情况下,以 samples 中的多数类创建一个树叶(步骤12)

其他算法:
- C4.5: Quinlan
- Classification and Regression Trees (CART): (L. Breiman, J. Friedman, R. Olshen, C. Stone)
共同点:都是贪心算法,自上而下(Top-down approach)
区别:属性选择度量方法不同: C4.5 gain ratio), CART(gini index), ID3 (Information Gain)

树剪枝叶 (避免overfitting)

  • 先剪枝
  • 后剪枝

决策树的优点:

  • 直观,便于理解,小规模数据集有效

决策树的缺点:

  • 处理连续变量不好
  • 类别较多时,错误增加的比较快
  • 可规模性一般

二、原生代码实现

任务同原理举得例子一样,这里放着全部的代码,笔者也不是全部是自己写的,但是每一行笔者都打印出来,看看实现的逻辑和结果。真心要想弄懂这些的话,100行代码也够你研究几个小时的了。

buy_computer.csv:
这里写图片描述

import csvimport operatorfrom math import logdef read_data():    buy_computer = open('buy_computer.csv', 'r')    reader = csv.reader(buy_computer)    headers = next(reader)    data_set = []    for row in reader:        # 删除将每一行的序号        row.pop(0)        data_set_item = []        # 分别遍历每一行中的所有项,将其转换为数值        for v in row:            if v == 'youth':                v = 0            elif v == 'middle_aged':                v = 1            elif v == 'senior':                v = 2            elif v == 'low':                v = 0            elif v == 'medium':                v = 1            elif v == 'high':                v = 2            elif v == 'no':                v = 0            elif v == 'yes':                v = 1            elif v == 'fair':                v = 0            elif v == 'excellent':                v = 1            data_set_item.append(v)        data_set.append(data_set_item)    return headers[1:], data_setdef calculate_shan(data_set):    """计算数据集的信息熵 (信息熵即指类别标签的混乱程度,值越小越好)"""    data_set_length = len(data_set)    p = {}    H = 0.0    for data in data_set:        current_label = data[-1]  # 获取类别标签        if current_label not in p.keys():  # 若字典中不存在该类别标签,即创建            p[current_label] = 0        p[current_label] += 1  # 递增类别标签的值    for key in p:        px = float(p[key]) / float(data_set_length)  # 计算某个标签的概率        H -= px * log(px, 2)  # 计算信息熵    return Hdef spilt_data(data_set, axis, value):    """    根据某一特征分类数据集    dataSet为要划分的数据集,axis为给定的特征,value为给定特征的具体值    """    sub_dataset = []    for data in data_set:        if data[axis] == value:            sub_data = data[:axis]  # 取出data中第0到axis-1个数进subData;            sub_data.extend(data[axis + 1:])  # 取出data中第axis+1到最后一个数进subData;这两行代码相当于把第axis个数从数据集中剔除掉            sub_dataset.append(sub_data)  # 此处要注意expend和append的区别    return sub_datasetdef choose_best_feature(data_set):    """遍历所有特征,选择信息熵最小的特征,即为最好的分类特征"""    len_feature = len(data_set[0]) - 1  # 计算特征维度时要把类别标签那一列去掉    shan_init = calculate_shan(data_set)  # 计算原始数据集的信息熵    init_value = 0.0    best_feature = 0    for i in range(len_feature):        shan_carry = 0.0        feature = [example[i] for example in data_set]  # 提取第i个特征的所有数据        feature = set(feature)  # 得到第i个特征所有的分类值,如'0'和'1'        for feat in feature:            sub_data = spilt_data(data_set, i, feat)  # 先对数据集按照分类值分类            prob = float(len(sub_data)) / float(len(data_set))            shan_carry += prob * calculate_shan(sub_data)  # 计算第i个特征的信息熵        out_value = shan_init - shan_carry  # 原始数据信息熵与循环中的信息熵的差        if out_value > init_value:            init_value = out_value  # 将信息熵与原始熵相减后的值赋给inValue,方便下一个循环的信息熵差值与其比较            best_feature = i    return best_featuredef majority_cnt(class_list):    """选择列表中重复次数最多的一项"""    class_count = {}    for vote in class_list:        if vote not in class_count.keys():            class_count[vote] = 0            class_count[vote] += 1    sorted_class_count = sorted(class_count.items(),                                key=operator.itemgetter(1),                                reverse=True)  # 按逆序进行排列,并返回由元组组成元素的列表    return sorted_class_count[0][0]def create_tree(data_set, label):    """创建我们所要分类的决策树"""    class_list = [example[-1] for example in data_set]  # classList是指当前数据集的类别标签    if class_list.count(class_list[0]) == len(class_list):  # 计算classList中某个类别标签的数量,若只有一类,则数量与它的数据长度相等        return class_list[0]    if len(data_set[0]) == 1:  # 当处理完所有特征而类别标签还不唯一时起作用        return majority_cnt(class_list)    feat_best = choose_best_feature(data_set)  # 选择最好的分类特征    feature = [example[feat_best] for example in data_set]  # 接下来使用该分类特征进行分类    feat_value = set(feature)  # 得到该特征所有的分类值,如'0'和'1'    new_label = label[feat_best]    del (label[feat_best])    Tree = {new_label: {}}  # 创建一个多重字典,存储决策树分类结果    for value in feat_value:        sub_label = label[:]        # 递归函数使得Tree不断创建分支,直到分类结束        Tree[new_label][value] = create_tree(spilt_data(data_set, feat_best, value), sub_label)    return Treeheaders, data_set = read_data()tree = create_tree(data_set, headers)print(tree)'''{    'age': {        0: {            'student': {                0: 0,                1: 1            }        },        1: 1,        2: {            'credit_rating': {                0: 1,                1: 0            }        }    }}将数值变回原来的字符串形式为:{    'age': {        'youth': {            'student': {                'no': 'no',                'yes': 'yes'            }        },        'middle_aged': 'yes',        'senior': {            'credit_rating': {                'fair': 'yes',                'excellent': 'no'            }        }    }}'''

三、scikit-learn包实现

  1. Python机器学习的库:scikit-learn
    1.1 特性:

    简单高效的数据挖掘和机器学习分析
    对所有用户开放,根据不同需求高度可重用性
    基于Numpy, SciPy和matplotlib
    开源,商用级别:获得 BSD许可

    2.2 覆盖问题领域:

    分类(classification), 回归(regression), 聚类(clustering), 降维(dimensionality reduction)

    模型选择(model selection), 预处理(preprocessing)

  2. 使用用scikit-learn

    安装scikit-learn: pip
    安装必要package:numpy, SciPy和matplotlib, 可使用Anaconda (包含numpy, scipy等科学计算常用package)

    文档: http://scikit-learn.org/stable/modules/tree.html

  3. 安装 Graphviz: http://www.graphviz.org/
    这是一个可视化的图形绘制工具软件,下载安装,然后配置环境变量

    打开命令行终端:cd到文件目录:
    转化dot文件至pdf可视化决策树:dot -Tpdf buy_computer.dot -o output.pdf

 # 将dict类型的list数据,转换成numpy arrayfrom sklearn.feature_extraction import DictVectorizerimport csvfrom sklearn import preprocessingfrom sklearn import treeimport numpy as npclass Data_Processing(object):    def __init__(self):        self.reader = None        self.headers = None        self.vec = None        self.dummy_x = None        self.dummy_y = None    def read_data(self, path):        buy_computer = open(path, 'r')        self.reader = csv.reader(buy_computer)        self.headers = next(self.reader)    def pre_processing(self):        feature_list = []        label_list = []        if self.reader and self.headers is None:            raise ValueError        for row in self.reader:            label_list.append(row[len(row) - 1])            row_dict = {}            for i in range(1, len(row) - 1):                row_dict[self.headers[i]] = row[i]            feature_list.append(row_dict)        # print("feature_list:" + str(feature_list))        # print("label_list:" + str(label_list))        self.vec = DictVectorizer()        self.dummy_x = self.vec.fit_transform(feature_list).toarray()        # print("dummy_x:" + str(dummy_x))        print(self.vec.get_feature_names())        lb = preprocessing.LabelBinarizer()        self.dummy_y = lb.fit_transform(label_list)        # print("dummy_y:" + str(dummy_y))if __name__ == '__main__':    dp = Data_Processing()    dp.read_data('buy_computer.csv')    dp.pre_processing()    clf = tree.DecisionTreeClassifier(criterion='entropy')    print(clf)    clf_ = clf.fit(dp.dummy_x, dp.dummy_y)    print("clf:" + str(clf_))    with open('buy_computer.dot', 'w') as f:        f = tree.export_graphviz(clf, feature_names=dp.vec.get_feature_names(), out_file=f)    one_row_x = dp.dummy_x[0, :]    print("one_row_x:" + str(one_row_x))    new_row_x = one_row_x    new_row_x[0] = 1    new_row_x[2] = 0    new_row_x = np.array(new_row_x).reshape((1, -1))    print("new_row_x" + str(new_row_x))    prediction_y = clf.predict(new_row_x)    print("prediction_y:" + str(prediction_y))

这里写图片描述

两种方式实现都能画出这样的图。有了这样的模型,我们就可以进行预测了。
上一组不同的数据来看看(上面代码中的这部分):

    one_row_x = dp.dummy_x[0, :]    print("one_row_x:" + str(one_row_x))    new_row_x = one_row_x    new_row_x[0] = 1    new_row_x[2] = 0    new_row_x = np.array(new_row_x).reshape((1, -1))    print("new_row_x" + str(new_row_x))    prediction_y = clf.predict(new_row_x)    print("prediction_y:" + str(prediction_y))

这里写图片描述

从图中我们可以看出,新的一组数据,我们预测这个人是要买电脑。所以当模型的数据足够大,内容特征足够丰富影响做这个事儿的决断。我们就能很好的、很正确的进行预测。

阅读全文
'); })();
1 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 影视快搜tv版apk下载 影视快搜下载 在线播 全能播放器免费下载 求个网址你们懂得 憣快下载 夜播影院破解版 快幡 日本播放器 快速播放器 360播放器 kuaibao 全能播放器 快币 快拨播放器下载 快波影院 四播 芊芊影院 快新 快新文 快新图片 快新吧 快新同人 快新肉 快新abo 快新r18 快新同人文 快新文囚禁工藤新一 快新快斗在新一身体里 快新吧新一怀孕 时青快穿 快穿之青闲时吃肉 快穿当妈进行时 说时迟那时快 快穿之拯救男配进行时 快绝经时月经会出现什么状况 宝宝快长牙时牙龈图片 揉豆豆超级快时会什么感觉 快雪时晴 快绝经时有哪些症状 快来月经时白带什么样