自然语言处理(三)文本处理之分词专题
上次我们了解了文本处理的流程,已经了解了文本处理的大体轮廓。“光说不练假把式!”今天,我们就来实际演练一下文本处理。
分词(Tokenize)
分词就是将句子拆分成一个个具有意义的“小部件”。仿佛就是传送带上的一个个小物品。
例如“Hello,everyone!”这个句子,经过NLTK分词(还不了解NLTK的可以参考下小叮当深度学习:自然语言处理(一)布朗语料库),这个句子便以词为单位存储在了列表中(包括标点符号)。
在使用NLTK执行分词之前,我们需要先安装“punkt”部件。“punkt”包含了许多预训练好的分词模型。如果没有安装“punkt”,我们在使用时系统将会报错,提示我们进行安装。
我们执行“import nltk ”、“nltk.download('punkt')”安装“punkt”部件。等待运行完毕,即可。
具体代码如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'IT小叮当'
date: 2018 / 10 / 18
import nltk
nltk.download('punkt')
在确认“punkt”已安装之后,我们便可以快乐地使用NLTK进行分词了。可以看到,“Hello ,eveyone!”的分词结果为一个列表,句子中的每个词和标点符号都是列表的一个元素。
具体代码如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'IT小叮当'
date: 2018 / 10 / 18
import nltk
sentence = 'hello, everyone!'
tokens = nltk.word_tokenize(sentence)
print("分词后:")
print(tokens)
看到这儿,小伙伴们可能就有疑问了。英文单词之间自带空格,当然就可以直接分词了,那我泱泱华夏华五千年文明传承下来的汉语又该怎么进行分词呢?
且不说沈腾的“红鲤鱼绿鲤鱼与驴”,光是断句就很不容易,一不小心就可能理解成别的意思了。
例如:”汽水不如果汁好喝。”别说计算机了,有的小学生看见也会懵,到底该怎么断句?是“不如”还是“如果”?
“我家门前的小河很难过”是河很不好渡过,还是拟人修辞?这样的例子数不胜数~
那么,计算机该怎样应对中文分词呢?
我们以“今天/天气/不错/!"为例,来进行说明。对于英文“what a nice weather today!”计算机直接根据英文空格便可直接分词。
对于中文,计算机分词一般有两大类方法:(1)启发式(Heuristic);(2)深度学习、机器学习、统计方法等,例如HMM(隐式马尔可夫)、CRF(条件随机场)等。
启发式(Heuristic):
简单来说,就是你拿着一本现代汉语词典,来对照你要处理的文本。对于”今天天气不错!",你将要判断“今天”、“今天天”、“今天天气”、“今天天气不”、“今天天气不错”等是否在字典里,如果在字典里就进行分词,例如“今天”在字典里,这句话就被分成“今天/天气不错”。之后,以同样的方法判断“天气不错”。最后便可以得到正确的分词“今天/天气/不错”。
深度学习:
另一种中文分词的方法就是深度学习,例如斯坦福大学的CoreNLP原生就支持中文分词。
简单来说,我们可以发现,中英文分词的主要区别就是“维度不同”。在自然语言处理角度来看,我们的每个汉字对应的就是英文里的每个字母。例如“word”和“千言万语”,在分词时,一个英文单词字母就相当于我们的一个汉字:w--千,o--言,r--万,d--语。
下面,我们就来看看常用的中文分词工具--Jieba
在python里jieba十分好用,我们直接import就行,当然如果你没安装jieba的话,可以参考下小叮当python:借用清华更新源,让你的pip飞起来!快速安装jieba(pip install jieba)
在jieba里我们直接利用cut即可分词。
jieba分词还可以根据需求设定分词的模式,例如“小明在塞上清华大学”,我们可以有“全模式”、“精确模式”、“搜索引擎模式”。
(1)全模式:jieba分词将根据最大的组词可能性来进行分词。我们设定“cut_all=True”,可以看到“小明在塞上清华大学”在全模式下的分词结果为:
“小/明/在/塞上/上清/清华/清华大学/华大/大学”
在这里可能的组词方式“塞上”、“上清”、“清华”、“华大”、“大学”全部都被罗列出来。
(2)精确模式:默认情况(不设置“cut_all”)下就是精确模式(cut_all=False)。精确模式,将按最符合汉语习惯的断句来进行分词,往往是最精确的。例如“小明在塞上清华大学”在精确模式下的分词结果为:
“小明/在/塞上/清华大学”
(3)搜索引擎模式:将罗列出一句话在搜索引擎里的所有可搜关键字。例如"小明硕士毕业于塞上小清华,后在波士顿大学深造"通过搜索引擎模式后的分词结果为:
“小明/硕士/毕业/于/塞上/小/清华/,/后/在/波士/大学/波士顿/波士顿大学/深造”
具体代码如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'IT小叮当'
date: 2018 / 10 / 30
import jieba
sentence1=jieba.cut("小明在塞上清华大学",cut_all=True)
sentence2=jieba.cut("小明在塞上清华大学",cut_all=False)
sentence3=jieba.cut("小明在塞上清华大学")
sentence4=jieba.cut_for_search("小明硕士毕业于塞上小清华,后在波士顿大学深造")
print("全模式:")
print("/".join(sentence1))
print("---------------")
print("精确模式:")
print("/".join(sentence2))
print("---------------")
print("默认情况:")
print("/".join(sentence3))
print("---------------")
print("搜索引擎模式:")
print("/".join(sentence4))
另外,由于Jieba分词的Viterbi算法,它还可以进行一些新词的识别。例如,“小明来到了网易杭研大厦”,“杭研”是一栋大厦的名字,属于新词,但是jieba仍然能够正确的划分为“小明/来到/了/网易/杭研/大厦”
社交网络上的文本分词
在社交网络上,一些乱七八糟、不合语法、不合正常逻辑的语法有很多:比如@某人,表情符号,URL , #话题符号等。
我们以黄教主和baby某年的推特互动为例进行分析。
某年,黄教主在推特上艾特了baby,说道“RT @angelababy: love you baby! :D http://ah.love #168.com”
如果我们对这句话直接分词,将会得到大量的含有特殊符号的“噪声”信息。
代码如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'IT小叮当'
date: 2018 / 10 / 31
from nltk.tokenize import word_tokenize
tweet = 'RT @angelababy: love you baby! :D http://ah.love #168cm'
print(word_tokenize(tweet))
为了去除这些噪声信息,高度还原句子本身所要表达的意思,我们可以使用正则化的方法来实现。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
__author__ = 'IT小叮当'
__time__ = '2019-03-20 16:03'
from nltk.tokenize import word_tokenize
#对表情做正则
import re
emoticons_str = r"""
(?: [:=;]
[oO\-]?
[D\)\]\(\]/\\OpP] )"""
regex_str = [
emoticons_str,
r'<[^>]+>', # HTML tags
r'(?:@[\w_]+)', # @某⼈人
r"(?:\#+[\w_]+[\w\'_\-]*[\w_]+)", # 话题标签
r'http[s]?://(?:[a-z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-f][0-9a-f]))+', # URLs
r'(?:(?:\d+,?)+(?:\.?\d+)?)', # 数字
r"(?:[a-z][a-z'\-_]+[a-z])", # 含有 - 和 ‘ 的单词
r'(?:[\w_]+)', # 其他
r'(?:\S)' # 其他
]
tokens_re = re.compile( r'('+'|'.join(regex_str)+')', re.VERBOSE | re.IGNORECASE )
emoticon_re = re.compile( r'^'+emoticons_str+'$', re.VERBOSE | re.IGNORECASE )
def tokenize(s):
return tokens_re.findall(s)
def preprocess(s, lowercase=False):
tokens = tokenize(s)
if lowercase:
tokens = [token if emoticon_re.search(token) else token.lower() for token in tokens]
return tokens
tweet = 'RT @angelababy: love you baby! :D http://ah.love #168cm'
print('正则化处理前:')
print(word_tokenize(tweet))
print('正则化处理后:')
print(preprocess(tweet))
处理后的结果如下:
可以看到,经过正则化处理的后的tweet社交文本,可以帮助我们识别出简单的符号表情、网址等信息。
这对于语义的理解是十分重要的!