自然语言处理(3)

1. 基本文本处理技能

尽管现在很多文本处理采用基于字/字符的方式,词作为能够独立语用的基本语言单位,依然是目前是主流的NLP任务的基本处理单位。对于没有间隔符的汉语,分词就成了文本预处理的第一个任务。汉语分词,现在其实已经有大量的开源工具,比如最常用的jieba, Stanford NLP,THULAC以及最近开源的pkuseg。
宗成庆老师的书里对于分词难度总结为三个方面: 分词规范,歧义切分和未登录词的识别。特别是歧义切分,尽管学术界有关于交集型和组合型,固有型和偶然型这样的划分,但依然很难完全消歧。 任务中提到的正向最大,逆向最大和双向最大,这里也简单说明一下。

1.1 分词的概念

(分词的正向最大、逆向最大、双向最大匹配法)
正向最大匹配法
分词目标:
在词典中进行扫描,尽可能地选择与词典中最长单词匹配的词作为目标分词,然后进行下一次匹配。

算法流程:
假设词典中最长的单词为 5 个,那么最大匹配的起始子串字数也为 5 个

(1)从左往右读入子串,扫描字典,测试读入的子串是否在字典中

(2)如果存在,则从输入中删除掉该子串,重新按照规则取子串,重复(1)

(3)如果不存在于字典中,则从右向左减少子串长度,重复(1)

分词实例:
比如说输入 “北京大学生前来应聘”,

第一轮:取子串 “北京大学生”,正向取词,如果匹配失败,每次去掉匹配字段最后面的一个字
“北京大学生”,扫描 5 字词典,没有匹配,子串长度减 1 变为“北京大学”
“北京大学”,扫描 4 字词典,有匹配,输出“北京大学”,输入变为“生前来应聘”
第二轮:取子串“生前来应聘”
“生前来应聘”,扫描 5 字词典,没有匹配,子串长度减 1 变为“生前来应”
“生前来应”,扫描 4 字词典,没有匹配,子串长度减 1 变为“生前来”
“生前来”,扫描 3 字词典,没有匹配,子串长度减 1 变为“生前”
“生前”,扫描 2 字词典,有匹配,输出“生前”,输入变为“来应聘””
第三轮:取子串“来应聘”
“来应聘”,扫描 3 字词典,没有匹配,子串长度减 1 变为“来应”
“来应”,扫描 2 字词典,没有匹配,子串长度减 1 变为“来”
颗粒度最小为 1,直接输出“来”,输入变为“应聘”
第四轮:取子串“应聘”
“应聘”,扫描 2 字词典,有匹配,输出“应聘”,输入变为“”
输入长度为0,扫描终止
最终结果: “北京大学/生前/来/应聘”

逆向最大匹配法
分词目标:
在词典中进行扫描,尽可能地选择与词典中最长单词匹配的词作为目标分词,然后进行下一次匹配。 在实践中,逆向最大匹配算法性能优于正向最大匹配算法。

算法流程:
假设词典中最长的单词为 5 个,那么最大匹配的起始子串字数也为 5 个

(1)从右往左读入子串,扫描字典,测试读入的子串是否在字典中

(2)如果存在,则从输入中删除掉该子串,重新按照规则取子串,重复(1)

(3)如果不存在于字典中,则从左向右减少子串长度,重复(1)

分词实例:
依然是这个例子 “北京大学生前来应聘”,

第一轮:取子串 “生前来应聘”,逆向取词,如果匹配失败,每次去掉匹配字段最前面的一个字
“生前来应聘”,扫描 5 字词典,没有匹配,字串长度减 1 变为“前来应聘”
“前来应聘”,扫描 4 字词典,没有匹配,字串长度减 1 变为“来应聘”
“来应聘”,扫描 3 字词典,没有匹配,字串长度减 1 变为“应聘”
“应聘”,扫描 2 字词典,有匹配,输出“应聘”,输入变为“大学生前来”
第二轮:取子串“大学生前来”
“大学生前来”,扫描 5 字词典,没有匹配,字串长度减 1 变为“学生前来”
“学生前来”,扫描 4 字词典,没有匹配,字串长度减 1 变为“生前来”
“生前来”,扫描 3 字词典,没有匹配,字串长度减 1 变为“前来”
“前来”,扫描 2 字词典,有匹配,输出“前来”,输入变为“北京大学生”
第三轮:取子串“北京大学生”
“北京大学生”,扫描 5 字词典,没有匹配,字串长度减 1 变为“京大学生”
“京大学生”,扫描 4 字词典,没有匹配,字串长度减 1 变为“大学生”
“大学生”,扫描 3 字词典,有匹配,输出“大学生”,输入变为“北京”
第四轮:取子串“北京”
“北京”,扫描 2 字词典,有匹配,输出“北京”,输入变为“”
输入长度为0,扫描终止
逆向匹配法最终的切分结果为:”北京/ 大学生/ 前来 / 应聘”

双向最大匹配法
分词目标:
将正向最大匹配算法和逆向最大匹配算法进行比较,从而确定正确的分词方法。

算法流程:
比较正向最大匹配和逆向最大匹配结果:
如果分词数量结果不同,那么取分词数量较少的那个;
如果分词数量结果相同 ,
若分词结果相同,可以返回任何一个,
分词结果不同,返回字符比较少的那个。

分词实例:
就上例来看,

正向匹配最终切分结果为:北京大学 / 生前 / 来 / 应聘,分词数量为 4,单字数为 1

逆向匹配最终切分结果为:”北京/ 大学生/ 前来 / 应聘,分词数量为 4,单字数为 0

