统计学习方法——第五章决策树

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a786150017/article/details/78710945

【算法】


信息增益


    在数据比较大,特征比较多的情况下,很容易造成过拟合,于是需进行决策树剪枝,一般剪枝方法是当按某一特征分类后的熵小于设定值时,停止分类。

【缺点】

  • ID3算法在选择根节点和内部节点中的分支属性时,采用信息增益作为评价标准。信息增益的缺点是倾向于选择取值较多是属性,在有些情况下这类属性可能不会提供太多有价值的信息。
  • ID3算法只能对描述属性为离散型属性的数据集构造决策树 。

       为了改进决策树,又提出了ID4.5算法(依据:信息增益比)和CART算法(回归树:平方误差最小/分类树:基尼指数最小)。

 

【案例:头发声音判断特征】

参考博客

扫描二维码关注公众号,回复: 3469179 查看本文章

(案例)http://blog.csdn.net/csqazwsxedc/article/details/65697652

(代码注解详细)

     http://blog.csdn.net/u011197534/article/details/52749325?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

(另个一类似案例)http://blog.csdn.net/alvine008/article/details/37760639

(其他)http://blog.csdn.net/wds2006sdo/article/details/52849400

A、问题描述

     一天,老师问了个问题,只根据头发和声音怎么判断一位同学的性别。

     为了解决这个问题,同学们马上简单的统计了7位同学的相关特征,数据如下:


B、计算解决

               

                              同学A                                                                         同学B

信息增益的计算

总共有8位同学,男生3位,女生5位。


       比较各特征的信息增益值。由于A2(声音)的信息增益值更大,所以选择A2为最优特征。

C、代码

1.创建示例数据

def createTrainset():
    dataSet = [['长', '粗', '男'],
               ['短', '粗', '男'],
               ['短', '粗', '男'],
               ['长', '细', '女'],
               ['短', '细', '女'],
               ['短', '粗', '女'],
               ['长', '粗', '女'],
               ['长', '粗', '女']]
    train_set = [sample[:-1] for sample in dataSet]
    train_label = [sample[-1] for sample in dataSet] #['男', '男', '男', '女', '女', '女', '女', '女']
    features = ['头发','声音']
    return np.array(train_set),np.array(train_label),features

2.预处理:统计label的的个数,放入字典class_count{label:count}。

def createclass_count(train_label):
    class_count = {}
    for label in train_label:
        if label in class_count:
            class_count[label] += 1
        else:
            class_count[label] = 1
    return class_count

3.计算原始信息熵和各特征对数据集的信息熵

1)计算信息熵hd

def calc_ent(train_label):
    hd = 0
    class_count = createclass_count(train_label)
    for label in class_count.keys():
        prob = class_count[label] / len(train_label)
        hd -= prob * math.log(prob,2)
    return hd

2)计算各特征对数据集的信息熵had = H(train_label | feature)

#其中输入feature为train_set的一列e.g ['长', '短', '短', '长', '短', '短', '长', '长']
def calc_condition_ent(feature,train_label):
    hda = 0
    for feature_value in set(feature):
		 #对于某个特征feature_value,只考虑包含此特征的train_label
        sub_train_label = train_label[feature == feature_value]
        tempt_ent = calc_ent(sub_train_label)
        hda += len(sub_train_label) / len(train_label) * tempt_ent
    return hda

4.递归构建决策树

def createTree(train_set,train_label,features):
    # 步骤1——如果train_set中的所有实例都属于同一类Ck[递归停止条件]
    label_set = set(train_label)

    if len(label_set) == 1:
        return label_set.pop()

    # 步骤2——如果特征集features为空[递归停止条件]
    class_count = createclass_count(train_label)
    # → 类标记为train_set中实例数最大的类
    max_class = max(class_count, key=class_count.get)

    if len(features) == 0:
        return max_class

    # 步骤3——计算信息增益
    #计算原始的信息熵
    hd = calc_ent(train_label)

    max_gda = 0
    max_feature_idx = -1
    #计算各特征对数据集D的信息增益
    for i in range(len(features)):
        gda = hd - calc_condition_ent(train_set[:,i],train_label)

        if gda > max_gda:
            max_gda = gda
            max_feature_idx = i

    # 步骤4——小于阈值
    if max_gda < epsilon:
        return max_class

    # 步骤5——构建非空子集
    max_feature = features[max_feature_idx]
    tree = {max_feature:{}}

    #删除此特征
    del(features[max_feature_idx])

    feature_value = set(train_set[:,max_feature_idx])	#构建子树,遍历feature的值
    for value in feature_value:
		  #子树的训练集和label只包含-含有当前feature-的行
        sub_train_set = train_set[train_set[:,max_feature_idx] == value]
        sub_train_label = train_label[train_set[:,max_feature_idx] == value]
        tree[max_feature][value] = createTree(sub_train_set,sub_train_label,features)
    return tree

*判定分类结束的依据是,若按某特征分类后出现了最终类(男或女),则判定分类结束。

5.测试_输入特征,判断性别

def classify(myTree,features,sample):
    #找到最优特征-根节点['声音']
    firstfeature =list(myTree.keys())[0]
    #找到最优特征的索引
    feature_idx = features.index(firstfeature)  #此处'声音'的索引为1
    
    #判断最优特征的值
    secondDic = myTree[firstfeature]
    for key in secondDic.keys():
        if key == sample[feature_idx]:  #和sample对应处相同
            if type(secondDic[key]) == dict:#还没有结束
                mylabel = classify(secondDic[key],features,sample)
            else:
                mylabel = secondDic[key]
    return mylabel

6.main函数及输出

if __name__ == '__main__':
    epsilon = 1e-6
    train_set,train_label,features = createTrainset()
    myTree = createTree(train_set,train_label,features)
    print(myTree)

    train_set,train_label,features = createTrainset()
    sample = ['短','粗']
    mylabel = classify(myTree,features,sample)
    print('特征为%s的同学性别为: %s'%(str(sample),mylabel)) # 男

输出:

{'声音': {'细': '女', '粗': {'头发': {'长': '女', '短': '男'}}}}

特征为['短', '粗']的同学性别为: 男








































猜你喜欢

转载自blog.csdn.net/a786150017/article/details/78710945