熵被定义为信息的期望值。一个人的性别——男、女——可以看成是一个信息;一件衣服的颜色——很多颜色——也是信息。但是这两种信息一个非常简单,只有两个可能的值,而颜色是非常多的。也可以说颜色的信息量要比性别的信息量要大、要更加混杂。而熵就是衡量这种混杂度的数学指标。
那么具体一点,一个符号A的信息被表示为:
>>> from math import log
>>> probabilityA = 0.5 # the probability of A
>>> log(probabilityA, 2) # the information for A
那么一个数据集的信息量呢?当然就是信息的期望值了,而这个期望值就是香农熵:
In [26]: def calcShannonEnt(dataSet):
....: numEntries = len(dataSet)
....: labelCounts = defaultdict(int)
....: for featVec in dataSet:
....: currentLabel = featVec[-1] # 类别信息,比如男、女
....: labelCounts[currentLabel] += 1 # 计算每类出现的频率
....: shannonEnt = 0.0
....: for key in labelCounts:
....: prob = float(labelCounts[key]) / numEntries # 根据大数定律,如果统计量足够,相对频率就等于概率
....: shannonEnt -= prob * log(prob, 2) # 加入到期望值中(因为prob在[0,1]区间,log结果为负数,所以用-),最终的期望值就是香农熵
....: return shannonEnt
....:
我们来感受一下香农熵所指示的信息混杂度是不是符合我们的感性认识:
如果,我们的数据集中只有两个不同的数据,并且正好属于两个不同的分类,那么这个数据集的信息混杂度就是:
In [47]: dataSet = [[0, 'M'], [1, 'F']]
In [48]: calcShannonEnt(dataSet)
Out[48]: 1.0
如果,我们再加入一个新的类别,那么很明显,信息更加‘混杂’了,看看是不是符合我们的期望呢:
In [49]: dataSet = [[0, 'M'], [1, 'F'], [2, 'S']]
In [50]: calcShannonEnt(dataSet)
Out[50]: 1.584962500721156
信息的混杂度因为加入了一个新的类别而增加了!
再假如说,这个信息集合中有10000个M,而F和S各有一个,那么信息是更混杂了呢还是更清晰了呢?
In [53]: dataSet = [[1, 'F'] for i in range(10000)]
In [54]: dataSet.append([0, 'M'])
In [55]: dataSet.append([2, 'S'])
In [56]: calcShannonEnt(dataSet)
Out[56]: 0.0029455212318187044
可以看到,信息的混杂程度大大地降低了,这也符合我们的直观认识:数据集中基本上全部是F,非常清晰的数据啊!