李航老师《统计学习方法》第八章课后习题答案

其他章节答案请参考我的汇总统计学习方法答案汇总,都是自己写的。

8.1、题目太长,懒得打字了

因为训练数据实例的维度比书中的例子8.1的实例的维度大,也就是特征的数目比较多,因而需要进行特征选择。我在这里根据数据集里面数据的权重进行特征选择的,如果按照原始数据进行原则,那么除了强制排除已经选择的特征,否则每次构造决策树桩,都只能选择相同的特征进行构造决策树桩,这显然是不合理的。
直接上代码:

import numpy as np
def choose_character_by_data_weight(X,Y,w):
    '''
    该方法使用数据的每次迭代的权重来选择特征,如果不使用数据的权重的话,每次计算出的特征都是相同的,将无法构造分类树桩
    Parameters
    ----------
    X : numpy array
        训练数据.
    Y : numpy array
        数据标签.
    w : numpy array
        数据的权重.

    Returns
    -------
    最佳的特征.

    '''
    s = np.shape(X)
    char_nums = s[1] ## 特征的个数
    ## 下面开始计算H(D)
    class_ = list(set(Y)) ## 类别集合
    H_D = -sum([sum(np.where(Y == c, w, 0.0)) * np.log(sum(np.where(Y == c, w, 0.0))) for c in class_])
    ## 下面开始计算信息增益比
    info_rate = []
    for i in range(char_nums):
        H_D_i = 0.0
        char_i = list(set(X[:, i]))
        for ch_i in char_i:
            w1 = sum(np.where(X[:, i] == ch_i, w, 0.0))
            for c in class_:
                w2 = sum(np.where((X[:,i] == ch_i) * (Y == c), w, 0.0)) / w1
                if w2 != 0.0:
                    H_D_i -= w1 * w2 * np.log(w2)
                    
        ## 下面开始计算特征i的条件经验熵
        H_i_D = -sum([sum(np.where(X[:, i] == ch, w, 0.0)) * np.log(sum(np.where(X[:, i] == ch, w, 0.0))) for ch in char_i])
        info_rate.append((H_D - H_D_i) / H_i_D)
    # print('2 is :', info_rate)
    return info_rate.index(max(info_rate))
    
def create_Tree(X,Y,w):
    #首先选择特征
    char = choose_character_by_data_weight(X,Y,w) ## 根据权重选择特征
    char_val = list(set(X[:, char])) ## 特征的取值
    char_val = sorted(char_val)
    ## 下面开始确定选择特征char的取值才能是误差率最小
    best_tree = None
    best_loss = 2 ** 15
    for i in range(len(char_val) - 1):## 只要循环特征char取值少一个就行啦
        tree_i = [] # 使用一个列表表示一个二叉树桩,第0个元素是选择哪个特征来进行分类,第一个元素是决策元素,第二个元素表示当小于时的类别,第三个是大于时的类别
        loss_i = 0
        ch = (char_val[i] + char_val[i + 1]) / 2 #在已经排序好的特征取值中,取两个相邻特征的中间值就可以了,将其分为两类
        # 下面根据数据权重计算损失并且确定决策树桩
        Y1 = Y[X[:, char] < ch]
        Y2 = Y[X[:, char] > ch]
        W1 = w[X[:, char] < ch]
        W2 = w[X[:, char] > ch]
        n1 = list(set(Y1))
        n2 = list(set(Y2))
        tree_i.append(char)
        tree_i.append(ch)
        if len(n1) == 1:
            ## 此时说明只有一个类别,无需计算每个类别的损失,此时在这个子集上的分类误差是0
            tree_i.append(Y1[0])
            loss_i += 0
        else:
            ## 此时说明Y1有两个类别,因为权重不是均衡的,不能按照数量的多少进行划分类别
            loss_1 = sum(np.where(Y1 != 1, W1, 0)) ## 类别1的损失
            loss_2 = sum(np.where(Y1 != -1, W1, 0)) ## 类别-1的损失
            if loss_1 >= loss_2:
                #此时说明应该取值为-1
                tree_i.append(-1)
                loss_i += loss_2
            else:
                tree_i.append(1)
                loss_i += loss_1
                
        if len(n2) == 1:
            ## 此时说明只有一个类别,无需计算每个类别的损失,此时在这个子集上的分类误差是0
            tree_i.append(Y2[0])
            loss_i += 0
        else:
            ## 此时说明Y1有两个类别,因为权重不是均衡的,不能按照数量的多少进行划分类别
            loss_1 = sum(np.where(Y2 != 1, W2, 0)) ## 类别1的损失
            loss_2 = sum(np.where(Y2 != -1, W2, 0)) ## 类别-1的损失
            if loss_1 >= loss_2:
                #此时说明应该取值为-1
                tree_i.append(-1)
                loss_i += loss_2
            else:
                tree_i.append(1)
                loss_i += loss_1
        if loss_i < best_loss:
            best_loss = loss_i
            best_tree = tree_i
        
    return best_tree, best_loss
        
