西瓜书课后题——第十一章(特征选择与稀疏学习)

11.1 编程实现 Relief 算法,并在西瓜数据集上测试。

Relief 是过滤式特征选择算法,根据设计的 “相关统计量” 来度量特征的重要性。该方法和后续的学习器无关,只根据数据集就可完成特征选择。相关的思想理论介绍见书P249-250

代码实现如下:

import pandas as pd
import numpy as np

class Relief:
    def readData(self):
        dataset = pd.read_excel('./WaterMelon_3.0.xlsx',encoding = 'gbk')  # 读取数据
        self.Attributes = dataset.columns[1:-1]        #所有属性的名称
        #print(self.Attributes)
        dataset = np.matrix(dataset)
        dataset = dataset[:,1:]
        m,n = np.shape(dataset)      # 得到数据集大小
        #print(dataset)
        dataset[:,n-3:n-1] = (dataset[:,n-3:n-1]-np.min(dataset[:,n-3:n-1],0))/\
                             (np.max(dataset[:,n-3:n-1],0)-np.min(dataset[:,n-3:n-1],0))     # 连续属性规范化
        self.goodindex = np.where(dataset[:,n-1]=='是')[0]        # 好瓜的索引
        self.badindex = np.where(dataset[:,n-1]=='否')[0]         # 坏瓜的索引
        self.dataset = dataset


    # 计算每个样本之间的距离
    def getDist(self):
        m,n = np.shape(self.dataset)
        distance = np.ones([m,m])
        for i in range(m):
            distance[i,i] = np.inf
            for j in range(i+1,m):
                dis = 0
                for k in range(n-1):
                    if type(self.dataset[i,k])== str:        # 离散属性
                        dis = dis + 1 - np.int(self.dataset[i,k]==self.dataset[j,k])
                    else:                                   # 连续属性
                        dis = dis + pow((self.dataset[i,k]-self.dataset[j,k]),2)
                distance[i,j] = dis
                distance[j,i] = dis
        self.distance = distance

    # 过滤
    def fliter(self):
        m,n = np.shape(self.dataset)
        delte = np.zeros([n-1])
        for i in range(m):    # 依次对每一个样本进行
            delte = delte + self.getdelet(i)
        return delte

    # 计算一个样本中所有属性的权值delte
    def getdelet(self,i):
        m,n = np.shape(self.dataset)
        distance = self.distance[i,:]            # 该样本i到每一个样本的距离
        gooddis = distance[self.goodindex]       # 到好瓜距离
        baddis = distance[self.badindex]         # 到坏瓜距离
        good = dict(zip(gooddis,self.goodindex))     # 生成字典,键为距离,值为样本索引
        bad = dict(zip(baddis,self.badindex))
        if self.dataset[i,-1] == '是':               # 样本i是好瓜
            minh = np.min(gooddis)       # 同类中最小距离
            indexh = good[minh]          # 最小距离对应的样本索引
            minm = np.min(baddis)        # 不同类中最小距离
            indexm = bad[minm]           # 不同类中最小距离对应的索引
        else:
            minh = np.min(baddis)       # 同类
            indexh = bad[minh]
            minm = np.min(gooddis)      # 不同类
            indexm = good[minm]
        delte = []
        for j in range(n-1):           # 遍历每一个属性,进行计算
            if type(self.dataset[i,j])== str:     # 离散属性
                dh = 1 - np.int(self.dataset[i,j]==self.dataset[indexh,j])     # 同类
                dm = 1 - np.int(self.dataset[i,j]==self.dataset[indexm,j])     # 不同类
            else:                                # 连续属性
                dh = np.float64(pow((self.dataset[i,j]-self.dataset[indexh,j]),2))   # 同类
                dm = np.float64(pow((self.dataset[i,j]-self.dataset[indexm,j]),2))   # 不同类
            delte.append(-dh+dm)
        return delte                    # 返回的是样本i计算得到的每一个属性上的权值


    def getAttr(self,delte):
        dic = dict(zip(self.Attributes,delte))       # 得到字典
        dd = sorted(dic.items(),key=lambda item:item[1],reverse=True)      # 根据值的大小进行排序,倒序
        for i,j in dd:
            print(i+':'+str(j),end='\t')

def main():
    relief = Relief()
    relief.readData()
    relief.getDist()
    delte = relief.fliter()
    relief.getAttr(delte)

