中文分词,c++应用,想到jieba分词,结果还的自己封装。探索中

2024-04-13 02:12

本文主要是介绍中文分词,c++应用,想到jieba分词,结果还的自己封装。探索中,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、研究背景   

       随着互联网的快速发展,信息也呈了爆炸式的增长趋势。在海量的信息中,我们如何快速抽取出有效信息成为了必须要解决的问题。由于信息处理的重复性,而计算机又善于处理机械的、重复的、有规律可循的工作,因此自然就想到了利用计算机来帮助人们进行处理。在用计算机进行自然语言处理时,主要使用的还是基于统计的方法,并且实际的使用中取得了不错的效果。

       因为中文句子的特点——没有分隔符来分离句子中的词,所以在进行中文处理的时候,首先要做的就是如何对中文语句进行分词。这也是本次工程所要实现的功能。

       在这个工程中,实现的是一个分词系统。系统的主要的内容就是建立隐马尔科夫模型,用《人民日报语料库》进行训练得到模型参数,然后再用维特比算法求出最可能的隐含序列,最后将输入的句子分成一个个词的形式。

      

二、模型方法

       本工程主要使用的是隐马尔科夫模型和维特比算法。

       隐马尔科夫模型是一个统计模型,它可以用一个5元组来表示:{S,O,π,A,B}。下面对隐马尔科夫模型的五元组的学术含义和工程含义进行说明,通过对比直观的了解五元组在实际工程中的含义:

HMM五元素

学术含义

工程含义

S

隐含转态

词中4种状态:词头、词中、词尾、单字成词

O

观察状态

语料库中的全部汉字

π

初始状态概率矩阵

各种隐含状态的初始概率

A

隐含状态转移概率矩阵

4种隐含状态的转移概率

B

观察状态转移概率矩阵

每一个汉字到四种状态的概率

       在本工程中,为每个汉字设置了可能的四种状态:词头([/B]Begin)、词中([/M]Middle)、词尾([/E]End)和单字成词([/S]Single)。

       根据设置的状态,举个例子说明五个参数:

       假设输入的语句为:我是中国人

              S={/B、/M、/E、/S}

              O={迈、向、新、充、满、……}(语料库中的所有不重复汉字)

              π={P(我|B)、P(我|M)、P(我|E)、P(我|S)}

              A=

/B

/M

/E

/S

/B

0

0.3

0.7

0

/M

/E

/S

              B=

/B

0.3

/M

/E

0.6

/S

       上述涉及到的概率均可从语料库中根据统计得到。

三、系统设计

       本分词系统主要分为两个部分,一个部分是通过语料库训练出需要的文件。该部分只要执行一次即可。另一个部分是根据输入的语句,构建具体的模型参数(通过上面也可以看到,根据具体输入得到对应的概率),然后执行维特比算法求出最佳的隐含状态序列。根据隐含状态序列得到最终的分词结果。

       系统的开发语言是C++。C++在处理中文方面显得有点不方便——表示英文字符时用的是一个字节,表示中文时用的是两个字节(可以通过判断字符是否小于0来分出是ASCII字符还是中文字符)。但是最后还是通过一些技巧解决了C++处理中文的不便带来的问题。

       1、语料库处理

              (1)去掉原语料库中的词性

                     A、原始语料库如图所示:

                     B、处理后的语料库(在每行前面加了一个空格并去掉了词性)

                     C、处理流程图

              (2)统计每个状态中出现的字及其个数

                     A、设计的数据结构如下:

 struct node{string name;//保存单个字int quantity;//字出现的次数bool operator ==(const node & a){return name==a.name;}};struct Word{string name;//状态名long long num;//状态出现次数list<node> chinese;bool operator ==(const Word & a){return name==a.name;}bool findCh(string ch){node temp;temp.name=ch;temp.quantity=1;list<node >::iterator it;it=find(chinese.begin(),chinese.end(),temp);if(it==chinese.end()){chinese.push_back(temp);}else{it->quantity++;}return true;}};

                     B、处理步骤

                            a、从语料库读入一行字符串,再遍历字符串获得一个中文字

                            b、判断字的前后是否是空格,得到字对应的状态(S:前面是空格后面不是;M:前后都不是空格;E:前面不是空格后面是空格;S:前后都是空格)

                            c、根据字的状态,判断该字是否在该状态下出现过。是,对应字个数加1,否,插入新节点并且个数设置为1)

                            d、读到文件末尾结束

                     C、结束后得到如下的文件

              (3)统计状态间的转换,求得状态转移矩阵

                     A、统计出各个状态间转换在语料库中出现的次数及状态转换的总次数,计算出对应的概率

                     B、该步骤的输入语料库如下:

                           

                     C该过程结束后可以得到4*4的状态转移矩阵

       2、viterbi算法解码,求最佳隐含序列

              (1)维特比算法是一种动态规划算法。在本工程中,通过当前状态的前一个状态,计算出在前面状态出现的条件下出现当前状态的概率,并取最大值作为当前状态出现的概率。通过迭代可以计算出到最后一个字时,哪个状态出现的概率最大。最后通过回溯得到最佳的隐含状态序列。

              (2)算法伪代码如下:

四,系统演示与分析

       1、测试样例及结果

       2、结果分析

              (1)商品和服务->BESBE->商品/和/服务/

              (2)中国在比赛中取得了胜利->BESBESBESBE->中国/在/比赛/中/取得/了/胜利/

              (3)分词说明:根据维特比算法求得了隐含序列后,顺序输出,当该字是处于E状态或者S状态时,在该字后添加‘/’,输出后即可看到分词的效果。

              (4)由于每个字都有一个状态,所以在分词过程中,有可能会把原来是词的分开了,原来不是词的合成了词,造成错误的分词。比如上面的“明天”被拆开了,而“天会”被则被合成起来了。再比如,“和尚”和“尚未”都被分开了,即使词库中有这两个字。

       3、改进方案

              本工程仅仅依靠HMM实现,因此必然存在一定的缺陷。为了改进该系统,可以结合其他的分词方法,在HMM实现过程中或实现结束后再做进一步分析,以得到更好的分词效果。

五,参考资料

       1、http://www.tuicool.com/articles/FRZ77b 利用统计进行中文分词与词性分析

       2、基于N最短路径和隐马尔科夫模型的中文POI分词系统的研究 唐霄

       3、基于逆向隐马尔可夫模型的中文分词方法研究

       4、http://blog.csdn.net/sight_/article/details/43307581  隐马尔科夫模型详解

这篇关于中文分词,c++应用,想到jieba分词,结果还的自己封装。探索中的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/898869

相关文章

C++ 函数 strftime 和时间格式示例详解

《C++函数strftime和时间格式示例详解》strftime是C/C++标准库中用于格式化日期和时间的函数,定义在ctime头文件中,它将tm结构体中的时间信息转换为指定格式的字符串,是处理... 目录C++ 函数 strftipythonme 详解一、函数原型二、功能描述三、格式字符串说明四、返回值五

C++作用域和标识符查找规则详解

《C++作用域和标识符查找规则详解》在C++中,作用域(Scope)和标识符查找(IdentifierLookup)是理解代码行为的重要概念,本文将详细介绍这些规则,并通过实例来说明它们的工作原理,需... 目录作用域标识符查找规则1. 普通查找(Ordinary Lookup)2. 限定查找(Qualif

RedisTemplate默认序列化方式显示中文乱码的解决

《RedisTemplate默认序列化方式显示中文乱码的解决》本文主要介绍了SpringDataRedis默认使用JdkSerializationRedisSerializer导致数据乱码,文中通过示... 目录1. 问题原因2. 解决方案3. 配置类示例4. 配置说明5. 使用示例6. 验证存储结果7.

Python使用Tkinter打造一个完整的桌面应用

《Python使用Tkinter打造一个完整的桌面应用》在Python生态中,Tkinter就像一把瑞士军刀,它没有花哨的特效,却能快速搭建出实用的图形界面,作为Python自带的标准库,无需安装即可... 目录一、界面搭建:像搭积木一样组合控件二、菜单系统:给应用装上“控制中枢”三、事件驱动:让界面“活”

C/C++ chrono简单使用场景示例详解

《C/C++chrono简单使用场景示例详解》:本文主要介绍C/C++chrono简单使用场景示例详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友... 目录chrono使用场景举例1 输出格式化字符串chrono使用场景China编程举例1 输出格式化字符串示

C++/类与对象/默认成员函数@构造函数的用法

《C++/类与对象/默认成员函数@构造函数的用法》:本文主要介绍C++/类与对象/默认成员函数@构造函数的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录名词概念默认成员函数构造函数概念函数特征显示构造函数隐式构造函数总结名词概念默认构造函数:不用传参就可以

C++类和对象之默认成员函数的使用解读

《C++类和对象之默认成员函数的使用解读》:本文主要介绍C++类和对象之默认成员函数的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、默认成员函数有哪些二、各默认成员函数详解默认构造函数析构函数拷贝构造函数拷贝赋值运算符三、默认成员函数的注意事项总结一

如何确定哪些软件是Mac系统自带的? Mac系统内置应用查看技巧

《如何确定哪些软件是Mac系统自带的?Mac系统内置应用查看技巧》如何确定哪些软件是Mac系统自带的?mac系统中有很多自带的应用,想要看看哪些是系统自带,该怎么查看呢?下面我们就来看看Mac系统内... 在MAC电脑上,可以使用以下方法来确定哪些软件是系统自带的:1.应用程序文件夹打开应用程序文件夹

C/C++中OpenCV 矩阵运算的实现

《C/C++中OpenCV矩阵运算的实现》本文主要介绍了C/C++中OpenCV矩阵运算的实现,包括基本算术运算(标量与矩阵)、矩阵乘法、转置、逆矩阵、行列式、迹、范数等操作,感兴趣的可以了解一下... 目录矩阵的创建与初始化创建矩阵访问矩阵元素基本的算术运算 ➕➖✖️➗矩阵与标量运算矩阵与矩阵运算 (逐元

C/C++的OpenCV 进行图像梯度提取的几种实现

《C/C++的OpenCV进行图像梯度提取的几种实现》本文主要介绍了C/C++的OpenCV进行图像梯度提取的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录预www.chinasem.cn备知识1. 图像加载与预处理2. Sobel 算子计算 X 和 Y