def boost(X,Y):
    init_w = np.array([0.1] * len(Y)) ## 初始的权重分类,使用原始数据训练一个决策树
    all_tree = [] ## 用来存储生成的决策树
    all_alpha = [] ## 存储每颗决策树的系数
    while True:
        tree_i, loss_i = create_Tree(X,Y,init_w) ## 生成一个决策树
        alpha = 0.5 * np.log((1-loss_i) / loss_i)
        all_tree.append(tree_i)
        all_alpha.append(alpha)
        ## 下面开始计算已经得到决策树是否可以让训练的准确率足够高,这里使用完全正确分类来衡量是否跳出循环
        acc = 0
        for i in range(len(Y)):
            x_i = X[i,:]
            f = 0
            y_true = Y[i]
            for t in range(len(all_alpha)):
                a_t = all_alpha[t]
                tree_ = all_tree[t]
                char = tree_[0]
                seg = tree_[1]
                label_1 = tree_[2]
                label_2 = tree_[3]
                
                if x_i[char] < seg:
                    f += a_t * label_1
                else:
                    f += a_t * label_2
            acc += int(np.sign(f) == y_true)
            
        if (acc / len(Y)) == 1:
            return all_tree, all_alpha
        ## 下面开始更新数据的权重
        for i in range(len(Y)):
            x_i = X[i,:]
            y_true = Y[i]
            char = tree_i[0]
            seg = tree_i[1]
            label1 = tree_i[2]
            label2 = tree_i[3]
            
            if x_i[char] < seg:
                G = label1
            else:
                G = label2
            init_w[i] = init_w[i] * np.exp(- alpha * y_true * G)
        init_w = init_w / sum(init_w)
    
    
if __name__ == '__main__':
    X = np.array([[0,1,3],
                  [0,3,1],
                  [1,2,2],
                  [1,1,3],
                  [1,2,3],
                  [0,1,2],
                  [1,1,2],
                  [1,1,1],
                  [1,3,1],
                  [0,2,1]])
    Y = np.array([-1,-1,-1,-1,-1,-1,1,1,-1,-1])
    tree, alpha = boost(X,Y)

2、比较支持向量机、AdaBoost、逻辑斯谛回归模型的学习策略与算法。

2.1、支持向量机的学习策略与算法

学习策略:
由目标函数函数可以看到,支持向量机的学习策略是结构风险极小化

算法有最大间隔方法、对偶算法、软间隔算法,emm,貌似对偶算法和软间隔算法是有相交关系的。

2.2、Adaboot模型的策略和算法

学习策略:经验风险极小化
学习算法:提升树算法等

2.3、逻辑斯谛回归的学习策略和算法

学习策略:经验风险极小化
算法:极大似然估计法

你可能感兴趣的:(统计学习方法第二版,python,机器学习,adaboost算法,决策树)