zoukankan      html  css  js  c++  java
  • 数据离散化与Python实现

    一、原理
            数据离散化(也称,数据分组),指将连续的数据进行分组,使其变为一段离散化的区间。

            根据离散化过程中是否考虑类别属性,可以将离散化算法分为:有监督算法无监督算法。事实证明,由于有监督算法充分利用了类别属性的信息,所以再分类中能获得较高的正确率。

    常用的数据离散化方法:

    • 等宽分组
    • 等频分组
    • 单变量分组
    • 基于信息熵分组

            数据离散化所使用的方法需要事先对数据进行排序,且假设待离散化的数据是按照升序排序。

    1、等宽分组
            原理:根据分组的个数得出固定的宽度,分到每个组中的变量的宽度是相等的。

    如:现在有一个待离散化的数组[1, 7, 12, 12, 22, 30, 34, 38, 46],需要分成三组,

    那么,width = frac{x_{max} - x_{min}}{n},即宽度 =( 46 - 1)/3 = 15

     分组后结果范围:[1,16],(16, 31],(31, 46],第一个分组取的是全闭区间,

    分组后结果:[1, 7, 12, 12],[22, 30],[34, 38, 46]

    2、等频分组
            原理:等频分组也叫分位数分组,即分组后,每个分组的元素个数是一样的。

    如:现在有一个待离散化的数组[1, 7, 12, 12, 22, 30, 34, 38, 46],需要分成三组,

    那么,num = frac{len_{arr}}{n},即每组元素的个数 = 9 / 3 = 3

    分组后的结果:[1, 7, 12],[12, 22, 30],  [34, 38, 46]

    3、单变量分组
            原理:单变量分组,也叫秩分组。将所有元素按照降序或者升序排序,排序名次即为排序结果,即将相同的元素划分到同一个组。

    如:现在有一个待离散化的数组[1, 7, 12, 12, 22, 30, 34, 38, 46],

    分组后的结果:[1], [7], [12, 12], [22], [30], [34], [38], [46]

    4、基于信息熵分组
            概念:

    (1)信息量

            Shannon认为,信息是用来消除随机不确定性的东西。即,衡量信息量大小就看这个消息消除不确定性的程度。

            信息量的大小和事件发生的概率成反比。可以用公式表示为:l(x) = -log_{2}p(x)

    式中,p(x)表示x发生的概率。

    (2)熵

            熵,是在结果出来之前对可能产生的信息量的期望——考虑该随机变量的所有可能取值,即所有可能发生事件所带来的信息量的期望。

    可以表示为:E(x) = -sum_{i=1}^{n}p(x_i)log_{2}p(x_i)

            按照随机变量的所有可能取值划分数据的总熵E是所有事件的熵的加权平均:E = sum_{i=1}^{k}w_iE_i

    式中,w_i = frac{m_i}{m}是第x个事件出现的比例,是第个可能取值出现的次数,是所有取值出现的总次数。

    熵表示的是样本集合的不确定性。熵越大,则样本的不确定性越大。

    所以,基于信息熵进行数据分组的具体做法是:

    1. 对属性A的所有取值从小到大进行排序;
    2. 遍历属性A的每个值,将属性A的值分为两个区间、,使得将其作为分隔点划分数据集后的熵最小;
    3. 当划分后的熵大于设置的阈值且小于指定的数据分组个数时,递归对、执行步骤2中的划分。

    总结:

            上述分组方法中,等宽分组和等频分组实现起来比较简单,但需要人为指定分组个数。

            等宽分组的缺点:对离散值比较敏感,将属性值不均匀地分布到各个区间。有些区间的元素个数较多,有些则较少,容易导致数据倾斜。

            等频分组虽然能避免等宽分组的缺点,但是会将相同的元素分到不同的组,如例子中的“12”元素。

    二、基于信息熵的数据离散化实现

    import numpy as np
    import math
     
    class DiscreateByEntropy:
        def __init__(self, group, threshold):
            self.maxGroup = group # 最大分组数
            self.minInfoThreshold = threshold # 停止划分的最小熵
            self.result = dict()
     
        def loadData(self):
            data = np.array(
                [
                    [56,1],[87,1],[129,0],[23,0],[342,1],
                    [641,1],[63,0],[2764,1],[2323,0],[453,1],
                    [10,1],[9,0],[88,1],[222,0],[97,0],
                    [2398,1],[592,1],[561,1],[764,0],[121,1]
                ]
            )
            return data
     
        # 计算按照数据指定数据分组后的Shannon熵
        def calEntropy(self, data):
            numData = len(data)
            labelCounts = {}
            for feature in data:
                # 获得标签,这里只有0或者1
                oneLabel = feature[-1]
                # 设置字典中,标签的默认值
                if labelCounts.get(oneLabel,-1) == -1:
                    labelCounts[oneLabel] = 0
                # 统计同类标签的数量
                labelCounts[oneLabel] += 1
            shannoEnt = 0.0
            for key in labelCounts:
                # 同类标签出现的概率,某一标签出现的次数除以所有标签的数量
                prob = float(labelCounts[key])/numData
                # 求熵,以2为底,取对数
                shannoEnt -= prob * math.log2(prob)
            return shannoEnt
     
        # 按照调和信息熵最小化原则分割数据集
        def split(self, data):
            # inf为正无穷
            minEntropy = np.inf
            # 记录最终分割的索引
            index = -1
            # 按照第一列对数据进行排序
            sortData = data[np.argsort(data[:,0])]
            # print(sortData)
            # 初始化最终分割数据后的熵
            lastE1,lastE2 = -1, -1
            # 返回的数据区间,包括数据和对应的熵
            S1 = dict()
            S2 = dict()
            for i in range(len(data)):
                splitData1, splitData2 = sortData[:i+1], sortData[i+1:]
                # 计算信息熵
                entropy1, entropy2 = (
                    self.calEntropy(splitData1),
                    self.calEntropy(splitData2)
                )
                # 计算调和平均熵
                entropy = entropy1 * len(splitData1) / len(sortData) + entropy2 * len(splitData2) / len(sortData)
                if entropy < minEntropy:
                    minEntropy = entropy
                    index = i
                    lastE1 = entropy1
                    lastE2 = entropy2
            S1["entropy"] = lastE1
            S1["data"] = sortData[:index+1]
            S2["entropy"] = lastE2
            S2["data"] = sortData[index+1:]
            return S1, S2, entropy
     
        def train(self,data):
            # 需要遍历的key
            needSplitKey = [0]
     
            self.result.setdefault(0,{})
            self.result[0]["entropy"] = np.inf
            self.result[0]["data"] = data
     
            group = 1
            for key in needSplitKey:
                S1, S2, entropy = self.split(self.result[key]["data"])
                if entropy > self.minInfoThreshold and group < self.maxGroup:
                    self.result[key] = S1
                    newKey = max(self.result.keys()) + 1
                    self.result[newKey] = S2
                    needSplitKey.extend([key])
                    needSplitKey.extend([newKey])
                    group += 1
                else:
                    break
     
    if __name__ == '__main__':
        dbe = DiscreateByEntropy(group=6,threshold=0.5)
        data = dbe.loadData()
        dbe.train(data)
        print("result is {}".format(dbe.result))
     
     
     

    运行结果:


        可见,将商品价格分为了5份,下标分别对应了0,1,2,3,4.

  • 相关阅读:
    Analysis Services features supported by SQL Server editions
    Azure DevOps to Azure AppServices
    Power BI For Competition
    Win10开机“提示语音”以及”随机播放音乐”
    Azure DevOps
    Allow Only Ajax Requests For An Action In ASP.NET Core
    Mobile CI/CD 101
    Configure SSL for SharePoint 2013
    AWS Step Function Serverless Applications
    Cordova Upload Images using File Transfer Plugin and .Net core WebAPI
  • 原文地址:https://www.cnblogs.com/SysoCjs/p/11595584.html
Copyright © 2011-2022 走看看