您的位置:首页 > 其它

特征选择之信息增益

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

熵(Entropy)

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

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

如何量化信息

平时我们会这样说”这句话信息量好大”,我们通常所指的信息是指那句话里的语义,而这里我们谈的信息则是信息论鼻祖Shannon定义的,Shannon老爷子认为消息传递的过程是这样的:消息首先被编码器编码之后经过一定的通道再经过解码器解码,最后信息传递给目标。那么目标者能获得多少原来的信息则是我们这里所谈的信息,这样的信息可能是一堆废话,完全没”信息量”。

我们知道信息在传递的时候有很多不确定因素,而量化不确定因素的一个利器就是概率论,那么在概率框架下的信息的定义是这样的:对于一个事件i,那么当观察到该事件的时候,我们到底获得多少信息呢?Shannon老爷子是这样定义信息函数的:

I(p)=−log(p)等。为什么要以对数来定义呢?在老爷子自己的开山大作《A Mathematical Theory of Communication》中给了三个理由:

第一,这样定义在实际中非常有用(不管黑猫白猫理论),工程的重要参数随数据概率的对数而线性改变。如时间、带宽、继电器数,等等。

第二,对数更接近我们本身的直观感受,我们是线性直观地测量实体对象,例如两张穿孔卡片比一张具有有两倍信息贮存量。

第三,以对数定义信息在数学上可以得到极大便利。

信息函数的性质

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

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

那么回过头来看看我们的老朋友熵:

H(X)=−∑xp(x)logp(x)=∑xp(x)I(x)所构成的图像是怎样的:



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

条件熵(Conditional Entropy)

我们的目的是特征选择,那么现在假设我们在做一个垃圾分类器,首先我们从训练数据X={x1,x2,...,xn},然后通过我们熟悉的机器学习算法比如SVM,NaiveBayes,LogisticRegression等等,从训练数据中获得这样的模型:

f(F)=C变小,降低到几千或者几百。接下来进入我们的尝试阶段。

定义

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

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)

性质

好吧,看容貌,条件熵更加平易远人,我们知道熵是非负的,那么上面那一坨定义是否也是非负呢?利用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的上界(upbound)。

现在先不管复杂的表达式,我们试之从直觉上理解。上一节我们了解到熵是衡量事件发生的可预知性,那么条件熵我们可以这样理解,事件Z的预知能力变强了。

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

那么对于分类器而言,我们想知道某个特征对于分类这样的事件到底有多大贡献,然后对贡献太小的特征就舍弃,从而达到特征选择地效果。现在我们就进行尝试,假设我们有一个事件F的大小从而决定该特征是对识别为垃圾的事件贡献大还是对识别为非垃圾的贡献大呢?答案是否定的,因为两者不具备可比性,为什么呢?因为两者具有不同的上界,不在同一标准,所以不具备可比性。那该怎么办呢?

信息增益(Information Gain)

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

定义

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

IG(X,Z)=H(X)−H(X|Z)=H(Z)−H(Z|X)上界,就已经出现上述所示。这次我们并不是要证明什么上界下界,我们直接对其差值进行定义,并取名字为信息增益(Information Gain)。

性质

我们照常来看看信息增益的一些性质。首先从定义可以很容易知道它符合交换律,也就是
IG(X,Z)=IG(Z,X)提供了多少信息。通过定义我们可以很容易验证两种描述都是正确的。因此我们称之为信息增益,观察到一个事件,另一个事件获得了多少信息。我们类比一下高中学过的重力势能,不同高度的重力势能是不同的,但是对于相同的高度差,重力势能的差值却是相同的。

由于两个事件相互的信息增益是相同的,所以信息增益也叫相互信息(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))之间的散度。

利用信息增益做特征选择

上一节中,我们说过H(C=1|f1),H(C=0|f2)个特征,我们就达到利用信息增益做特征选择的目的!

信息增益法在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),计算熵的时候,涉及到概率计算,我们通常都是采用极大似然法来估计概率,各个概率的估计如下:

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

p(C=0)=count(c=0)Np(C=1)=1−p(C=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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55


[/code]

对于每个特征计算信息增益后,进行排序,然后就可以愉快地取前K个特征了!

参考文献

维基百科Entropy: https://en.wikipedia.org/wiki/Entropy_(information_theory)

课程Text Mining and Analytics第一周最后4节:https://class.coursera.org/textanalytics-001/lecture
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: