最近迷上了spark,写一个专门处理语料库生成词库的项目拿来练练手, github地址:https://github.com/LiuRoy/spark_splitter。代码实现参考wordmaker项目,有兴趣的可以看一下,此项目用到了不少很tricky的技巧提升性能,单纯只想看懂源代码可以参考wordmaker作者的一份简单版代码。

这个项目统计语料库的结果和执行速度都还不错,但缺点也很明显,只能处理GBK编码的文档,而且不能分布式运行,刚好最近在接触spark,所以用python实现了里面的算法,使之能处理更大规模的语料库,并且同时支持GBK和UTF8两种编码格式。

分词原理

wordmaker提供了一个统计大规模语料库词汇的算法,和结巴分词的原理不同,它不依赖已经统计好的词库或者隐马尔可夫模型,但是同样能得到不错的统计结果。原作者的文档提到是用多个线程独立计算各个文本块的词的信息,再按词的顺序分段合并,再计算各个段的字可能组成词的概率、左右熵,得到词语输出。下面就详细的讲解各个步骤:

  1. 读取文本,去掉文本中的换行、空格、标点,将语料库分解成一条一条只包含汉字的句子。
  2. 将上一步中的所有句子切分成各种长度的词,并统计所有词出现的次数。此处的切分只是把所有出现的可能都列出来,举个例子,天气真好 就可以切分为:天 天气 天气真 天气真好 气 气真 气真好 真 真好 好。不过为了省略一些没有必要的计算工作,此处设置了一个词汇长度限制。
  3. 针对上面切分出来的词汇,为了筛掉出那些多个词汇连接在一起的情况,会进一步计算这个词分词的结果,例如 月亮星星中的月亮和星星这两个词汇在步骤二得到的词汇中频率非常高,则认为月亮星星不是一个单独的词汇,需要被剔除掉。
  4. 为了进一步剔除错误切分的词汇,此处用到了信息熵的概念。举例:邯郸,邯字右边只有郸字一种组合,所以邯的右熵为0,这样切分就是错误的。因为汉字词语中汉字的关系比较紧密,如果把一个词切分开来,则他们的熵势必会小,只需要取一个合适的阈值过滤掉这种错误切分即可。

代码解释

原始的C++代码挺长,但是用python改写之后很少,上文中的1 2 3步用spark实现非常简单,代码在split函数中。第3部过滤后的结果已经相对较小,可以直接取出放入内存中,再计算熵过滤,在split中执行target_phrase_rdd.filter(lambda x: _filter(x))过滤的时候可以phrasedictmap做成spark中的广播变量,提升分布式计算的效率,因为只有一台机器,所以就没有这样做。split代码如下,原来很长的代码用python很容易就实现了。

 def split(self):
"""spark处理"""
raw_rdd = self.sc.textFile(self.corpus_path) utf_rdd = raw_rdd.map(lambda line: str_decode(line))
hanzi_rdd = utf_rdd.flatMap(lambda line: extract_hanzi(line)) raw_phrase_rdd = hanzi_rdd.flatMap(lambda sentence: cut_sentence(sentence)) phrase_rdd = raw_phrase_rdd.reduceByKey(lambda x, y: x + y)
phrase_dict_map = dict(phrase_rdd.collect())
total_count = 0
for _, freq in phrase_dict_map.iteritems():
total_count += freq def _filter(pair):
phrase, frequency = pair
max_ff = 0
for i in xrange(1, len(phrase)):
left = phrase[:i]
right = phrase[i:]
left_f = phrase_dict_map.get(left, 0)
right_f = phrase_dict_map.get(right, 0)
max_ff = max(left_f * right_f, max_ff)
return total_count * frequency / max_ff > 100.0 target_phrase_rdd = phrase_rdd.filter(lambda x: len(x[0]) >= 2 and x[1] >= 3)
result_phrase_rdd = target_phrase_rdd.filter(lambda x: _filter(x))
self.result_phrase_set = set(result_phrase_rdd.keys().collect())
self.phrase_dict_map = {key: PhraseInfo(val) for key, val in phrase_dict_map.iteritems()}

分词结果

进入spark_splitter/splitter目录,执行命令PYTHONPATH=. spark-submit spark.py处理test/moyan.txt文本,是莫言全集,统计完成的结果在out.txt中,统计部分的结果如下,由于算法的原因,带有 的 地 这种连词词语不能正确的切分。

(我也不知道为什么这个词这么多)

问题统计

  1. 上述的算法不能去掉连词,结果中会出现很多类似于轻轻地 等待着这种词
  2. 单机上用spark处理小规模数据没有任何优势,比wordmaker中的C++代码慢很多
  3. 可以和结巴基于隐马尔科夫模型的分词结果做一下准确率的比较

