Relief算法python实现

文章目录
一、算法流程图
二、代码步骤
1.第一步:定义类和init方法
2.第二步:数据处理
3.第三步:通过计算距离,找出猜错近邻和猜对近邻
4.第四步:计算特征权重
5.第五步:根据权重过滤式选取特征
6.第六步:选取最终特征
7.第七步:定义主函数
三、为什么要写relief算法?以及解决什么问题?

算法流程

relief算法流程图.png

第一步:定义类和init方法

方便函数调用参数,只需要一次向类中导入参数即可,不用重复导入参数

class Filter:
    def __init__(self, data_df, sample_rate, t, k):
        """
        #
        :param data_df: 数据框(字段为特征,行为样本)
        :param sample_rate: 抽样比例
        :param t: 统计量分量阈值
        :param k: 选取的特征的个数
        """
        self.__data = data_df
        self.__feature = data_df.columns
        self.__sample_num = int(round(len(data_df) * sample_rate))#round函数:四舍五入
        self.__t = t
        self.__k = k

第二步:数据处理

将读取到的数据特征值中离散型处理成连续型,比如色泽:青绿,属于离散型,密度:0.679,属于连续型。

    def get_data(self):
        new_data = pd.DataFrame()#建立一个空二维表
        for one in self.__feature[:-1]:#遍历循环每个特征
            col = self.__data[one]#读取全部样本中其中一个特征
            # 判断读取到的特征是否全为数值类,如果字符串中全为数字  ,则不作改变写进新的二维表new_data里面,否则处理成数值类型写进二维表
            if (str(list(col)[0]).split(".")[0]).isdigit() or str(list(col)[0]).isdigit()\
            or (str(list(col)[0]).split('-')[-1]).split(".")[-1].isdigit():#isdigit函数:如果是字符串包含数字返回ture,否则返回false
                new_data[one] = self.__data[one]
            else:
                keys = list(set(list(col)))#set函数:删除重复值,得到一个特征的类别,如色泽:青绿、浅白、乌黑
                values = list(range(len(keys)))#遍历循环len(keys),色泽特征为例,三个特征类别,则得到三个数0、1、2
                new = dict(zip(keys, values))#dict函数就是创建一个字典,zip函数矩阵中的元素对应打包成一个元组列表
                new_data[one] = self.__data[one].map(new)#map函数:将new: {'青绿': 0, '浅白': 1, '乌黑': 2}在col列表里做一个映射
        new_data[self.__feature[-1]] = self.__data[self.__feature[-1]]#瓜的类别属性不做改变
        return new_data

get_data(self)函数:经过处理数据,用0、1、2这样的数字去取代特征的中文类别,拿色泽为例,色泽=['青绿','浅白','乌黑'] 替换为 色泽=['0' , '1' , '2'],完成所有替换后返回一个连续型数据类型的数据集。

第三步:通过计算距离,找出猜错近邻和猜对近邻

    def get_neighbors(self, row):
        df = self.get_data()
        #row是一行一行(一个一个)样本
        row_type = row[df.columns[-1]]#矩阵最后一列:瓜的类别,如好瓜、坏瓜、模糊
        #下面进行分类,与读取到的样本类型相同的分为  “同类”,不相同的分为 “异类”,储存在两个数据集中
        right_df = df[df[df.columns[-1]] == row_type].drop(columns=[df.columns[-1]])#筛选出数据集类别与读取样本同类的样本,删除数据集最后一列
        #将删除后的数据集储存在right_df中,原数据集df保持不变。
        wrong_df = df[df[df.columns[-1]] != row_type].drop(columns=[df.columns[-1]])#异类样本数据集
        aim = row.drop(df.columns[-1])#删除类别特征
        f = lambda x: eulidSim(np.mat(x), np.mat(aim))#lambda函数:定义一个隐函数,  mat函数:转换为矩阵,方便线性代数的操作
        #eulidsim函数是自己定义的一个计算距离的函数
        right_sim = right_df.apply(f, axis=1)#apply函数:就是将right_df里面的每个变量,axis=1按行的顺序计算,
        #apply函数解释链接: https://www.cnblogs.com/xiaodongsuibi/p/8927688.html
        right_sim_two = right_sim.drop(right_sim.idxmin())#idxmin()函数:获取某行最小的序列号,里面删除了读取样本本身的那个数据
        #之所以在同类中删除距离最小的那个数据,是因为在原数据集中,包括了本身的那个数据
        wrong_sim = wrong_df.apply(f, axis=1)
        return right_sim_two.idxmin(), wrong_sim.idxmin()

get_neighbors()函数:随机从数据集中选取一个样本X,识别样本X所属的类别,如好瓜、坏瓜、模糊。在数据集中将与样本X同类的数据分类为同类数据集,不同类的分为异类数据集,得到两个数据集。计算样本X与两个数据集中的所有样本的欧式距离,因为同类样本数据集中有一个是数据样本X,要将这个样本删了,因为返回最近近邻的数据时,样本X与样本X的距离肯定是最小的。然后分别返回两个数据集中与样本X距离最近的数据样本,同类数据集中的最近距离样本即为猜对近邻,异类数据集中的最近距离样本即为猜错近邻。

