基于libsvm的中文文本分类原型

李海波

http://blog.csdn.net/marising/article/details/5844063

支持向量机(Support Vector Machine)是Cortes和Vapnik于1995年首先提出的,它在解决小样本非线性高维模式识别 中表现出许多特有的优势,并能够推广应用到函数拟合等其他机器学习问题中。支持向量机方法是建立在统计学习理论的VC 维理论和结构风险最小 原理基础上的,根据有限的样本信息在模型的复杂性(即对特定训练样本的学习精度,Accuracy)和学习能力(即无错误地识别任意样本的能力)之间寻求最佳折衷,以期获得最好的推广能力(或称泛化能力)。SVM理论的学习,请参考jasper的博客 http://www.blogjava.net/zhenandaci/category/31868.html

LIBSVM 是台湾大学林智仁(Chih-Jen Lin)博士等开发设计的一个操作简单、易于使用、快速有效的通用 SVM 软件包,可以解决分类问题(包括 C−SVC 、ν−SVC ), 回归问题(包括 ε − SVR 、v− SVR ) 以及分布估计(one − class − SVM ) 等问题,提供了线性、多项式、径向基和 S 形函数四种常用的核函数供选择,可以有效地解决多类问题、交叉验证选择参数、对不平衡样本加权、多类问题的概率估计等。LIBSVM 是一个开源的软件包,。他不仅提供了 LIBSVM 的 C++语言的算法源代码,还提供了 Python、Java、R、MATLAB、Perl、Ruby、LabVIEW以及 C#.net 等各种语言的接口,可以方便的在 Windows 或 UNIX 平台下使用,也便于科研工作者根据自己的需要进行改进(譬如设计使用符合自己特定问题需要的核函数等)。

文本分类,大致分为如下几件事情:样本分词特征提取向量计算分类训练测试和调试

1.样本选择

搜狗语料 http://www.sogou.com/labs/dl/c.html ,下精简版吧,如果实验用用,这足够了,你要下107M的也可以。当然,你也可以自己找语料,不过麻烦点而已,把各大门户网站的对应频道下的文章都爬下来。

2.分词

Bamboo分词,这是基于CRF++的分词模块,既然是研究统计学习,分词也得用基于统计的不是,如果还是用一字典来分词,那就太out啦。

http://code.google.com/p/nlpbamboo/wiki/GettingStarted 。安装完毕bamboo,还要下载训练好的模型(这个模型是基于人民日报1月语料)

http://code.google.com/p/nlpbamboo/downloads/list ,下载index.tar.bz2, 解压到/opt/bamboo/index下。

因为咱主要目的是研究分类,不是分词,就不要去搞分词的训练了,如果想训练可以看我的另外一篇博客:CRF++中文分词指南

可以试试:/opt/bamboo/bin/bamboo -p crf_seg filename,如果成功证明装好了。

稍微注意以下,搜狗的词库是gb2312的,所以,请转为utf8,再分词,这是python写的函数:输入一个文件名,转为utf8,再分词,分词文件以.seg为后缀。

[python] view plain copy

  1. def seg(fn):
  2. if not os.path.isfile(fn+'.utf8'):
  3. cmd = 'iconv -f gb2312 -t utf8 -c %s > %s.utf8' %(fn,fn)
  4. print cmd
  5. os.system(cmd)
  6. cmd = '/opt/bamboo/bin/bamboo -p crf_seg %s.utf8 > %s.seg' % (fn,fn)
  7. print cmd
  8. os.system(cmd)

分词结果如下:

一 家 刚刚 成立 两 年 的 网络 支付 公司 , 它 的 目标 是 成为 市值 100亿 美元 的 上市 公司 。 这家 公司 叫做 快 钱 , 说 这 句 话 的 是 快钱 的 CEO 关 国光 。 他 之前 曾 任 网易 的 高级 副 总裁 , 负责 过 网易 的 上市 工作 。 对于 为什么 选择 第三 方 支付 作为 创业 方向 , 他 曾经 对 媒体 这样 说 : “ 我 能 看到 这个 胡同 对面 是 什么 , 别人 只能 看到 这个 胡同 。 ” 自信 与 狂妄 只 有 一 步 之 遥 ―― 这 几乎 是 所有 创业者 的 共同 特征 , 是 自信 还是 狂妄 也许 需要 留待 时间 来 考证 。

3.特征提取

svm不是在高维模式识别具有优势吗,咋还要特征提取呢,把所有词都当成特征不就行了吗?对于词库来说,十几万的词是很常见的,把对类别区分度(GDP,CPI,股票对经济类的区分度就高,其他一些高频词,如我们,大家,一起等就没有区分度)高的词挑选出来,一来可以减少计算量,二来应该是可以提高分类效果。

