特征选择指的是按照一定的规则从原来的特征集合中选择出一小部分最为有效的特征。通过特征选择,一些和任务无关或是冗余的特征被删除,从而提高数据处理的效率。
文本数据的特征选择研究的重点就是用来衡量单词重要性的评估函数,其过程就是首先根据这个评估函数来给每一个单词计算出一个重要性的值,然后根据预先设定好的阈值来选择出所有其值超过这个阈值的单词。
根据特征选择过程与后续数据挖掘算法的关联,特征选择方法可分为过滤、封装和嵌入。
(1)过滤方法(Filter Approach):使用某种独立于数据挖掘任务的方法,在数据挖掘算法运行之前进行特征选择,即先过滤特征集产生一个最有价值的特征子集。或者说,过滤方法只使用数据集来评价每个特征的相关性, 它并不直接优化任何特定的分类器, 也就是说特征子集的选择和后续的分类算法无关。
(2)封装方法(Wrapper Approach):将学习算法的结果作为特征子集评价准则的一部分,根据算法生成规则的分类精度选择特征子集。该类算法具有使得生成规则分类精度高的优点,但特征选择效率较低。封装方法与过滤方法正好相反, 它直接优化某一特定的分类器, 使用后续分类算法来评价候选特征子集的质量。
一般说来, 过滤方法的效率比较高, 结果与采用的分类算法没有关系, 但效果稍差;封装方法占用的运算时间较多, 结果依赖于采用的分类算法, 也因为这样其效果较好。
(3)嵌入方法(embedded Approach):特征选择作为数据挖掘算法的一部分自然地出现。在数据挖掘算法运行期间,算法本身决定使用哪些属性和忽略哪些特征,如决策树C4.5分类算法。
如果将过滤方法和封装方法结合,就产生了第四种方法:
(4)混合方法(Hybrid Approach):过滤方法和封装方法的结合,先用过滤方法从原始数据集中过滤出一个候选特征子集,然后用封装方法从候选特征子集中得到特征子集。该方法具有过滤方法和封装方法两者的优点,即效率高,效果好。
根据特征选择过程是否用到类信息的指导,即其评估函数是否依赖类信息,特征选择可分为监督式特征选择(需要依赖类信息的有监督特征选择,只能用于文本分类)、无监督式特征选择(不需要依赖类信息的无监督特征选择,用于文本分类和文本聚类)。
(1)监督式特征选择(supervised feature selection):使用类信息来进行指导,通过度量类信息与特征之间的相互关系来确定子集大小。
(2)无监督式特征选择(unsupervised feature selection):在没有类信息的指导下,使用样本聚类或特征聚类对聚类过程中的特征贡献度进行评估,根据贡献度的大小进行特征选择。
下面,我先介绍有监督特征选择方法IG(Information Gain信息增益)和CHI(X2 statistic卡方统计)及它们相应的Java实现。由于这两者需要的数据是相同的:clusterMember类别成员类,特征所在文本集,DF集,需要做的事情是相同的:进行特征选择得到特征重要性集,所以我写了一个抽象父类Supervisor:
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
*
* @author Angela
*/
public abstract class Supervisor {
protected Map<Integer,List<String>> clusterMember;//簇成员
protected Map<String,Set<String>> featureIndex;//特征-文本名集
protected Map<String,Integer> DF;//DF集
protected int textNum;//总文本数
protected Set<String> featureSet;//特征集
protected Map<String,Double> featureMap;//特征重要性集
/**
* 构造函数,初始化各个数据
* @param clusterMember 类别成员
* @param featureIndex
* @param DF
*/
public Supervisor(Map<Integer,List<String>> clusterMember,
Map<String,Set<String>> featureIndex,Map<String,Integer> DF){
this.clusterMember=clusterMember;
textNum=0;
for(Map.Entry<Integer,List<String>> me: clusterMember.entrySet()){
textNum+=me.getValue().size();//计算文本数
}
this.featureIndex=featureIndex;
this.DF=DF;
featureSet=DF.keySet();//得到特征集
featureMap=new HashMap<String,Double>();
}
/**
* 进行特征选择,得到featureMap
* @return 特征-重要性集
*/
public abstract Map<String,Double> selecting();
}
IG
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
*
* @author Angela
*/
public class IG extends Supervisor{
public IG(Map<Integer,List<String>> clusterMember,
Map<String,Set<String>> featureIndex,Map<String,Integer> DF){
super(clusterMember,featureIndex,DF);
}
/**
* 计算文本集的熵
* @return 总熵
*/
public double computeEntropyOfCluster(){
double entropy=0;//文本集的熵
double pro;//类的概率
double temp;//类的熵
for(Map.Entry<Integer,List<String>> me:clusterMember.entrySet()){
pro=(double)me.getValue().size()/textNum;
temp=pro*Math.log(pro);
entropy+=temp;
}
return -entropy;
}
/**
* 计算特征的条件熵
* @param f 特征
* @return 特征f的条件熵
*/
public double computeConditionalEntropy(String f){
double ce=0;
double df=DF.get(f); //含有特征f的文本总数
double nf=textNum-df;
Set<String> text=featureIndex.get(f);//含有特征f的文本
double proOfCF1;//P(Ci|T)
double proOfCF2;//P(Ci|!T)
double value1=0;//P(Ci|T)log2(P(Ci|T))的和
double value2=0;//P(Ci|!T)