第四步:计算特征权重

    def get_weight(self, feature, index, NearHit, NearMiss):
        data = self.__data.drop(self.__feature[-1], axis=1)#西瓜数据集
        row = data.iloc[index]#选取到的数据样本,命名为样本X
        nearhit = data.iloc[NearHit]#猜对近邻数据样本
        nearmiss = data.iloc[NearMiss]#猜错近邻数据样本
        #将特征的数据类型分类,分类连续型和离散型,不同类型的数据,用不同的方法计算特征距离
        if (str(row[feature]).split(".")[0]).isdigit() or str(row[feature]).isdigit() \
                or (str(row[feature]).split('-')[-1]).split(".")[-1].isdigit():
            #连续型特征距离计算方式:
            max_feature = data[feature].max()#连续型数据特征的最大值
            min_feature = data[feature].min()#连续型数据特征的最小值
            #公式原理:如果两个特征值差距越小,则距离越近,反之,则距离越远,加一个分母是为了归一化
            right = pow(round(abs(row[feature] - nearhit[feature]) / (max_feature - min_feature), 2), 2)#猜对近邻特征权重
            wrong = pow(round(abs(row[feature] - nearmiss[feature]) / (max_feature - min_feature), 2), 2)#猜错近邻特征权重
        else:
            # 离散型特征距离计算方式:
            right = 0 if row[feature] == nearhit[feature] else 1#如果猜对近邻特征与样本X一样。则返回0,不一样返回1
            wrong = 0 if row[feature] == nearmiss[feature] else 1#如果猜错近邻特征与样本X一样。则返回0,不一样返回1
        w = wrong - right#right越小,说明两个同类样本的特征越相似,反之,则同类样本差距越大。
                         #wrong越小,说明两个异类样本的特征越相似,反之,则异类样本差距越大。
        #w越大,说明wrong越大,ringt越小,则表示同类的样本间,该特征的数值差距小,不同类的差距大,说明以该特征区分不同类别,比较容易。
        return w

计算出每个数据样本中每个特征的权重w

第五步:根据权重过滤式选取特征

    def relief(self):
        sample = self.get_data()
        m, n = np.shape(self.__data)  # m为行数,n为列数
        score = []
        sample_index = random.sample(range(0, m), self.__sample_num)#random.sample函数:从指定序列中随机获取指定长度的片断。sample函数不会修改原有序列。
        print ('采样样本索引为 %s ' % sample_index)
        num = 1
        for i in sample_index:    # 采样次数
            one_score = dict()#创建一个字典
            row = sample.iloc[i]
            NearHit, NearMiss = self.get_neighbors(row)
            print ('第 %s 次采样,样本index为 %s,其NearHit行索引为 %s ,NearMiss行索引为 %s' % (num, i, NearHit, NearMiss))
            for f in self.__feature[0:-1]:
                w = self.get_weight(f, i, NearHit, NearMiss)
                one_score[f] = w
                print( '特征 %s 的权重为 %s.' % (f, w))
            score.append(one_score)
            num += 1
        f_w = pd.DataFrame(score)#将字典的格式换成表格
        print ('采样各样本特征权重如下:')
        #print (f_w)
        print ('平均特征权重如下:')
        print (f_w.mean())
        return f_w.mean()

将所有样本的特征权重采集到一个字典里,再将字典类型的数据集转换成表格,表格行标签为样本属性,列标签为样本序号,表格内为权重。再将每个属性的特征权重取均值,即每列数据取均值,得到每个属性的平均特征权重。

第六步:选取最终特征

    def get_final(self):
        f_w = pd.DataFrame(self.relief(), columns=['weight'])
        print("f_w:",f_w)
        final_feature_t = f_w[f_w['weight'] > self.__t]#设置阈值,将大于阈值的属性筛选出来
        print ("final_feature_t:",final_feature_t)
        final_feature_k = f_w.sort_values('weight').head(self.__k)#sort_values函数:排序函数,https://blog.csdn.net/qq_24753293/article/details/80692679
        print ("final_feature_k:",final_feature_k)
        return final_feature_t, final_feature_k

将数据集中的平均特征权重转换成一个表格形式,方便我们研究数据,设置一个阈值,将符合我们预期的特征筛选出来并且将平均特征权重做一个排序。到这里为止,我们就对数据集中的特征做了一个筛选,返回出我们需要的特征。

第七步:定义主函数

if __name__ == '__main__':
    data = pd.read_csv('1.csv',encoding="gbk")[['色泽', '根蒂', '敲声', '纹理', '脐部', '触感', '密度', '含糖率', '类别']]
    f = Filter(data, 1, 0.2, 8)
    f.relief()
    f.get_final()

为什么要写relief算法?以及解决什么问题?

为什么写relief算法,因为relief算法简单,可操作性强。
解决什么问题?当我们遇到维数灾难问题的时候,主要是因为属性太多,我们需要将一些影响极小的属性进行一个剔除,所以就引入特征选择,这其实跟降维差不多。
然而relief算法就是特征选择的一个方法,通过对所有样本的一个过滤,过滤后给每个特征赋予一个权重,我们根据一个权重的大小排序来筛选出对类别影响大的特征。
以后的运用:比如我们建立一个模型,去判断不同属性对信用程度的一个影响,例如其中属性包括财富、性格、颜值、年龄等,我们给这些属性一个权重,比如颜值这个属性的权重极小,也就是说你颜值如何跟你守不守信关系极小,所以我们根据计算出来的属性权重值做一个排序,将一些对我们分类的目的影响极小的属性进行一个剔除。

附上代码+数据:https://gitee.com/liu_ji_duan/DuanGe/tree/master/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/RELIEF%E7%AE%97%E6%B3%95%E5%AE%9E%E7%8E%B0

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

推荐阅读更多精彩内容