跟着大神重写的KNN 文档归类小工具
·背景
在知道KNN之前,楼主有时候会粗糙地做一些分类模型的计算。在拜读了Orisun大神[http://www.cnblogs.com/zhangchaoyang/articles/2162393.html]的一些文章从中得到了一些启发,这些天突发奇想决定把N年前的分类模型按照KNN的思路重写,重新把大神的思路形象地再回溯一下,方便后人更加清晰的认识整个过程。很多时候,历史的进步来源于前辈们的传道、授业、解惑。既然大神给JAVA,不材这边就继续补充一个C++的,为陷在JAVA中的斗士们吹一曲老革命之歌。
·设计思路
像大多数的ML体系一下,向量和概率学几乎是整个ML体系的基础,但从历史经验的推断又是ML的命门,人类与机器之间的战争从未体质。文档分类工具的设计初衷是希望拿到的这边文章能够准确的归为某一类,大神是通过KNN把复旦的语料分个类。楼主这边就简单地把公司投诉内容也简单归个类。KNN的最早设计模型如下图所示:
如上面左所示,X在K的定义范围内(规则半径或规则图形内)与其周围邻居属性归类最多的一项,则归为某类。具体到与邻居的相似是如何计算的,则是采用最基本的向量空间算法,Cos夹角。而SVM则是利用两个向量至理想边界的最大距离来分类,所以对于向量的理解至关重要。很多人KNN很简单,但是越是简单的,要用好反而更难。
在得知了最基本的计算思路后,做文档分类就能迎刃而解。把用自然分词分类,把每一个文档设置成一个向量,把每个词汇出现概率增益作为向量的维度,这样每一个向量就有了自己的标尺。有了标尺之后,就可以回到了上面有图的理论部分。剩下的工作就是遍历计算夹角,如下图所示,一目了然吧。
·编码中的可能碰到问题
- 文档分词工具,按目前汉字系来说其实都差不多,看个人喜好,楼主喜欢用SCWS开源加自定义词汇,唯独在编译时会碰到const char*的警告问题,这个与会不同的编译器有关。有洁癖者,请变量前加const。
- 计算文档向量原始矩阵:原著中推荐使用了berkleyDB+MR,但是实际操作过程中,并没有原著中那么复杂,经过实践,64位下c++ String和Map,真的隐秘而强大。
- 从流行的角度,在真正分类时,可以推荐使用Spark,几乎完爆hadoop了,后续楼主会补充pyspark的代码。可惜了分词的时候不能发挥外部API的特色。
- 由于出于个人兴趣,未追求程序计算量的性能极限,有一些声明和全局的处理比较粗糙。有该癖好的者,请多用指针。
- 下面是代码和工具截图,方便期间仅做了.a文件。其中涉及到部分公司的商业数据,楼主做了敏感处理,请仅做学术之后。如派为他用,请自行接受法律制裁。
- 仅适用linux/centos kernel2.6
·测试的结果
把投诉内容按网络质量、终端销售、服务质量进行分类。如之前所述楼主把cos值做了直接相加,相加最大值为最相似判定。在测试样本的随机结果中命中还是OK的。当然,话说回来,任何ML算是的弊端还是"历史经验和人的因素。