逆向匹配单字数少,因此返回逆向匹配的结果。

关于分词,其实博大精深,现在那么多的分词工具,其实一旦语料和测试集跨领域,也还做的不是很好,何况现在又有大量生存周期很短的网络用户和新词,也大大加大了分词的难度,毕竟你拿着人明日报的语料库,大概率分不出什么屌丝之类的词语。

1.2 词、字符频率统计

(可以使用Python中的collections.Counter)
字符统计代码如下所示:

text = '我爱自然语言处理。自然语言处理是一个很有意思的研究领域'
from collections import Counter
c = Counter(text)
print(c)

结果如下所示:
Counter({‘言’: 2, ‘自’: 2, ‘然’: 2, ‘。’: 2, ‘处’: 2, ‘理’: 2, ‘语’: 2, ‘研’: 1, ‘很’: 1, ‘域’: 1, ‘爱’: 1, ‘思’: 1, ‘一’: 1, ‘领’: 1, ‘意’: 1, ‘究’: 1, ‘我’: 1, ‘个’: 1, ‘是’: 1, ‘有’: 1, ‘的’: 1})

词频统计相比字符统计而言,只是多了一步分词的过程,具体代码如下所示:

import jieba 
seg_list = list(jieba.cut('我爱自然语言处理。自然语言处理是一个很有意思的研究领域。', cut_all=False)) 
c = Counter(seg_list )
print(c)

结果如下所示:
Counter({’。’: 2, ‘自然语言’: 2, ‘处理’: 2, ‘很’: 1, ‘爱’: 1, ‘研究’: 1, ‘我’: 1, ‘领域’: 1, ‘有意思’: 1, ‘是’: 1, ‘一个’: 1, ‘的’: 1})

结果发现,里面包含了一些标点符号和停用词。如果不需要停用词,可下载停用词词典,进行过滤即可。

2. 语言模型

n-gram是一种基于统计语言模型的算法。它的思想是将文本里面的内容按照指定的单元进行大小为N的滑动窗口操作,每次取得长度为N的序列,直到滑窗结束。模型本质上是一种近似,即第N个词只与前N-1个词相关。如果指定的单元是字,则可用来做分词任务。如果指定的单元是词,则可以计算出整个句子的概率。下面所述的语言模型,都指定单元为词,而不是字。

2.1 语言模型中unigram、bigram、trigram的概念

unigram指的是单个词为一个单元。每个词之间没有关联关系。
bigram指的是两个词为一个单元。当前词只和上一个词有关系。
trigram指的是三个词为一个单元。当前词只和前两个词有关系。
sklearn CountVectorizer

2.2 unigram、bigram频率统计

(可以使用Python中的collections.Counter模块)
unigram等同于词频统计,而bigram频率统计只需要取n-gram,然后传入到Counter()中即可。

3. 文本矩阵化:要求采用词袋模型且是词级别的矩阵化

3.1 分词
(可采用结巴分词来进行分词操作,其他库也可以);

分词工具采用结巴中文分词,涉及到的算法:

基于Trie树结构实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图(DAG);
采用了动态规划查找最大概率路径, 找出基于词频的最大切分组合;
对于未登录词,采用了基于汉字成词能力的HMM模型,使用了Viterbi算法。
结巴中文分词支持的三种分词模式包括:

精确模式:试图将句子最精确地切开,适合文本分析;
全模式:把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义问题;
搜索引擎模式:在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。

import jieba

# 全模式
text = "我爱深度学习的自然语言处理"
seg_list = jieba.cut(text, cut_all=True)
print(u"[全模式]: ", "/ ".join(seg_list))

# 精确模式
seg_list = jieba.cut(text, cut_all=False)
print(u"[精确模式]: ", "/ ".join(seg_list))

# 默认是精确模式
seg_list = jieba.cut(text)
print(u"[默认模式]: ", "/ ".join(seg_list))

# 搜索引擎模式
seg_list = jieba.cut_for_search(text)
print(u"[搜索引擎模式]: ", "/ ".join(seg_list))

结果如下所示:
[全模式]: 我/ 爱/ 深度/ 学习/ 的/ 自然/ 自然语言/ 语言/ 处理
[精确模式]: 我/ 爱/ 深度/ 学习/ 的/ 自然语言/ 处理
[默认模式]: 我/ 爱/ 深度/ 学习/ 的/ 自然语言/ 处理
[搜索引擎模式]: 我/ 爱/ 深度/ 学习/ 的/ 自然/ 语言/ 自然语言/ 处理

注:如果是Python3版本,jieba返回的是一个生成器,需要转换成列表。
seg_list = list(seg_list)

3.2 去停用词;构造词表

不同互联网公司有不同的停用词表,如百度等。这里提供一份百度的停用词表。https://download.csdn.net/download/herosunly/11102927

with open(r'E:\BaiduNetdiskDownload\ml6_0.Teacher\Data\baidu_stopwords.txt', 'r', encoding = 'utf-8') as f:
    content = f.read()
    stop_words = content.split('\n')

3.3 每篇文档的向量化

from sklearn.feature_extraction.text import CountVectorizer

count_vectorizer = CountVectorizer(stop_words=stop_words) #上一步的停用词
count_vectorizer.fit(seg_list)
vec = count_vectorizer.transform(seg_list).toarray()
vocab_list = count_vectorizer.get_feature_names() #得到字典

4.参考

https://blog.csdn.net/shark803/article/details/89189737
https://blog.csdn.net/herosunly/article/details/89177698

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值