svm(libsvm)在文本分类中的应用

预备知识:
1)svm:svm(support vector machine)即支持向量机,是一种机器学习算法,2000年左右开始火爆,被认为是(2005年论文上写的)目前分类算法中最好的二个之一(还有一个是boost方法,即使用多个 低分辨率的分类器线性组合成一个高分辨率的模式);根据它的原理,个人认为它和人工神经网络的计算公式本质一样,虽然它们的类切分方式不一样。至少svm是完全的基于超平面,利用核函数进行扩展。已有的证据表面对于基本的多分类来说,RBF(核函数)是效果还比较好的。
2)svm特点:svm具有一个其他分类方法(可能会有,但笔者不知道)都不具备的特点,即不用进行特征简约。特征简约是一个十分麻烦的问题,传统上面的(2000年论文)方法不过那么几种,最好的就是IG(information gain)。但用在文本分类上面,传统的特征简约(feature selection/ dimensionality reduction )达到不了什么很好的效果。之前我们的一个项目就是人工进行特征简约的,大约花费了1人1周时间,效果还不怎么样(KNN算法,80%左右精度。KNN的平均性能比除了SVM的其他普通分类算法都好,有论文里面有实验结果)。现在使用的特征简约方法一般都会基于文本分类的特点,比如,会先进行特征的分类。svm则不需要进行特征简约!它具有很强的抗干扰能力,特别是,有人研究表明,大部分时候,不进行特征简约得到的精度比进行了特征简约之后得到的精度还要高。这或许是因为有些看起来十分没有用的词语,比如,“有限公司”,它可能也代表了一种很强烈的区分方式,比如,名字含有“有限公司”的公司可能一般都是纺织(石油)等行业。
3)svm分类精度:knn出现的时间很早了,在它出现之后,大量出现了各种机器学习算法,比如,决策树(decision tree),人工神经网络,贝叶斯分类等等,可惜的是,研究结果表明,这些算法的平均分类精度居然还不如knn(一般差10%左右)。svm是第一个(论文里面说的)达到knn分类精度的分类算法。当然了,并不是说所有的时候,knn都最好,精度高不高,要看环境,要看使用者。

本文主要说明一下使用libsvm这个著名的软件来进行文本分类的具体方式。首先,请大家看看 入门文章:http://ntu.csie.org/~piaip/svm/svm_tutorial.html

现在假设大家已经看过入门文章,并且实际的操作过之后,我们来解决几个应用上的问题:

1)scale的必要性:scale就是把每个特征的值映射到[0,1]或者[-1,1]上面。首先应该明白,libsvm里面的svmtrain.exe是不要求输入的样本矩阵的每个值一定要在[0,1]或者[-1,1]范围的。那为什么要把值映射到这2个范围内呢?2个原因:a)为了计算速度;b)为了计算精度。第一个原因在入门文章里说的很清楚了,那第二个原因是怎么回事呢?在使用easy.py进行c和g参数选择的时候,会在某个范围内进行选择的,问题就是在这里。这个范围是一个小范围,只有在特征的值都在上述范围的时候,才比较有可能从这个范围中找到很好的参数。
2)scale的处理:scale的处理方法有多种,但是,libsvm里面提供的svmscale.exe是很不好的一种。为什么?因为它的算法是基于样本列表的。可能会发生将来待分类的数据的特征值都比较大,最后会被分到同一个类里面!所以,你自己需要做一个scale的方法来处理这类情况。一个简单的做法就是,给每个特征一个最大的可能值,然后再线性映射到[0,1]上面。注意,是[0,1],不是[-1,1],这是因为文本分类的时候,得到的特征向量里面,大部分特征的值都为0,映射到[0,1]可以加快计算速度。
3)easy.py的说明:仔细的分析easy.py里面的命令代码,你可以看到,easy.py做了几件事:a)调用svmscale.exe来scale原始样本向量;b)遍历预设的c和g参数;c)调用svmtrain.exe的交叉检验功能(-v参数)来计算c和g参数的精度;d)获得一个最好的精度,根据对应的c和g计算一个模型。如果你已经scale过输入了,就应该在这里把第一步注释掉,因为默认是把值scale到[-1,1]范围。
4)提高计算速度:文本分类的时候,特征一般选取为词语(关键词),特征的值一般选取为词语的出现次数。这样一来,数据的空间维度很高(经常是5K - 10K之间)。easy.py会扫描大约11*10=110次,每次都调用svmtrain.exe的交叉检验功能,而svmtrain的交叉检验功能,需要n(样本分成n份进行交叉检验)次计算和(n-1)*n次predict。反正就是说,easy.py运行一次,时间很长很长,一般在110*5*(2-10)分钟左右。提高计算速度的方法至少有:a)svmtrain.exe的-m参数,设置cache特别大(800M?);b)修改easy.py里面的c和g的范围,然后跑多个进程(多cpu时)。

简简单单的使用libsvm,在理解了svm的基础上,你就会发现,文本分类非它莫属了。

后记:
        以上简单的介绍已经是很久前的事情了,虽然当初对其作了一些简单的研究,但因为各个方面的原因,没有做过多的探讨,只是能用,会用就完了。
        最近一个朋友请我帮他们做一个简单的分类,努力了2天之后,我发现了一些未考虑到的问题。主要有:
1)特征选取:
        理论和实践表明了svm是用不着进行特征简约(即选取)的,但考虑到计算时间复杂度,必须把特征的个数限制在一个合理的范围内。需要进行特征选择的另外一个原因是样本的选取。一般来说,样本的选择在最初(可能以后也如此)很难保证其 准确 和 全集同分布性。有效的进行特征筛选是必要的。进行特征选择的第3个原因是:各个类型的权重不同。举例来说,你可以把大量的垃圾邮件都划分到正确邮件里面,但不能把大量的正确邮件都当成垃圾邮件。
        特征选取的基本解决方案:a) 重要的分类手动(或者半自动)选择特征,确保不引入一个垃圾特征;b) 非重要的分类自动(或者半自动)选择特征;c)构建一个特征过滤程序过滤特征(比如,数字,email,基本英文,单个汉字,一般词语等等);d)为了保证计算速度,最后的特征个数在10K以内。
        因为样本的选择难以精确,故直接使用普通的特征简约方法得到的结果效果很差。这是因为有些只出现了一次的词语其区分度其实特别高,甚至可能它就代表了某个行业。
       有关特征简约的算法,可以参考另外一篇文章:http://hi.baidu.com/algorithms/blog/item/565243d9c5c009e238012f1e.html

2)特征值的计算:
      特征值的计算也是一个值得关注的问题。一般我们直接把特征(词语)在文本中出现的次数当作其特征值。我们需要把这个次数映射到[0,1]空间上。最近我们使用的计算公式为:
      weight = 词语出现的次数 / n ;
      weight = weight > 1? 1:weight;
      其中,n = ln(特征在样本中出现的次数)。
3)文档分类:
      假设文档包含了多个属性,每个属性是一个文本类型,属性的权重不同。在分类的时候,有几种策略。
      策略一:每个属性构建一个分类模型;根据权重进行排序,当前一个模型不能识别的时候,就使用下一个模型分类;
      策略二:对属性和其对应模型来说,计算它和里面最相似的分类的相似度;根据这个相似度来选择最后的分类;
      策略三:把属性的值合并到一起(权重大的属性值重复若干次?),构建一个分类模型。
      在这里,一个经验之谈是:文本越短,其样本精度越高,分类越准确。

posted @ 2010-04-16 15:40  大CC  阅读(9936)  评论(0编辑  收藏  举报
木书架 大CC的博客