if __name__ == '__main__':
    main()

最终得到的每个属性的权值(重要性程度)如下:

纹理:9.0	脐部:7.0	根蒂:4.0	含糖率:2.04491655411	密度:-0.500966445714	敲声:-1.0	触感:-4.0	色泽:-7.0	

 

11.2 Relief-F 算法描述

输入:
     数据集D

过程:
1. 将数据集中连续属性取值规范化到[0,1]
2. 计算数据集D中各类样本所占的比例 p_l
3. 计算数据集D中每一对样本之间的距离distance
4. thete = [0,0,……,0] , 表示每一个属性的权值
5. for x_i in D:
6.     d_nh,d_nm = [0,0,……,0]  , 表示通过样本 x_i 在所有属性上计算得到的权值,对应于式11.4的前后两部分
7.     根据distance矩阵找出每个分类类别中与 x_i 距离最近的样本,构成集合 xmin
8.     for x_j in xmin:
9.          if(x_i和x_j类别相同):d_nh = diff(x_i,x_j)^2
10.         else: d_nm = d_nm + p_l * diff(x_i,x_j)^2       其中,p_l是x_j 所在类别的比例
11.    thete = thete + (-d_nh+d_nm)

输出:thete

 

11.3  设计一个可以考虑每一对属性重要性的改进算法。

可以将所有的属性两两配对,然后将其看成一个整体,将整体带入类似于原来的 Relief 算法中进行运算,最终得到针对每一对的权重,即可实现每一对属性重要性的衡量。     (好像有点 low, 但是确实想不到其他的好的方法,如有什么新的思路还请指教!)

 

11.4  设计一个算法,即便有运行时间限制,LVW 算法也一定能给出解。

该算法的结束条件是 连续 t 次随机产生的特征子集在学习器上的效果都比当前的特征子集差。但是当数据集和特征集都很大时,这个条件很难满足,所以为了可以在规定的时间内结束算法,我们可以再人为设定一个最大的迭代次数,当达到最大的迭代次数之后,不论当前状态如何,都将当前的最佳特征子集返回。

 

11.5  L1正则化在何种情形下不能产生稀疏解。

L1正则化之所以可以产生稀疏解,主要是因为平方误差项等值线与L1等值线的第一个交点位于坐标轴上,如书上图11.2所示,当平方误差项等值线的曲率比较大时,就会导致其与L1等值线的第一个交点不再位于坐标轴上,此时就无法产生稀疏解。

 

11.6  试述岭回归和SVM的联系。

 相同点: 两者的优化目标中都有权重参数项,都想得到较小的权重。

不同点:

岭回归的目标函数主要是 累积平方误差,主要的目的是减小这个误差。而后面加的权重参数项只是一个正则化的手段,以此来防止过拟合。整体上看就是想要实现  在尽量小的权重参数取值下尽可能地降低累积平方误差,两者之间通过系数进行权衡。

SVM则不同,它是直接将权重参数的二范数作为优化目标,没有考虑累积平方误差,而对应的约束条件是保证每一个样本和分隔线之间具有足够的间隔。 所以整体上是为了实现  在保证所有的样本都可以以指定的间隔分离的条件下(必须达到这个条件),取具有最小二范数值的权重参数。  所以,SVM 的优化目标决定了样本必须线性可分,否则就无法实现。

 

11.7 直接求解 L0 范数正则化会遇到的困难。

L0 范数是不连续的,而且是非凸函数,无法通过优化直接求解,必须采用遍历的方式,因此导致这个问题是个NP难问题。

 

11.8  L1范数求解最小化问题式 11.14 的推导。

西瓜书课后题——第十一章(特征选择与稀疏学习)_第1张图片

参考自: https://blog.csdn.net/icefire_tyh/article/details/52254580

 

11.9 试述字典学习与压缩感知对稀疏稀疏性利用的异同。

字典学习使样本转化为稀疏表示的形式,是为了利用稀疏性来使学习任务得到简化,使模型的复杂度得到降低,从而可以学习到一个对于当前的学习任务比较好的一个学习器。

而压缩感知主要是想利用信号本身所具有的稀疏性,从而实现从部分观测样本中恢复出原始信号的目的。 

你可能感兴趣的:(机器学习)