设计分类系统的时候,一个很重要的环节便是特征选择,面对成千上万上百万的特征,如何选取有利于分类的特征呢?信息增益(Information Gain)法就是其中一种简单高效的做法。本文首先介绍理解信息增益(Information Gain)需要的基本概念,之后介绍如何将其运用在特征选择中,最后以stanford-nlp中利用信息增益法实现特征选择的例子结束本文。

熵(Entropy)

介绍信息增益大法前,不得不提的一个概念就是熵。熵是信息论中一个很重要的概念,我们先看看它的长相:

H(X)=−∑xp(x)logp(x)

H(X)=-\sum_x p(x)logp(x)不得不承认,熵长得挺恶心的,从表达式中完全看不出半点端倪,根本不知道它有何作用。别急,我们慢慢研究,希望最后可以得到一个直观理解。

如何量化信息

平时我们会这样说”这句话信息量好大”,我们通常所指的信息是指那句话里的语义,而这里我们谈的信息则是信息论鼻祖Shannon定义的,Shannon老爷子认为消息传递的过程是这样的:消息首先被编码器编码之后经过一定的通道再经过解码器解码,最后信息传递给目标。那么目标者能获得多少原来的信息则是我们这里所谈的信息,这样的信息可能是一堆废话,完全没”信息量”。
我们知道信息在传递的时候有很多不确定因素,而量化不确定因素的一个利器就是概率论,那么在概率框架下的信息的定义是这样的:对于一个事件ii,它发生的概率是pip_i,那么当观察到该事件的时候,我们到底获得多少信息呢?Shannon老爷子是这样定义信息函数的:

I(p)=−log(p)

I(p)=-log(p),并规定底可以取大于1的任意数,通常可以取 2,e,102,e,10等。为什么要以对数来定义呢?在老爷子自己的开山大作 《A Mathematical Theory of Communication》中给了三个理由:

第一,这样定义在实际中非常有用(不管黑猫白猫理论),工程的重要参数随数据概率的对数而线性改变。如时间、带宽、继电器数,等等。
第二,对数更接近我们本身的直观感受,我们是线性直观地测量实体对象,例如两张穿孔卡片比一张具有有两倍信息贮存量。
第三,以对数定义信息在数学上可以得到极大便利。

信息函数的性质

我们参考一下维基百科看看这样定义的性质有什么:

I(p)>=0......(1)I(1)=0......(2)I(p1,p2)=I(p1)+I(p2)......(3)

I(p) >= 0......(1)\\I(1)=0......(2)\\I(p_1,p_2)=I(p_1)+I(p_2)......(3)(1)式讲的是信息是非负的,我们最坏情况是得不到信息。(2)式表面必然发生的事情是不含信息量的,如果我们被告知地球是球状的,我们不会获得什么直接信息吧(除了觉得那个人有毛病)。(3)式则是说对于两个独立事件发生产生的信息量等于我们各自观察每个事件所获得的信息量。看,这样定义信息其实也挺符合我们对信息的通常理解。
那么回过头来看看我们的老朋友熵:

H(X)=−∑xp(x)logp(x)=∑xp(x)I(x)

H(X)=-\sum_x p(x)logp(x)=\sum_xp(x)I(x)那么熵可以看成是观察事件 XX发生后我们获得的期望信息量,如果H(x)H(x)越大,那么说明我们获得的信息量越大,同时也说明 XX更趋向于均匀分布,由上面(2)式可知,信息量大不大反应于我们对事件发生可预知的概率大不大,如果我们知道事件肯定发生或者肯定不发生,我们得到的信息量是0,而越是对事件越不确定,越能够从这样的事件获得信息。那么当事件发生的概率是0.5的时候,我们获得最大的熵。再看一个常见的例子,假如我们在抛一枚硬币的事件是XX,我们看看 H(X)H(X)与看到正面的事件的概率 Pr(X=1)Pr(X=1)所构成的图像是怎样的:

从图像中我们可以知道,当 Pr(X=1)=0.5Pr(X=1)=0.5的时候, H(X)H(X)达到峰值。因此我们可以这样直观地理解熵:熵是用来衡量事件可预知性,熵越大,事件发生的概率越随机。

条件熵(Conditional Entropy)

我们的目的是特征选择,那么现在假设我们在做一个垃圾分类器,首先我们从训练数据X={x1,x2,...,xn}X=\{x_1,x_2,...,x_n\}中抽取特征,将每个输入xix_i映射到特征空间Fi={f1,f2,...,fm}F^i=\{f_1,f_2,...,f_m\},然后通过我们熟悉的机器学习算法比如SVM,NaiveBayes,LogisticRegression等等,从训练数据中获得这样的模型:

f(F)=C

f(F)=C C=1C=1代表输入是垃圾, C=0C=0代表是输入非垃圾。很不幸,通常 mm将会很大,几万或几百万,这样不仅导致冗长的训练时间,甚至导致严重的Overfitting。那么我们便希望通过某种方法,将mm变小,降低到几千或者几百。接下来进入我们的尝试阶段。

定义

我们先来看看这小节的主角的形象:

H(X|Z)=−∑zp(z)∑xp(x|z)log(p(x|z))=−∑x∑zp(z)p(x|z)log(p(x|z))=−∑x∑zp(x,z)logp(x,z)p(z)=∑x∑zp(x,z)logp(z)p(x,z)

H(X|Z)\\=-\sum_zp(z)\sum_xp(x|z)log(p(x|z))\\=-\sum_x\sum_zp(z)p(x|z)log(p(x|z))\\=-\sum_x\sum_zp(x,z)log\frac{p(x,z)}{p(z)}\\=\sum_x\sum_zp(x,z)log\frac{p(z)}{p(x,z)}

性质

好吧,看容貌,条件熵更加平易远人,我们知道熵是非负的,那么上面那一坨定义是否也是非负呢?利用Jensen不等式我们可以检验:

H(X|Z)=∑x∑zp(x,z)logp(z)p(x,z)≥log∑x∑zp(x,z)p(z)p(x,z)=log∑zp(z)=0

H(X|Z)=\sum_x\sum_zp(x,z)log\frac{p(z)}{p(x,z)}\ge \\log\sum_x\sum_zp(x,z)\frac{p(z)}{p(x,z)}=log\sum_zp(z)=0那么我们的定义应该没有问题。我们再来看看它和单独的 H(X)H(X)有什么关系,我们可以检验一下 H(X)−H(X|Z)H(X)-H(X|Z)的正负性,经过类似上面的推导,我们知道:

H(X)≥H(X|Z)

H(X)\ge H(X|Z)也就是 H(X)H(X)是 H(X|Z)H(X|Z)的上界(upbound)。

现在先不管复杂的表达式,我们试之从直觉上理解。上一节我们了解到熵是衡量事件发生的可预知性,那么条件熵我们可以这样理解,事件ZZ发生了对于我们知道事件XX有什么贡献。当事件ZZ发生了但是完全没贡献时候,当前仅当H(X)=H(X|Z)H(X)=H(X|Z),此时事件XX与事件ZZ相互独立,否则,只要H(X|Z)≥0H(X|Z)\ge 0,事件ZZ就对我们预知事件XX有贡献,因为H(X|Z)≤H(X)H(X|Z)\le H(X)的,ZZ的出现导致熵变小了,我们对事件XX的预知能力变强了。

尝试利用条件熵做特征选择

那么对于分类器而言,我们想知道某个特征对于分类这样的事件到底有多大贡献,然后对贡献太小的特征就舍弃,从而达到特征选择地效果。现在我们就进行尝试,假设我们有一个事件FF,f1=1f_1=1代表在我们拥有f2,f3,...,fmf_2,f_3,...,f_m的情况下,再包含特征f1f_1的事件,f1=0f_1=0则表明不包含特征f1f_1的事件。那么我们想知道f1,f2f_1,f_2对于我们识别垃圾到底哪个贡献大,我们可以比较H(C=1|f1),H(C=1|f2)H(C=1|f_1),H(C=1|f_2)看看哪个更小,熵小的特征说明对于识别信息为垃圾的事件贡献更大。于是我们计算所有特征都的H(C=1|fi)H(C=1|f_i),按照从小到大排序,取前KK个特征,太棒了,貌似我们解决了特征选择问题了。但是我们再仔细思考一下,上面的做法只是筛选出了对于识别是垃圾这种类别有用的特征,但是可能刷掉了对于识别非垃圾事件有用的特征,怎么办呢?我们可不可以比较一下H(C=1|f1),H(C=0|f1)H(C=1|f_1),H(C=0|f_1)的大小从而决定该特征是对识别为垃圾的事件贡献大还是对识别为非垃圾的贡献大呢?答案是否定的,因为两者不具备可比性,为什么呢?因为两者具有不同的上界,不在同一标准,所以不具备可比性。那该怎么办呢?

信息增益(Information Gain)

上一节我们一开始以为找到了特征选择的办法,后来发现是不可行的,这一次,我们的主角将为我们解决难题。

定义

老套路,我们还是先看看老兄的形象:

IG(X,Z)=H(X)−H(X|Z)=H(Z)−H(Z|X)

