[微信机器人_04]自然语言处理简单实现
这篇博文中将介绍奇迹蛋自然语言处理模块的实现,自然语言处理的三个关键词:分词、建库、匹配。
建库:
先来看两个对话:
问:今天吃什么答:面条
问:今天吃面条答:太好了
机器人要如何来记忆这两组对话呢?
1、直接存储
问题 |
答案 |
今天吃什么 |
火锅 |
今天吃面条 |
不好吃 |
这样存储当然没有问题,但是显然太土了,有没有其它的办法呢?
2、树
在存储过程中,总是希望能够去除冗余,即相同的词语能够只存储一次。很容易想到,把句子拆分成词来存储。
如图所示,每个问题都拆分成词,并以词为节点建立树。每个几点可以与一个答案(或者多个答案)关联。这样的存储方式比 直接存储要精细很多,存储空间小、查找效率高。
实际建立的树结构如下:
树存储特点介绍
Ø 根节点不存储任何信息;
Ø 内部节点和叶子节点都可以与答案关联;
Ø 这棵树类似于B树的结构,即一个节点可以有N个子节点;
Ø 树的高度与一个句子中包含的词语个数有关。
分词
注意到以树来记忆对话,需要把问题进行拆分,即 分词。
分词是自然语言处理里非常关键的一部分,用于把句子拆分成词,进行存储、匹配。分词的实现包含两个部分:
Ø 分词算法
即按照什么样的规则来切割句子,比如从头开始切还是从结尾开始切,有多种切割选择时如何决策等等。
Ø 知识库
知识库即一些常用的词语,分词算法依赖知识库来识别 元词(即由多个汉字组成的有意义的词)。知识库是否丰富,对算法的精确度有很大的影响。
分词算法我是不太懂,这里也不做过多的描述,有兴趣可以去研究下比较有名的开源分词软件如: IK分词器等。
不懂分词算法没关系,我的目的只是得到分词的结果,“拿来主义”是程序员的优良传统,可以使用开放的API来帮咱完成分词的工作,在前面的博文提到过,我这里使用的是sina的api: http://5.tbip.sinaapp.com/api.php?str=[sentence]&type=[json]
比如在浏览器中输入
http://5.tbip.sinaapp.com/api.php?str=今天吃什么&type=json
返回json格式的结果:
[
{
"word":"\u4eca\u5929",
"word_tag":"132",
"index":"0"
},
{
"word":"\u5403",
"word_tag":"170",
"index":"1"
},
{
"word":"\u4ec0\u4e48",
"word_tag":"123",
"index":"2"
}
]
匹配
匹配算法也很简单,关键是几个模糊匹配的规则。
假设数据库中记录了这样一个问题: ABCD,其中,A、B、C、D分别代表一个词语。
而可能遇到的问题有如下几种:
1. ABC
由于数据库中没有ABC对应的答案,而前几个词完全匹配,那么继续搜寻C的子节点,知道找到有答案的节点,将该答案作为ABC的答案返回。比如,记录的对话为:
问题: 你 在 干嘛 呢
答案:发呆
此时如果用户提问: 你 在 干嘛,会匹配到 “你在干嘛呢”这个问题,并获得答案“发呆”。
2. ABCD
完全匹配,不多说。
3. ABCDE
虽然前四个词完全匹配,但是多了一个E,则认为是一个新问题,不能匹配,没有答案。
4. XABC
5. XABCD
6. XABCDE
4、5、6这三种情况可分别转换为1、2、3三种情况。当发现问题的首字不匹配时,则去掉首字,重新匹配。比如,记录的对话为:
问题: 今天 还有 火车票 吗
答案:卖完了
此时如果用户提问: 请问 今天 还有 火车票 吗,首词 “请问”无法匹配,则去掉首词,得到新的问题 今天 还有 火车票 吗,与原问题匹配,得到答案“卖完了”。
7. CD
也遵循上面的处理原则,去掉不匹配的首词,但C、D作为首词均不能匹配到ABCD,故该问题没有答案。
以上即使奇迹蛋的自然语言模块的设计,很简单吧^_^
关于代码及数据库实现会在后面以整个工程上传,其实并不复杂,相信各位有更精妙的实现方法。
这里的自然语言处理只是一个简化的实现,后面如果有时间,会去研究相关的资料,这里也放出一些相关的信息,各位感兴趣的话可以去研究下,期待你的分享。
Ø Aiml (Artificial Intelligence Markup Language)
国外一个很优秀的开源人工智能项目,有丰富的语料库,很多聊天机器人都用它来实现。不过原版堆对中文的支持不好,需要修改下源码。
Ø Lucence
Ø IK分词
这两个我也只是扫了一眼,有兴趣直接google吧。
谢谢关注奇迹蛋~扫一下&调戏之