据说,开方检验(CHI)信息增益(IG)对于挑选特征好,我选择的是CHI。两者的概念,请google。

首先统计词在文档中的次数

[python] view plain copy

  1. #ingore some term
  2. def ingore(s):
  3. return s == 'nbsp' or s == ' ' or s == ' ' or s == '/t' or s == '/n' /
  4. or s == ',' or s == '。' or s == '!' or s == '、' or s == '―'/
  5. or s == '?' or s == '@' or s == ':' /
  6. or s == '#' or s == '%' or s == '&' /
  7. or s == '(' or s == ')' or s == '《' or s == '》' /
  8. or s == '[' or s == ']' or s == '{' or s == '}' /
  9. or s == '*' or s == ',' or s == '.' or s == '&' /
  10. or s == '!' or s == '?' or s == ':' or s == ';'/
  11. or s == '-' or s == '&'/
  12. or s == '<' or s == '>' or s == '(' or s == ')' /
  13. or s == '[' or s == ']' or s == '{' or s == '}'
  14. #term times
  15. def getterm(fn):
  16. fnobj = open(fn,'r')
  17. data = fnobj.read()
  18. fnobj.close()
  19. arr = data.split(' ')
  20. docterm = dict()
  21. for a in arr:
  22. a = a.strip(' /n/t')
  23. if not ingore(a) and len( a.decode('utf-8')) >=2:
  24. times = docterm.get(a)
  25. if times:
  26. docterm[a] = times + 1
  27. else:
  28. docterm[a] = 1
  29. return docte
  30. #cls_term:cls,term,artcount
  31. #term_cls:term,cls,artcount
  32. def stat(cls,fn,cls_term,term_cls):
  33. docterm = getterm(fn)
  34. termdi = cls_term.get(cls)
  35. if not termdi:
  36. termdi = dict()
  37. cls_term[cls] = termdi
  38. #term,times
  39. for t in docterm.iterkeys():
  40. artcount = termdi.get(t)
  41. if not artcount:
  42. artcount = 0
  43. termdi[k] = artcount + 1
  44. clsdi = term_cls.get(t)
  45. if not clsdi:
  46. clsdi = {}
  47. term_cls[k] = clsdi
  48. artcount = clsdi.get(cls)
  49. if not artcount:
  50. artcount = 0
  51. clsdi[cls] = artcount + 1

分别计算每个词的a/b/c/d

a:在这个分类下包含这个词的文档数量

b:不在该分类下包含这个词的文档数量

c:在这个分类下不包含这个词的文档数量

d:不在该分类下,且不包含这个词的文档数量

因为前面统计了每个类下,每个词,文章数和每个词,每个类,文章数。所以很容易得到a,b,c,d的值。

z1 = a*d - b*c x2 = (z1 * z1 * float(N)) /( (a+c)*(a+b)*(b+d)*(c+d) )

计算之后,排序,并取出前1000个词(这里指的每个类别的特征词)。

li = sorted(termchi.iteritems(), key=lambda d:d[1], reverse = True)

循环每个分类,并把每个类别的特征合并(合并成一个文件,作为特征词典),合并后存为feature文件,第一列是序号,第二列是对应的词,序号就是特征号。

1 逐项 2 深市 3 九寨沟 4 岛内 5 期望 6 第20分钟 7 合理 8 谢杏芳 9 赛迪 10 毛泽东

注:特征选择的目的就是选择在该类下,不在其他类下的特征,但是重复是避免不了的,合并的文件肯定是排重过的。先选择每个类下的1000个词,假如10个类,则共选择10 * 1000个词,然后去重,并生成特征的唯一id。

4.训练和测试样本组织

搜狐语料的1990篇中的1890作为训练集,100篇作为测试集,分别形成train和test文件,libsvm的训练集的格式为:

lable1 index1:featureValue1 index2:featureValue2 index3:featureValue3 ...

lable2 index1:featureValue1 index2:featureValue2 index3:featureValue3 ...

对应到文本分类上就是:类别ID 特征序号(第3步计算的特征序号):特征值(TFIDF值)......

如,我摘了一行,这是一篇文章的例子,8就是类别ID,189是特征“189 指导"的序号,0.171153是特征值:

8 189:0.171153 253:0.081381 298:0.630345 504:0.135512 562:79.423503 578:0.072219 698:0.078896 710:0.036074 740:0.215368 868:0.263524 1336:0.114355 1365:0.076494 1372:0.085780 1555:0.572497 1563:3.932806 1598:0.114717 1685:0.129870 1972:0.193693 2282:0.061828 2865:0.026699 2897:0.099020 3040:0.039621 3041:0.258