IG(X,Z)=H(X)-H(X|Z)=H(Z)-H(Z|X)有了前两节的基础,老兄并不那么面目可憎,反而有点熟悉,似曾相识。没错,你没有认错,上一节中我们为了证明 H(X)H(X)是 H(X|Z)H(X|Z)上界,就已经出现上述所示。这次我们并不是要证明什么上界下界,我们直接对其差值进行定义,并取名字为信息增益(Information Gain)。

性质

我们照常来看看信息增益的一些性质。首先从定义可以很容易知道它符合交换律,也就是

IG(X,Z)=IG(Z,X)

IG(X,Z)=IG(Z,X),其次信息增益具有非负性

IG(X,Z)≥0

IG(X,Z) \ge 0当且仅当 X,ZX,Z相互独立的时候等号取得成立。我们可以这样直观地理解信息增益的含义:观察到事件 ZZ对于我们预知XX提供了多少信息,或者观察到事件 XX对于我们预知ZZ提供了多少信息。通过定义我们可以很容易验证两种描述都是正确的。因此我们称之为信息增益,观察到一个事件,另一个事件获得了多少信息。我们类比一下高中学过的重力势能,不同高度的重力势能是不同的,但是对于相同的高度差,重力势能的差值却是相同的。
由于两个事件相互的信息增益是相同的,所以信息增益也叫相互信息(Mutual Information)。对于定义,我们可以展开重写一下:

IG(X,Z)=H(X)−H(X|Z)=−∑xp(x)logp(x)+∑z∑xp(x,z)logp(x,z)p(z)=−∑x∑zp(x,z)logp(x)+∑z∑xp(x,z)logp(x,z)p(z)=∑z∑xp(x,z)logp(x,z)p(z)p(x)=KL(p(x,z)||p(x)p(z))

IG(X,Z)=H(X)-H(X|Z)\\=-\sum_xp(x)logp(x)+\sum_z\sum_xp(x,z)log\frac{p(x,z)}{p(z)}\\=-\sum_x\sum_zp(x,z)logp(x)+\sum_z\sum_xp(x,z)log\frac{p(x,z)}{p(z)}\\=\sum_z\sum_xp(x,z)log\frac{p(x,z)}{p(z)p(x)}=KL(p(x,z)||p(x)p(z))突然出现一个新人物,Kullback-Leibler Divergence,对于 KL(p||q)KL(p||q),可以近似认为他是衡量分布p与q的距离,当两个分布相同的时候,KL散度为0,越是不同,KL散度越大。所以信息增益又被称为Information Divergence。我们可以理解为它是衡量联合分布 p(x,z)p(x,z)与假设他们 X,ZX,Z相互独立时的联合分布 p(x)p(z)p(x)p(z)之间的散度。

利用信息增益做特征选择

上一节中,我们说过H(C=1|f1),H(C=0|f2)H(C=1|f_1),H(C=0|f_2)不具备可比性,因为他们具有不同的上界H(C=1),H(C=0)H(C=1),H(C=0),从而阻止我们利用条件熵来做特征选择,这次我们利用信息增益再看看会不会有相同问题。我们看

IG(C=1,f1)与IG(C=0,f1)

IG(C=1,f_1)与IG(C=0,f_1)是否具有可比性,由于两者都是算当包含或不包含特征 f1f_1的时候,为识别为垃圾的事件带来多少信息,为识别为非垃圾带来多少信息,那么我们可以直接用

IG(C,f1)

IG(C,f_1)来衡量特征当包含或不包含 f1f_1的时候,为分类器的识别提供了多少信息量,同理可以利用

IG(C,f2)

IG(C,f_2)来衡量包含或不包含特征 f2f_2为分类器提供了多少信息量,依次类推,我们分别求出每个特征对分类器提供的信息量,然后从大到小进行排序,取前 KK个特征,我们就达到利用信息增益做特征选择的目的!

信息增益法在stanford-nlp的应用

前面讲了那么多理论,该是大显身手的时候了。我们再回过头来看如何求取分类与特征之间的信息增益。首先观察定义:

IG(C,fi)=H(C)−H(C|fi)=−∑c∈{0,1}p(c)logp(c)+∑fi∈{0,1}p(fi)∑c∈{0,1}p(c|fi)logp(c|fi)

IG(C,f_i)=H(C)-H(C|f_i)\\=-\sum_{c\in\{0,1\}}p(c)logp(c)+\sum_{f_i\in\{0,1\}}p(f_i)\sum_{c\in\{0,1\}}p(c|f_i)logp(c|f_i),我们知道计算信息增益分为两部分,一部分是计算类别 CC的熵H(C)H(C),另一部分是计算在事件 fif_i下的条件熵 H(C|fi)H(C|f_i),计算熵的时候,涉及到概率计算,我们通常都是采用极大似然法来估计概率,各个概率的估计如下:

