From 7e7fcc118409e483fc9c08a010962b90af2c1c86 Mon Sep 17 00:00:00 2001 From: Sun Junyi Date: Thu, 5 Sep 2013 17:09:27 +0800 Subject: [PATCH] add an option to disable HMM --- jieba/__init__.py | 49 +++++++++++++--- jieba/posseg/__init__.py | 45 +++++++++++++-- test/jieba_test.py | 38 +++++++++++++ test/test_no_hmm.py | 100 +++++++++++++++++++++++++++++++++ test/test_pos_no_hmm.py | 98 ++++++++++++++++++++++++++++++++ test/test_tokenize_no_hmm.py | 106 +++++++++++++++++++++++++++++++++++ 6 files changed, 422 insertions(+), 14 deletions(-) create mode 100644 test/test_no_hmm.py create mode 100644 test/test_pos_no_hmm.py create mode 100644 test/test_tokenize_no_hmm.py diff --git a/jieba/__init__.py b/jieba/__init__.py index 3494538..efceece 100644 --- a/jieba/__init__.py +++ b/jieba/__init__.py @@ -167,6 +167,29 @@ def get_DAG(sentence): DAG[i] =[i] return DAG +def __cut_DAG_NO_HMM(sentence): + re_eng = re.compile(ur'[a-zA-Z0-9]',re.U) + DAG = get_DAG(sentence) + route ={} + calc(sentence,DAG,0,route=route) + x = 0 + N = len(sentence) + buf = u'' + while x0: + yield buf + buf = u'' + yield l_word + x =y + if len(buf)>0: + yield buf + buf = u'' def __cut_DAG(sentence): DAG = get_DAG(sentence) @@ -209,7 +232,7 @@ def __cut_DAG(sentence): for elem in buf: yield elem -def cut(sentence,cut_all=False): +def cut(sentence,cut_all=False,HMM=True): if not isinstance(sentence, unicode): try: sentence = sentence.decode('utf-8') @@ -219,7 +242,10 @@ def cut(sentence,cut_all=False): if cut_all: re_han, re_skip = re.compile(ur"([\u4E00-\u9FA5]+)", re.U), re.compile(ur"[^a-zA-Z0-9+#\n]", re.U) blocks = re_han.split(sentence) - cut_block = __cut_DAG + if HMM: + cut_block = __cut_DAG + else: + cut_block = __cut_DAG_NO_HMM if cut_all: cut_block = __cut_all for blk in blocks: @@ -239,8 +265,8 @@ def cut(sentence,cut_all=False): else: yield x -def cut_for_search(sentence): - words = cut(sentence) +def cut_for_search(sentence,HMM=True): + words = cut(sentence,HMM=HMM) for w in words: if len(w)>2: for i in xrange(len(w)-1): @@ -291,6 +317,8 @@ __ref_cut_for_search = cut_for_search def __lcut(sentence): return list(__ref_cut(sentence,False)) +def __lcut_no_hmm(sentence): + return list(__ref_cut(sentence,False,False)) def __lcut_all(sentence): return list(__ref_cut(sentence,True)) def __lcut_for_search(sentence): @@ -309,12 +337,15 @@ def enable_parallel(processnum=None): processnum = cpu_count() pool = Pool(processnum) - def pcut(sentence,cut_all=False): + def pcut(sentence,cut_all=False,HMM=True): parts = re.compile('([\r\n]+)').split(sentence) if cut_all: result = pool.map(__lcut_all,parts) else: - result = pool.map(__lcut,parts) + if HMM: + result = pool.map(__lcut,parts) + else: + result = pool.map(__lcut_no_hmm,parts) for r in result: for w in r: yield w @@ -351,18 +382,18 @@ def get_abs_path_dict(): abs_path = os.path.join(_curpath,DICTIONARY) return abs_path -def tokenize(unicode_sentence,mode="default"): +def tokenize(unicode_sentence,mode="default",HMM=True): #mode ("default" or "search") if not isinstance(unicode_sentence, unicode): raise Exception("jieba: the input parameter should unicode.") start = 0 if mode=='default': - for w in cut(unicode_sentence): + for w in cut(unicode_sentence,HMM=HMM): width = len(w) yield (w,start,start+width) start+=width else: - for w in cut(unicode_sentence): + for w in cut(unicode_sentence,HMM=HMM): width = len(w) if len(w)>2: for i in xrange(len(w)-1): diff --git a/jieba/posseg/__init__.py b/jieba/posseg/__init__.py index b5d3775..2a789fe 100644 --- a/jieba/posseg/__init__.py +++ b/jieba/posseg/__init__.py @@ -129,6 +129,30 @@ def __cut_detail(sentence): else: yield pair(x,'x') +def __cut_DAG_NO_HMM(sentence): + DAG = jieba.get_DAG(sentence) + route ={} + jieba.calc(sentence,DAG,0,route=route) + x = 0 + N = len(sentence) + buf =u'' + re_eng = re.compile(ur'[a-zA-Z0-9]',re.U) + while x0: + yield pair(buf,'eng') + buf = u'' + yield pair(l_word,word_tag_tab.get(l_word,'x')) + x =y + if len(buf)>0: + yield pair(buf,'eng') + buf = u'' + def __cut_DAG(sentence): DAG = jieba.get_DAG(sentence) route ={} @@ -172,7 +196,7 @@ def __cut_DAG(sentence): for elem in buf: yield pair(elem,word_tag_tab.get(elem,'x')) -def __cut_internal(sentence): +def __cut_internal(sentence,HMM=True): if not ( type(sentence) is unicode): try: sentence = sentence.decode('utf-8') @@ -181,9 +205,14 @@ def __cut_internal(sentence): re_han, re_skip = re.compile(ur"([\u4E00-\u9FA5a-zA-Z0-9+#&\._]+)"), re.compile(ur"(\r\n|\s)") re_eng,re_num = re.compile(ur"[a-zA-Z0-9]+"), re.compile(ur"[\.0-9]+") blocks = re_han.split(sentence) + if HMM: + __cut_blk = __cut_DAG + else: + __cut_blk = __cut_DAG_NO_HMM + for blk in blocks: if re_han.match(blk): - for word in __cut_DAG(blk): + for word in __cut_blk(blk): yield word else: tmp = re_skip.split(blk) @@ -201,15 +230,21 @@ def __cut_internal(sentence): def __lcut_internal(sentence): return list(__cut_internal(sentence)) +def __lcut_internal_no_hmm(sentence): + return list(__cut_internal(sentence,False)) + @makesure_userdict_loaded -def cut(sentence): +def cut(sentence,HMM=True): if (not hasattr(jieba,'pool')) or (jieba.pool==None): - for w in __cut_internal(sentence): + for w in __cut_internal(sentence,HMM=HMM): yield w else: parts = re.compile('([\r\n]+)').split(sentence) - result = jieba.pool.map(__lcut_internal,parts) + if HMM: + result = jieba.pool.map(__lcut_internal,parts) + else: + result = jieba.pool.map(__lcut_internal_no_hmm,parts) for r in result: for w in r: yield w diff --git a/test/jieba_test.py b/test/jieba_test.py index 4e6d35d..b05bd8d 100644 --- a/test/jieba_test.py +++ b/test/jieba_test.py @@ -159,5 +159,43 @@ class JiebaTestCase(unittest.TestCase): print >>sys.stderr, "word %s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2]) print >> sys.stderr, "testTokenize" + def testDefaultCut_NOHMM(self): + for content in test_contents: + result = jieba.cut(content,HMM=False) + assert isinstance(result, types.GeneratorType), "Test DefaultCut Generator error" + result = list(result) + assert isinstance(result, list), "Test DefaultCut error on content: %s" % content + print >> sys.stderr, " , ".join(result) + print >> sys.stderr, "testDefaultCut_NOHMM" + + def testPosseg_NOHMM(self): + import jieba.posseg as pseg + for content in test_contents: + result = pseg.cut(content,HMM=False) + assert isinstance(result, types.GeneratorType), "Test Posseg Generator error" + result = list(result) + assert isinstance(result, list), "Test Posseg error on content: %s" % content + print >> sys.stderr, " , ".join([w.word + " / " + w.flag for w in result]) + print >> sys.stderr, "testPosseg_NOHMM" + + def testTokenize_NOHMM(self): + for content in test_contents: + result = jieba.tokenize(content.decode('utf-8'),HMM=False) + assert isinstance(result, types.GeneratorType), "Test Tokenize Generator error" + result = list(result) + assert isinstance(result, list), "Test Tokenize error on content: %s" % content + for tk in result: + print >>sys.stderr, "word %s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2]) + print >> sys.stderr, "testTokenize_NOHMM" + + def testCutForSearch_NOHMM(self): + for content in test_contents: + result = jieba.cut_for_search(content,HMM=False) + assert isinstance(result, types.GeneratorType), "Test CutForSearch Generator error" + result = list(result) + assert isinstance(result, list), "Test CutForSearch error on content: %s" % content + print >> sys.stderr, " , ".join(result) + print >> sys.stderr, "testCutForSearch_NOHMM" + if __name__ == "__main__": unittest.main() diff --git a/test/test_no_hmm.py b/test/test_no_hmm.py new file mode 100644 index 0000000..a16de96 --- /dev/null +++ b/test/test_no_hmm.py @@ -0,0 +1,100 @@ +#encoding=utf-8 +import sys +sys.path.append("../") +import jieba + + +def cuttest(test_sent): + result = jieba.cut(test_sent,HMM=False) + print " / ".join(result) + + +if __name__ == "__main__": + cuttest("这是一个伸手不见五指的黑夜。我叫孙悟空,我爱北京,我爱Python和C++。") + cuttest("我不喜欢日本和服。") + cuttest("雷猴回归人间。") + cuttest("工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作") + cuttest("我需要廉租房") + cuttest("永和服装饰品有限公司") + cuttest("我爱北京天安门") + cuttest("abc") + cuttest("隐马尔可夫") + cuttest("雷猴是个好网站") + cuttest("“Microsoft”一词由“MICROcomputer(微型计算机)”和“SOFTware(软件)”两部分组成") + cuttest("草泥马和欺实马是今年的流行词汇") + cuttest("伊藤洋华堂总府店") + cuttest("中国科学院计算技术研究所") + cuttest("罗密欧与朱丽叶") + cuttest("我购买了道具和服装") + cuttest("PS: 我觉得开源有一个好处,就是能够敦促自己不断改进,避免敞帚自珍") + cuttest("湖北省石首市") + cuttest("湖北省十堰市") + cuttest("总经理完成了这件事情") + cuttest("电脑修好了") + cuttest("做好了这件事情就一了百了了") + cuttest("人们审美的观点是不同的") + cuttest("我们买了一个美的空调") + cuttest("线程初始化时我们要注意") + cuttest("一个分子是由好多原子组织成的") + cuttest("祝你马到功成") + cuttest("他掉进了无底洞里") + cuttest("中国的首都是北京") + cuttest("孙君意") + cuttest("外交部发言人马朝旭") + cuttest("领导人会议和第四届东亚峰会") + cuttest("在过去的这五年") + cuttest("还需要很长的路要走") + cuttest("60周年首都阅兵") + cuttest("你好人们审美的观点是不同的") + cuttest("买水果然后来世博园") + cuttest("买水果然后去世博园") + cuttest("但是后来我才知道你是对的") + cuttest("存在即合理") + cuttest("的的的的的在的的的的就以和和和") + cuttest("I love你,不以为耻,反以为rong") + cuttest("因") + cuttest("") + cuttest("hello你好人们审美的观点是不同的") + cuttest("很好但主要是基于网页形式") + cuttest("hello你好人们审美的观点是不同的") + cuttest("为什么我不能拥有想要的生活") + cuttest("后来我才") + cuttest("此次来中国是为了") + cuttest("使用了它就可以解决一些问题") + cuttest(",使用了它就可以解决一些问题") + cuttest("其实使用了它就可以解决一些问题") + cuttest("好人使用了它就可以解决一些问题") + cuttest("是因为和国家") + cuttest("老年搜索还支持") + cuttest("干脆就把那部蒙人的闲法给废了拉倒!RT @laoshipukong : 27日,全国人大常委会第三次审议侵权责任法草案,删除了有关医疗损害责任“举证倒置”的规定。在医患纠纷中本已处于弱势地位的消费者由此将陷入万劫不复的境地。 ") + cuttest("大") + cuttest("") + cuttest("他说的确实在理") + cuttest("长春市长春节讲话") + cuttest("结婚的和尚未结婚的") + cuttest("结合成分子时") + cuttest("旅游和服务是最好的") + cuttest("这件事情的确是我的错") + cuttest("供大家参考指正") + cuttest("哈尔滨政府公布塌桥原因") + cuttest("我在机场入口处") + cuttest("邢永臣摄影报道") + cuttest("BP神经网络如何训练才能在分类时增加区分度?") + cuttest("南京市长江大桥") + cuttest("应一些使用者的建议,也为了便于利用NiuTrans用于SMT研究") + cuttest('长春市长春药店') + cuttest('邓颖超生前最喜欢的衣服') + cuttest('胡锦涛是热爱世界和平的政治局常委') + cuttest('程序员祝海林和朱会震是在孙健的左面和右面, 范凯在最右面.再往左是李松洪') + cuttest('一次性交多少钱') + cuttest('两块五一套,三块八一斤,四块七一本,五块六一条') + cuttest('小和尚留了一个像大和尚一样的和尚头') + cuttest('我是中华人民共和国公民;我爸爸是共和党党员; 地铁和平门站') + cuttest('张晓梅去人民医院做了个B超然后去买了件T恤') + cuttest('AT&T是一件不错的公司,给你发offer了吗?') + cuttest('C++和c#是什么关系?11+122=133,是吗?PI=3.14159') + cuttest('你认识那个和主席握手的的哥吗?他开一辆黑色的士。') + cuttest('枪杆子中出政权') + cuttest('张三风同学走上了不归路') + cuttest('阿Q腰间挂着BB机手里拿着大哥大,说:我一般吃饭不AA制的。') + cuttest('在1号店能买到小S和大S八卦的书,还有3D电视。') diff --git a/test/test_pos_no_hmm.py b/test/test_pos_no_hmm.py new file mode 100644 index 0000000..c412a5d --- /dev/null +++ b/test/test_pos_no_hmm.py @@ -0,0 +1,98 @@ +#encoding=utf-8 +import sys +sys.path.append("../") +import jieba.posseg as pseg + +def cuttest(test_sent): + result = pseg.cut(test_sent,HMM=False) + for w in result: + print w.word, "/", w.flag, ", ", + print "" + + +if __name__ == "__main__": + cuttest("这是一个伸手不见五指的黑夜。我叫孙悟空,我爱北京,我爱Python和C++。") + cuttest("我不喜欢日本和服。") + cuttest("雷猴回归人间。") + cuttest("工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作") + cuttest("我需要廉租房") + cuttest("永和服装饰品有限公司") + cuttest("我爱北京天安门") + cuttest("abc") + cuttest("隐马尔可夫") + cuttest("雷猴是个好网站") + cuttest("“Microsoft”一词由“MICROcomputer(微型计算机)”和“SOFTware(软件)”两部分组成") + cuttest("草泥马和欺实马是今年的流行词汇") + cuttest("伊藤洋华堂总府店") + cuttest("中国科学院计算技术研究所") + cuttest("罗密欧与朱丽叶") + cuttest("我购买了道具和服装") + cuttest("PS: 我觉得开源有一个好处,就是能够敦促自己不断改进,避免敞帚自珍") + cuttest("湖北省石首市") + cuttest("湖北省十堰市") + cuttest("总经理完成了这件事情") + cuttest("电脑修好了") + cuttest("做好了这件事情就一了百了了") + cuttest("人们审美的观点是不同的") + cuttest("我们买了一个美的空调") + cuttest("线程初始化时我们要注意") + cuttest("一个分子是由好多原子组织成的") + cuttest("祝你马到功成") + cuttest("他掉进了无底洞里") + cuttest("中国的首都是北京") + cuttest("孙君意") + cuttest("外交部发言人马朝旭") + cuttest("领导人会议和第四届东亚峰会") + cuttest("在过去的这五年") + cuttest("还需要很长的路要走") + cuttest("60周年首都阅兵") + cuttest("你好人们审美的观点是不同的") + cuttest("买水果然后来世博园") + cuttest("买水果然后去世博园") + cuttest("但是后来我才知道你是对的") + cuttest("存在即合理") + cuttest("的的的的的在的的的的就以和和和") + cuttest("I love你,不以为耻,反以为rong") + cuttest("因") + cuttest("") + cuttest("hello你好人们审美的观点是不同的") + cuttest("很好但主要是基于网页形式") + cuttest("hello你好人们审美的观点是不同的") + cuttest("为什么我不能拥有想要的生活") + cuttest("后来我才") + cuttest("此次来中国是为了") + cuttest("使用了它就可以解决一些问题") + cuttest(",使用了它就可以解决一些问题") + cuttest("其实使用了它就可以解决一些问题") + cuttest("好人使用了它就可以解决一些问题") + cuttest("是因为和国家") + cuttest("老年搜索还支持") + cuttest("干脆就把那部蒙人的闲法给废了拉倒!RT @laoshipukong : 27日,全国人大常委会第三次审议侵权责任法草案,删除了有关医疗损害责任“举证倒置”的规定。在医患纠纷中本已处于弱势地位的消费者由此将陷入万劫不复的境地。 ") + cuttest("大") + cuttest("") + cuttest("他说的确实在理") + cuttest("长春市长春节讲话") + cuttest("结婚的和尚未结婚的") + cuttest("结合成分子时") + cuttest("旅游和服务是最好的") + cuttest("这件事情的确是我的错") + cuttest("供大家参考指正") + cuttest("哈尔滨政府公布塌桥原因") + cuttest("我在机场入口处") + cuttest("邢永臣摄影报道") + cuttest("BP神经网络如何训练才能在分类时增加区分度?") + cuttest("南京市长江大桥") + cuttest("应一些使用者的建议,也为了便于利用NiuTrans用于SMT研究") + cuttest('长春市长春药店') + cuttest('邓颖超生前最喜欢的衣服') + cuttest('胡锦涛是热爱世界和平的政治局常委') + cuttest('程序员祝海林和朱会震是在孙健的左面和右面, 范凯在最右面.再往左是李松洪') + cuttest('一次性交多少钱') + cuttest('两块五一套,三块八一斤,四块七一本,五块六一条') + cuttest('小和尚留了一个像大和尚一样的和尚头') + cuttest('我是中华人民共和国公民;我爸爸是共和党党员; 地铁和平门站') + cuttest('张晓梅去人民医院做了个B超然后去买了件T恤') + cuttest('AT&T是一件不错的公司,给你发offer了吗?') + cuttest('C++和c#是什么关系?11+122=133,是吗?PI=3.14159') + cuttest('你认识那个和主席握手的的哥吗?他开一辆黑色的士。') + cuttest('枪杆子中出政权') \ No newline at end of file diff --git a/test/test_tokenize_no_hmm.py b/test/test_tokenize_no_hmm.py new file mode 100644 index 0000000..48367e1 --- /dev/null +++ b/test/test_tokenize_no_hmm.py @@ -0,0 +1,106 @@ +#encoding=utf-8 +import sys +sys.path.append("../") +import jieba + +g_mode="default" + +def cuttest(test_sent): + global g_mode + test_sent = test_sent.decode('utf-8') + result = jieba.tokenize(test_sent,mode=g_mode,HMM=False) + for tk in result: + print "word %s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2]) + + +if __name__ == "__main__": + for m in ("default","search"): + g_mode = m + cuttest("这是一个伸手不见五指的黑夜。我叫孙悟空,我爱北京,我爱Python和C++。") + cuttest("我不喜欢日本和服。") + cuttest("雷猴回归人间。") + cuttest("工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作") + cuttest("我需要廉租房") + cuttest("永和服装饰品有限公司") + cuttest("我爱北京天安门") + cuttest("abc") + cuttest("隐马尔可夫") + cuttest("雷猴是个好网站") + cuttest("“Microsoft”一词由“MICROcomputer(微型计算机)”和“SOFTware(软件)”两部分组成") + cuttest("草泥马和欺实马是今年的流行词汇") + cuttest("伊藤洋华堂总府店") + cuttest("中国科学院计算技术研究所") + cuttest("罗密欧与朱丽叶") + cuttest("我购买了道具和服装") + cuttest("PS: 我觉得开源有一个好处,就是能够敦促自己不断改进,避免敞帚自珍") + cuttest("湖北省石首市") + cuttest("湖北省十堰市") + cuttest("总经理完成了这件事情") + cuttest("电脑修好了") + cuttest("做好了这件事情就一了百了了") + cuttest("人们审美的观点是不同的") + cuttest("我们买了一个美的空调") + cuttest("线程初始化时我们要注意") + cuttest("一个分子是由好多原子组织成的") + cuttest("祝你马到功成") + cuttest("他掉进了无底洞里") + cuttest("中国的首都是北京") + cuttest("孙君意") + cuttest("外交部发言人马朝旭") + cuttest("领导人会议和第四届东亚峰会") + cuttest("在过去的这五年") + cuttest("还需要很长的路要走") + cuttest("60周年首都阅兵") + cuttest("你好人们审美的观点是不同的") + cuttest("买水果然后来世博园") + cuttest("买水果然后去世博园") + cuttest("但是后来我才知道你是对的") + cuttest("存在即合理") + cuttest("的的的的的在的的的的就以和和和") + cuttest("I love你,不以为耻,反以为rong") + cuttest("因") + cuttest("") + cuttest("hello你好人们审美的观点是不同的") + cuttest("很好但主要是基于网页形式") + cuttest("hello你好人们审美的观点是不同的") + cuttest("为什么我不能拥有想要的生活") + cuttest("后来我才") + cuttest("此次来中国是为了") + cuttest("使用了它就可以解决一些问题") + cuttest(",使用了它就可以解决一些问题") + cuttest("其实使用了它就可以解决一些问题") + cuttest("好人使用了它就可以解决一些问题") + cuttest("是因为和国家") + cuttest("老年搜索还支持") + cuttest("干脆就把那部蒙人的闲法给废了拉倒!RT @laoshipukong : 27日,全国人大常委会第三次审议侵权责任法草案,删除了有关医疗损害责任“举证倒置”的规定。在医患纠纷中本已处于弱势地位的消费者由此将陷入万劫不复的境地。 ") + cuttest("大") + cuttest("") + cuttest("他说的确实在理") + cuttest("长春市长春节讲话") + cuttest("结婚的和尚未结婚的") + cuttest("结合成分子时") + cuttest("旅游和服务是最好的") + cuttest("这件事情的确是我的错") + cuttest("供大家参考指正") + cuttest("哈尔滨政府公布塌桥原因") + cuttest("我在机场入口处") + cuttest("邢永臣摄影报道") + cuttest("BP神经网络如何训练才能在分类时增加区分度?") + cuttest("南京市长江大桥") + cuttest("应一些使用者的建议,也为了便于利用NiuTrans用于SMT研究") + cuttest('长春市长春药店') + cuttest('邓颖超生前最喜欢的衣服') + cuttest('胡锦涛是热爱世界和平的政治局常委') + cuttest('程序员祝海林和朱会震是在孙健的左面和右面, 范凯在最右面.再往左是李松洪') + cuttest('一次性交多少钱') + cuttest('两块五一套,三块八一斤,四块七一本,五块六一条') + cuttest('小和尚留了一个像大和尚一样的和尚头') + cuttest('我是中华人民共和国公民;我爸爸是共和党党员; 地铁和平门站') + cuttest('张晓梅去人民医院做了个B超然后去买了件T恤') + cuttest('AT&T是一件不错的公司,给你发offer了吗?') + cuttest('C++和c#是什么关系?11+122=133,是吗?PI=3.14159') + cuttest('你认识那个和主席握手的的哥吗?他开一辆黑色的士。') + cuttest('枪杆子中出政权') + cuttest('张三风同学走上了不归路') + cuttest('阿Q腰间挂着BB机手里拿着大哥大,说:我一般吃饭不AA制的。') + cuttest('在1号店能买到小S和大S八卦的书。')