采用TFIDF的算法,数据处理和特征选择类似,计算每个类,每篇文档,每个词的次数,以包含这个词的文档数。每篇文章的每个特征项,用TF/DF的值作为特征值。(后记:用TF * IDF,然后用svm-scale缩放到0,1之间,效果比TF/DF要好,准确率能达到82%。,计算方式如下:

tf = float(times) / total idf = math.log( N / float(term_count[term]) ) term_times[term] = tf * idf

[python] view plain copy

  1. #doc_term: class doc term times
  2. #term_doc: term doccount
  3. def tfidf(doc_term,term_doc):
  4. print 'begin compute tf * idf'
  5. for cls,docdi in doc_term.iteritems():
  6. for doc,termdi in docdi.iteritems():
  7. total = 0
  8. for term,times in termdi.iteritems():
  9. total += times
  10. for term,times in termdi.iteritems():
  11. tf = float(times) / total
  12. df = float(term_doc[term]) / N
  13. termdi[term] = tf / df

注意:用CHI是提取类别的特征词,而这里用TFIDF是计算文档的特征向量,前者是要体现类别的区分度,后者要体现文档的区分度,两者概念和所做的事情不一样,所以采用的方法也不一样。

5.用libsvm训练

你看,忙活了半天,还没有到libsvm呢,其实前面几步很麻烦的,libsvm的资料不少,但是都是一个几行数据的简单例子,这不具有实际应用的价值,只有把样本,分词,特征提取/特征计算搞定了,分类才能做好。

下载libsvm:http://www.csie.ntu.edu.tw/~cjlin/cgi-bin/libsvm.cgi?+http://www.csie.ntu.edu.tw/~cjlin/libsvm+zip

解压,make

svm-scale:特征缩放的工具 svm-train:训练工具 svm-predict:测试工具

toos/grid.py:寻找参数的工具

用默认参数试试:

./svm-train train.s model.s

./svm-predict test.s model.s result.s

结果

Accuracy = 74.3889% (1339/1800) (classification)

不算太理想,也不算太差。如果只是2个类,结果能到95%。我想可以从如下几个方面改进:

  • 增加分词的样本数,训练更好的分词模型。
  • 特征提取后,用人工进行调整,因为很多词对于类别区分度不高。
  • 用grid.py寻找合适的参数。

ibsvm的官方网站:http://www.csie.ntu.edu.tw/~cjlin/libsvm/

看了理论性的东西,最好实践以下,libsvm就是很好的实践工具。

原文发布于微信公众号 - 大数据挖掘DT数据分析(datadw)

原文发表时间:2016-05-26

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大数据挖掘DT机器学习

通俗的将Xgboost的原理讲明白

初看Xgboost,翻了多篇博客发现关于xgboost原理的描述实在难以忍受,缺乏逻辑性,写一篇供讨论。 观其大略,而后深入细节,一开始扎进公式反正我是觉得效...

5586
来自专栏红色石头的机器学习之路

台湾大学林轩田机器学习技法课程学习笔记6 -- Support Vector Regression

上节课我们主要介绍了Kernel Logistic Regression,讨论如何把SVM的技巧应用在soft-binary classification上。方...

2090
来自专栏iOSDevLog

人工智能-数学基础总结

2774
来自专栏用户3246163的专栏

2.4 估值和模拟

Exponentially weighted moving average(指数加权移动平均)

953
来自专栏机器之心

教程 | 用人工蜂群算法求解k-分区聚类问题

我之前的文章介绍了如何利用名为人工蜂群算法(ABC)的集群智能(SI)算法来解决现实世界的优化问题:https://medium.com/cesar-updat...

790
来自专栏IT综合技术分享

大数据算法汇总

转载36大数据(36dsj.com):36大数据»大数据等最核心的关键技术:32个算法

1621
来自专栏PPV课数据科学社区

【学习】 R语言与机器学习学习笔记(1)K-近邻算法

前言 最近在学习数据挖掘,对数据挖掘中的算法比较感兴趣,打算整理分享一下学习情况,顺便利用R来实现一下数据挖掘算法。 数据挖掘里我打算整理的...

2836
来自专栏数说工作室

金融数据挖掘之朴素贝叶斯

你和我之前的人生, 就像是来自同一个分布族的共轭曲线, 即使有各自的参数空间, 也注定要相识相念。 你和我之后的人生, 是我们相扶相持下不离不弃的最大似然, 用...

33710
来自专栏计算机视觉战队

值得一看——机器学习中容易犯下的错

前言 在工程中,有多种方法来构建一个关键值存储,并且每个设计都对使用模式做了不同的假设。在统计建模,有各种算法来建立一个分类,每一个算法的对数据集有不同的假设。...

3335
来自专栏Coding迪斯尼

由深入浅,人工智能原理的大白话阐述

1255

扫码关注云+社区