spark处理大规模语料库统计词汇的更多相关文章

  1. Spark入门(三)--Spark经典的单词统计

    spark经典之单词统计 准备数据 既然要统计单词我们就需要一个包含一定数量的文本,我们这里选择了英文原著<GoneWithTheWind>(<飘>)的文本来做一个数据统计,看 ...

  2. spark streaming - kafka updateStateByKey 统计用户消费金额

    场景 餐厅老板想要统计每个用户来他的店里总共消费了多少金额,我们可以使用updateStateByKey来实现 从kafka接收用户消费json数据,统计每分钟用户的消费情况,并且统计所有时间所有用户 ...

  3. spark MLLib的基础统计部分学习

    参考学习链接:http://www.itnose.net/detail/6269425.html 机器学习相关算法,建议初学者去看看斯坦福的机器学习课程视频:http://open.163.com/s ...

  4. Spark 大数据文本统计

    此程序功能: 1.完成对10.4G.csv文件各个元素频率的统计 2.获得最大的统计个数 3.对获取到的统计个数进行降序排列 4.对各个元素出现次数频率的统计 import org.apache.sp ...

  5. python spark 通过key来统计不同values个数

    >>> rdd = sc.parallelize([("), ("b", 1), ("a", 1), ("a", ...

  6. Spark Streaming:大规模流式数据处理的新贵(转)

    原文链接:Spark Streaming:大规模流式数据处理的新贵 摘要:Spark Streaming是大规模流式数据处理的新贵,将流式计算分解成一系列短小的批处理作业.本文阐释了Spark Str ...

  7. Spark Streaming:大规模流式数据处理的新贵

    转自:http://www.csdn.net/article/2014-01-28/2818282-Spark-Streaming-big-data 提到Spark Streaming,我们不得不说一 ...

  8. Spark MLlib LDA 基于GraphX实现原理及源代码分析

    LDA背景 LDA(隐含狄利克雷分布)是一个主题聚类模型,是当前主题聚类领域最火.最有力的模型之中的一个,它能通过多轮迭代把特征向量集合按主题分类.眼下,广泛运用在文本主题聚类中. LDA的开源实现有 ...

  9. 学习笔记TF018:词向量、维基百科语料库训练词向量模型

    词向量嵌入需要高效率处理大规模文本语料库.word2vec.简单方式,词送入独热编码(one-hot encoding)学习系统,长度为词汇表长度的向量,词语对应位置元素为1,其余元素为0.向量维数很 ...

随机推荐

  1. ASP.NET MVC5+EF6+EasyUI 后台管理系统(75)-微信公众平台开发-用户管理

    系列目录 前言 本节主要是关注者(即用户)和用户组的管理,微信公众号提供了用户和用户组的管理,我们可以在微信公众号官方里面进行操作,添加备注和标签,以及移动用户组别,同时,微信公众号也提供了相应的接口 ...

  2. PhotoView实现图片随手势的放大缩小的效果

    项目需求:在listView的条目中如果有图片,点击条目,实现图片的放大,并且图片可以根据手势来控制图片放大缩小的比例.类似于微信朋友圈中查看好友发布的照片所实现的效果. 思路是这样的:当点击条目的时 ...

  3. OpenCV人脸识别Eigen算法源码分析

    1 理论基础 学习Eigen人脸识别算法需要了解一下它用到的几个理论基础,现总结如下: 1.1 协方差矩阵 首先需要了解一下公式: 共公式可以看出:均值描述的是样本集合的平均值,而标准差描述的则是样本 ...

  4. 【算法】C语言实现数组的动态分配

    C语言实现数组的动态分配 作者:白宁超 2016年10月27日20:13:13 摘要:数据结构和算法对于编程的意义不言而喻,具有指导意义的.无论从事算法优化方向研究,还是大数据处理,亦或者网站开发AP ...

  5. 简记某WebGIS项目的优化之路

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1. 背景 该项目为研究生时的老师牵头,个人已毕业数年,应老师要求协助其 ...

  6. 【知识必备】RxJava+Retrofit二次封装最佳结合体验,打造懒人封装框架~

    一.写在前面 相信各位看官对retrofit和rxjava已经耳熟能详了,最近一直在学习retrofit+rxjava的各种封装姿势,也结合自己的理解,一步一步的做起来. 骚年,如果你还没有掌握ret ...

  7. 【WPF】日常笔记

    本文专用于记录WPF开发中的小细节,作为备忘录使用. 1. 关于绑定: Text ="{Binding AnchorageValue,Mode=TwoWay,UpdateSourceTrig ...

  8. 利用poi导出Excel

    import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.r ...

  9. 玩转ajax

    1.什么是ajax? Ajax 是 Asynchronous JavaScript and XML(以及 DHTML 等)的缩写. 2.ajax需要什么基础? HTML 用于建立 Web 表单并确定应 ...

  10. 把int*传值给char*,打印出错误的数字

    首先进入debug模式查看i的地址也就是ptr的值 以16进制位小端模式存储(一个整型四个字节,8位16进制数)(根据系统位数情况) 紧接着因为ptr是char*型指针变量,读取数据时按照一个字节一个 ...