假设我们的训练样本数是NN

p(C=0)=count(c=0)Np(C=1)=1−p(C=0)

p(C=0)=\frac{count(c=0)}{N}\\p(C=1)=1-p(C=0)对于p(fi)和p(c|fi)p(f_i)和p(c|f_i)的估计,stanford-nlp中首先是对每个训练样本进行统计,对于每个特征fif_i在训练样本xx中只要出现过就加一次,出现两次也算一次。这样计数下来就可以统计到每个特征的featureCount。那么接下来的估计如下:

p(fi=1)=count(fi=1)Np(fi=0)=1−p(fi)p(C=0|fi=1)=count(C=0,fi=1)count(fi=1)p(C=1|fi=1)=count(C=1,fi=1)count(fi=1)p(C=0|fi=0)=count(C=0,fi=0)count(fi=0)p(C=1|fi=0)=count(C=1,fi=0)count(fi=0)

p(f_i=1)=\frac{count(f_i=1)}{N}\\p(f_i=0)=1-p(f_i)\\p(C=0|f_i=1)=\frac{count(C=0,f_i=1)}{count(f_i=1)}\\p(C=1|f_i=1)=\frac{count(C=1,f_i=1)}{count(f_i=1)}\\p(C=0|f_i=0)=\frac{count(C=0,f_i=0)}{count(f_i=0)}\\p(C=1|f_i=0)=\frac{count(C=1,f_i=0)}{count(f_i=0)}
且看Dataset里面的一段代码:

  public double[] getInformationGains() {labels = trimToSize(labels);ClassicCounter<F> featureCounter = new ClassicCounter<F>();ClassicCounter<L> labelCounter = new ClassicCounter<L>();TwoDimensionalCounter<F,L> condCounter = new TwoDimensionalCounter<F,L>();for (int i = 0; i < labels.length; i++) {labelCounter.incrementCount(labelIndex.get(labels[i]));boolean[] doc = new boolean[featureIndex.size()];for (int j = 0; j < data[i].length; j++) {doc[data[i][j]] = true;//标识一下特征是否出现过}for (int j = 0; j < doc.length; j++) {if (doc[j]) {//统计count(fi)和count(c|fi)featureCounter.incrementCount(featureIndex.get(j));condCounter.incrementCount(featureIndex.get(j), labelIndex.get(labels[i]), 1.0);}}}double entropy = 0.0;//计算H(C)for (int i = 0; i < labelIndex.size(); i++) {double labelCount = labelCounter.getCount(labelIndex.get(i));double p = labelCount / size();entropy -= p * (Math.log(p) / Math.log(2));}double[] ig = new double[featureIndex.size()];Arrays.fill(ig, entropy);//计算H(C|fi)for (int i = 0; i < featureIndex.size(); i++) {F feature = featureIndex.get(i);double featureCount = featureCounter.getCount(feature);//count(fi=1)double notFeatureCount = size() - featureCount;//count(fi=0)double pFeature =  featureCount / size();//p(fi=1)double pNotFeature = (1.0 - pFeature);//p(fi=0)if (featureCount == 0) { ig[i] = 0; continue; }if (notFeatureCount == 0) { ig[i] = 0; continue; }double sumFeature = 0.0;double sumNotFeature = 0.0;for (int j = 0; j < labelIndex.size(); j++) {L label = labelIndex.get(j);double featureLabelCount = condCounter.getCount(feature, label);//count(c,fi=1)double notFeatureLabelCount = size() - featureLabelCount;//count(c,fi=0)double p = featureLabelCount / featureCount;//p(c|fi=1)double pNot = notFeatureLabelCount / notFeatureCount;//p(c|fi=0)if (featureLabelCount != 0) {sumFeature += p * (Math.log(p) / Math.log(2));}if (notFeatureLabelCount != 0) {sumNotFeature += pNot * (Math.log(pNot) / Math.log(2));}}ig[i] += pFeature*sumFeature + pNotFeature*sumNotFeature;//最后H(C)+H(C|F)return ig;}

对于每个特征计算信息增益后,进行排序,然后就可以愉快地取前K<script type="math/tex" id="MathJax-Element-89">K</script>个特征了!

参考文献

维基百科Entropy: https://en.wikipedia.org/wiki/Entropy_(information_theory)
课程Text Mining and Analytics第一周最后4节:https://class.coursera.org/textanalytics-001/lecture

特征选择之信息增益法相关推荐

  1. 光谱特征选择---非信息变量剔除UVE

    作为光谱分析的经典算法之一,非信息变量剔除(Uninformative Variables Elimination, UVE)自1996年提出后一直被广泛应用于光谱分析领域,至今相关的研究论文都在使用 ...

  2. python文本分类特征选择_文本挖掘之特征选择(python 实现)

    机器学习算法的空间.时间复杂度依赖于输入数据的规模,维度规约(Dimensionality reduction)则是一种被用于降低输入数据维数的方法.维度规约可以分为两类: 特征选择(feature ...

  3. 文本分类特征选择方法

    1)DF(DocumentFrequency) 文档频率 DF:统计特征词出现的文档数量,用来衡量某个特征词的重要性 2)MI(MutualInformation) 互信息法 互信息法用于衡量特征词与 ...

  4. 文本分类--普通分类

    1 基本概念 文本分类 文本分类(text classification),指的是将一个文档归类到一个或多个类别的自然语言处理任务.文本分类的应用场景非常广泛,包括垃圾邮件过滤.自动打标等任何需要自动 ...

  5. 机器学习深度学习知识点总结

    1.Overfitting是什么?怎么解决? overfitting就是过拟合, 其直观的表现如下图所示,随着训练过程的进行,模型复杂度增加,在training data上的error渐渐减小,但是在 ...

  6. NLP︱句子级、词语级以及句子-词语之间相似性(相关名称:文档特征、词特征、词权重)

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 关于相似性以及文档特征.词特征有太多种说法.弄 ...

  7. 机器学习面试题总结!!!!

    需要内推三七互娱的盆友萌,(9月5号截止)可以参考另一篇文章,或者内推QQ群:175423207 BAT机器学习面试系列 1.请简要介绍下SVM. SVM,全称是support vector mach ...

  8. 算法模型---树相关---决策树

    决策树的特点 决策树的用途 决策树的适用范围 数据类型 特征可以连续和离散 因变量分类时是离散,回归时是连续 算法 支持模型 树结构 特征选择 连续值处理 缺失值处理 剪枝 ID3 分类 多叉树 信息 ...

  9. 大二文本分词过滤分类实验总结

    这次作业的内容是给定一个体育分类测试文档和体育分类训练文档,以体育分类训练文档为训练集,体育分类测试文档为测试集,选择一种特征选择算法对训练集样本进行特征选择:选择一种文本分类算法对训练集样本进行文本 ...

最新文章

  1. 8、Kubernetes核心技术Service
  2. @PropertySource读取外部配置文件中的k-v保存到运行的环境变量中,加载完微博的配置文件以后使用${}取配置文件中的键值
  3. JPA学习笔记2——JPA高级
  4. Unity 4.3 2D 教程:新手上路
  5. vue本地没事放到服务器上无限循环,解决vue中的无限循环问题
  6. 笔试面试常考数据结构-单链表常用操作编程实现
  7. mysql建立外键快捷方式_mysql建立外键
  8. python 在线编程 实现_Python进阶开发之网络编程,socket实现在线聊天机器人
  9. 完整HTML实例网页代码(1)
  10. android3.0新功能,PCWorld:Android 3.0最受期待的五大新功能
  11. Struts2默认拦截器
  12. 第十一届蓝桥杯 2020年省赛真题 (C/C++ 大学A组) 第一场
  13. PHP输出星座,php 通过日期推算星座的方法
  14. 企业微信调试H5页面
  15. mysql netcdf_NetCDF官方读写终端ncdump和ncgen的用法
  16. 两种图像骨架提取算法的研究原理及实现
  17. C++ 制作简易音乐播放器
  18. 如何0基础学传奇开服技术?(学传奇开服技术教程)
  19. Python爬取图片、视频以及将数据写入excel的方法小摘要
  20. 研究生阶段如何学习、做研究

热门文章

  1. VVC学习之二:VTM中CU划分结构QTMTT(3):打印QTMTT最终划分
  2. 学嵌入式,一定要买开发板吗?
  3. ECSHOP全版本注入漏洞分析
  4. 欧国联 18/19 冰岛 vs 瑞士 分析
  5. java 照片识别 自动判题,【判断题】throw关键字只可以抛出Java能够自动识别的异常。...
  6. OMNI USDT 0.11.0 环境部署
  7. JSP基础程序以及指令的使用
  8. 人工智能现在已经可以参与操纵高超音速飞行器
  9. 红象云腾CRH 一键部署大数据平台
  10. Linux关闭防火墙命令(centos 7)