基于Python的中英文分词基础:正则表达式和jieba分词器

您所在的位置:网站首页 结巴英文 基于Python的中英文分词基础:正则表达式和jieba分词器

基于Python的中英文分词基础:正则表达式和jieba分词器

2024-07-10 11:29| 来源: 网络整理| 查看: 265

基于Python的中英文分词基础:正则表达式和jieba分词器 前言介绍英文字符串处理Python中的str正则表达式Python中的正则表达式模块 re 小练习字符串中出现频次最多的字母统计字符出现的频率 中文字符串处理:jieba分词器jieba可以做关键词抽取基于 TF-IDF 算法的关键词抽取(term frequency–inverse document frequency)基于 TextRank 算法的关键词抽取 jieba做词性标注jieba分词加速:并行分词TokenizeChineseAnalyzer for Whoosh 搜索引擎使用命令行分词

前言介绍

这篇博文是我的一次笔记,主要讨论NLP的基础知识:中英文字符串的处理,其中英文部分主要是正则表达式,中文部分是jieba分词器。对于其他常用的扩展包:如NLTK、spacy等将接下来的博文中进行更新。

语料库和词汇知识库对于NLP任务起着极其关键的重要,有时候是建立和改进一个NLP系统的“瓶颈”。对于“语料库和词汇知识库”的基础知识,可以参考宗成庆老师的专著:

《统计自然语言处理》

如果说图像处理技术是智能机器的视觉系统,那么自然语言处理就是智能机器的视觉系统、听觉系统、语言系统;CV注重对一帧一帧的图片或者一段连续的视频进行处理,提取重要信息,而NLP注重对文本、语音(语音识别、语音合成)等信息的理解和生成,不管是语音还是图像中的语言信息最终还是转换为文本进行处理;

如果说语言信息是一种物质的话,那么语音就是包裹物质的外壳,文本是传达物质信息的实际载体;写过爬虫或者从事技术开发的童鞋或多或少都要跟文本信息(字符串)打交道,本博文将简要介绍面向英文和中文字符串的常见处理方法;

英文字符串处理 Python中的str

通过python中的字符串操作(str),可以直接完成一些简单的字符串处理任务,下图采用dir()函数快速了解str对象中的常用内置函数:通过dir()函数快速了解str中的常见内置函数 下面将挑一些使用频率比较高的内置函数进行演示:

去空格和特殊字符:s.strip() 将字符串头和尾的空格,以及位于头尾的\n \t之类给删掉; s.lstrip():从左侧起,去掉左侧括号内的字符,s.rstrip():去掉右边; In: s = ' hello, world!' print(len(s)) a = s.strip() print(a) print(len(a)) print(s.lstrip(' hello, ')) print(s.rstrip('!')) Out: 14 hello, world! 13 world! hello, world 连接两个字符串:+ In: sStr1 = 'strcat' sStr2 = 'append' sStr1 += sStr2 print sStr1 Out: strcatappend 查找字符后者子串:str1.index(str2) # 返回值< 0 为未找到 In: sStr1 = 'strchr' sStr2 = 'r' nPos = sStr1.index(sStr2) print nPos Out: 2 比较两个字符串:cmp(str1,str2); 返回-1:str1str2; 0: str1=str1 In: sStr1 = 'strchr' sStr2 = 'strch' print cmp(sStr2,sStr1) print cmp(sStr1,sStr2) print cmp(sStr1,sStr1) Out: -1 1 0 字符串的大小写:str1.upper()、str1.lower() In: sStr1 = 'JCstrlwr' sStr1 = sStr1.upper() print sStr1 sStr1 = sStr1.lower() print sStr1 Out: JCSTRLWR jcstrlwr 翻转字符串:str1[::-1] In: sStr1 = 'abcdefg' sStr1 = sStr1[::-1] print sStr1 Out: gfedcba 查找字符串:str1.find(str2) 返回str2中首字母出现的下标,不存在返回-1 In: sStr1 = 'abcdefg' sStr2 = 'cde' print sStr1.find(sStr2) Out: 2 分割字符串:s.split() In: sStr1 = 'ab,cde,fgh,ijk' sStr2 = ',' sStr1 = sStr1[sStr1.find(sStr2) + 1:] # 有个小小的递归在这里 print sStr1 #或者 s = 'ab,cde,fgh,ijk' print(s.split(',')) Out: cde,fgh,ijk ['ab', 'cde', 'fgh', 'ijk']

好了,以上就是常用的字符串操作,下面介绍正则表达式;

正则表达式

对于正则表达式一定不陌生,它描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。 对于正则表达式的教程可以参考:

https://www.runoob.com/regexp/regexp-syntax.html

当要匹配 一个/多个/任意个 数字/字母/非数字/非字母/某几个字符/任意字符,想要 贪婪/非贪婪 匹配,想要捕获匹配出来的 第一个/所有 内容的时候,主要以下这张正则表达式的常用语法: 正则表达式的常用语法

验证正则表达式正确性的工具:

http://regexr.com/

正则表达式的进阶联系地址(表达式长度越短,得分越高):

https://alf.nu/RegexGolf

Python中的正则表达式模块 re

re模块 (import re), re模块初探 re一般步骤: • 将正则表达式的字符串形式编译(re.compile)为Pattern实例; • 使用Pattern实例处理文本并获得匹配结果(一个Match的实例); • 使用match实例获得信息,进行其他操作; 示例:

import re # 将正则表达式编译成Pattern对象 pattern = re.compile(r'hello.*\!') #匹配以hello开始,以!结束的字符串 # 使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None match = pattern.match('hello,world! How are you?') if match: # 使用Match获得分组信息 print(match.group()) Out: Hello, world!

re.compile(strPattern[, flag]):

这个是Pattern类的工厂方法,用于将字符串形式的正则表达式编译为Pattern对象。第二个参数flag是匹配模式,取值可以使用按位或运算符’|‘表示同时生效,比如re.I | re.M。 flag可选值有: re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同) re.M(MULTILINE): 多行模式,改变’^‘和’$‘的行为 re.S(DOTALL): 点任意匹配模式,改变’.'的行为 re.L(LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定 re.U(UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性 re.X(VERBOSE): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。

当然,也可以在字符串中指定模式,比如re.compile(‘pattern’, re.I | re.M)等价于re.compile(’(?im)pattern’)

Match Match对象是一次匹配的结果,包含了很多关于此次匹配的信息,可以使用Match提供的可读属性或方法来获取这些信息。 match属性: string: 匹配时使用的文本。 re: 匹配时使用的Pattern对象。 pos: 文本中正则表达式开始搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。 endpos: 文本中正则表达式结束搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。 lastindex: 最后一个被捕获的分组在文本中的索引。如果没有被捕获的分组,将为None。 lastgroup: 最后一个被捕获的分组的别名。如果这个分组没有别名或者没有被捕获的分组,将为None。 方法:

group([group1, …]): 获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。group1可以使用编号也可以使用别名;编号0代表整个匹配的子串;不填写参数时,返回group(0);没有截获字符串的组返回None;截获了多次的组返回最后一次截获的子串。groups([default]): 以元组形式返回全部分组截获的字符串。相当于调用group(1,2,…last)。default表示没有截获字符串的组以这个值替代,默认为None。groupdict([default]): 返回以有别名的组的别名为键、以该组截获的子串为值的字典,没有别名的组不包含在内。default含义同上。start([group]): 返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引)。group默认值为0。end([group]): 返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引+1)。group默认值为0。span([group]): 返回(start(group), end(group))。expand(template): 将匹配到的分组代入template中然后返回。template中可以使用\id或\g、\g引用分组,但不能使用编号0。\id与\g是等价的;但\10将被认为是第10个分组,如果你想表达\1之后是字符’0’,只能使用\g0。

pattern match(string[, pos[, endpos]]) | re.match(pattern, string[, flags]): 这个方法将从string的pos下标处起尝试匹配pattern:如果pattern结束时仍可匹配,则返回一个Match对象;如果匹配过程中pattern无法匹配,或者匹配未结束就已到达endpos,则返回None。pos和endpos的默认值分别为0和len(string)。 注意:这个方法并不是完全匹配。当pattern结束时若string还有剩余字符,仍然视为成功。想要完全匹配,可以在表达式末尾加上边界匹配符’$’。 **search(string[, pos[, endpos]]) | re.search(pattern, string[, flags]): ** 这个方法从string的pos下标处起尝试匹配pattern:如果pattern结束时仍可匹配,则返回一个Match对象若无法匹配,则将pos加1后重新尝试匹配,直到pos=endpos时仍无法匹配则返回None。pos和endpos的默认值分别为0和len(string)); split(string[, maxsplit]) | re.split(pattern, string[, maxsplit]): 按照能够匹配的子串将string分割后返回列表。maxsplit用于指定最大分割次数,不指定将全部分割。 findall(string[, pos[, endpos]]) | re.findall(pattern, string[, flags]): 搜索string,以列表形式返回全部能匹配的子串。 finditer(string[, pos[, endpos]]) | re.finditer(pattern, string[, flags]): 搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。 sub(repl, string[, count]) | re.sub(pattern, repl, string[, count]): 使用repl替换string中每一个匹配的子串后返回替换后的字符串。 当repl是一个字符串时,可以使用\id或\g、\g引用分组,但不能使用编号0。 当repl是一个方法时,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。 count用于指定最多替换次数,不指定时全部替换。 subn(repl, string[, count]) |re.sub(pattern, repl, string[, count]): 返回 (sub(repl, string[, count]), 替换次数)。

小练习 字符串中出现频次最多的字母 #版本1:利用正则表达式和计数器 import re from collections import Counter def get_max_value_v1(text): text = text.lower() result = re.findall('[a-zA-Z]', text) # 去掉列表中的符号符 count = Counter(result) # Counter({'l': 3, 'o': 2, 'd': 1, 'h': 1, 'r': 1, 'e': 1, 'w': 1}) count_list = list(count.values()) max_value = max(count_list) max_list = [] for k, v in count.items(): if v == max_value: max_list.append(k) max_list = sorted(max_list) return max_list[0] #利用计数器 from collections import Counter def get_max_value(text): count = Counter([x for x in text.lower() if x.isalpha()]) m = max(count.values()) return sorted([x for (x, y) in count.items() if y == m])[0] #version 3 import string def get_max_value(text): text = text.lower() return max(string.ascii_lowercase, key=text.count) 统计字符出现的频率 # map函数 #T h e M i s s i s s i p p i R i v e r #[1, 1, 2, 2, 1, 5, 4, 4, 5, 4, 4, 5, 2, 2, 5, 2, 1, 5, 1, 2, 1] sentence='The Mississippi River' def count_chars(s): s=s.lower() count=list(map(s.count,s)) return (max(count)) print count_chars(sentence) 中文字符串处理:jieba分词器

jieba是一个非常好用的中文工具,是以分词起家的,但是功能比分词要强大很多。是目前开源软件中,最好用的中文分析库之一。Python环境下需要安装并导入:

import jieba

jieba模块初探 jieba.cut 以及 jieba.cut_for_search 返回的结构都是一个可迭代的 generator,可以使用 for 循环来获得分词后得到的每一个词语(unicode) jieba.cut 方法接受三个输入参数:

需要分词的字符串cut_all 参数用来控制是否采用全模式HMM 参数用来控制是否使用 HMM 模型(分词效果比较好的,一般都需要隐马尔可夫模型)

jieba.cut_for_search 方法接受两个参数:该方法适合用于搜索引擎构建倒排索引的分词,粒度比较细

需要分词的字符串是否使用 HMM 模型。 jieba.lcut 以及 jieba.lcut_for_search 直接返回 list 而不是 generator,用法与上面的一致。

添加用户自定义词典

很多时候我们需要针对自己的场景进行分词,会有一些领域内的专有词汇。 可以用 jieba.load_userdict(file_name) 加载用户字典;少量的词汇可以自己用下面方法手动添加: 用 add_word(word, freq=None, tag=None) 和 del_word(word) 在程序中动态修改词典 注意: 这种情况下HMM 需要被设置为False,不然HMM会忽略掉动态修改的信息;用 suggest_freq(segment, tune=True) 可调节单个词语的词频,使其能(或不能)被分出来。 jieba可以做关键词抽取

关于TF-IDF和TextRank的理论,将在下一篇博客中给出,这里只关注这两个方法在jieba中的使用; 通常数据量很大的时候,可以选用TextRank提取关键词(TextRank与Google的PageRank类似,通过分析大量的文档获得更加精确的关系); TF-IDF可以通过优化停用词库和自定义语料库,也可以获得比较好的效果;

基于 TF-IDF 算法的关键词抽取(term frequency–inverse document frequency)

TF: 当前词在当前文档中出现的频率 IDF: 这个词在所有文档中出现的频率,逆向文件频率 用法:

import jieba.analyse jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=()) sentence 为待提取的文本topK 为返回几个 TF/IDF 权重最大的关键词,默认值为 20withWeight 为是否一并返回关键词权重值,默认值为 FalseallowPOS 仅包括指定词性的词,默认值为空,即不筛选

关于TF-IDF 算法的关键词抽取补充内容: 1. 关键词提取所使用逆向文件频率(IDF)文本语料库可以切换成自定义语料库的路径

用法: jieba.analyse.set_idf_path(file_name) # file_name为自定义语料库的路径

自定义语料库示例可参考:

https://github.com/fxsjy/jieba/blob/master/extra_dict/idf.txt.big

用法示例可参考

https://github.com/fxsjy/jieba/blob/master/test/extract_tags_idfpath.py

2. 关键词提取所使用停止词(Stop Words)文本语料库可以切换成自定义语料库的路径

用法: jieba.analyse.set_stop_words(file_name) # file_name为自定义语料库的路径

自定义语料库示例可参考

https://github.com/fxsjy/jieba/blob/master/extra_dict/stop_words.txt

用法示例可参考

https://github.com/fxsjy/jieba/blob/master/test/extract_tags_stop_words.py

3.关键词一并返回关键词权重值示例

用法示例可参考

https://github.com/fxsjy/jieba/blob/master/test/extract_tags_with_weight.py

基于 TextRank 算法的关键词抽取 # 直接使用,接口相同,注意默认过滤词性: jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v')) # 新建自定义 TextRank 实例 jieba.analyse.TextRank()

原始论文: TextRank: Bringing Order into Texts

http://web.eecs.umich.edu/~mihalcea/papers/mihalcea.emnlp04.pdf

基本思想:

将待抽取关键词的文本进行分词以固定窗口大小(默认为5,通过span属性调整),词之间的共现关系,构建图计算图中节点的PageRank,注意是无向带权图 jieba做词性标注 # 新建自定义分词器,tokenizer 参数可指定内部使用的 jieba.Tokenizer 分词器。 # jieba.posseg.dt 为默认词性标注分词器 jieba.posseg.POSTokenizer(tokenizer=None)

标注句子分词后每个词的词性,采用和 ictclas 兼容的标记法。

具体的词性对照表参见计算所汉语词性标记集

http://ictclas.nlpir.org/nlpir/html/readme.htm

import jieba.posseg as pseg words = pseg.cut("我爱自然语言处理") for word, flag in words: print('%s %s' % (word, flag)) Out: 我 r 爱 v 自然语言 l 处理 v jieba分词加速:并行分词

原理: 将目标文本按行分隔后,把各行文本分配到多个 Python 进程并行分词,然后归并结果,从而获得分词速度的可观提升 基于 python 自带的 multiprocessing 模块,目前暂不支持 Windows 用法:

jieba.enable_parallel(4) # 开启并行分词模式,参数为并行进程数;jieba.disable_parallel() # 关闭并行分词模式;

实验结果:在 4 核 3.4GHz Linux 机器上,对金庸全集进行精确分词,获得了 1MB/s 的速度,是单进程版的 3.3 倍。 注意: 并行分词仅支持默认分词器 jieba.dt 和 jieba.posseg.dt。

Tokenize

返回词语在原文的起止位置(定位) 注意,输入参数只接受 unicode

ChineseAnalyzer for Whoosh 搜索引擎

from jieba.analyse import ChineseAnalyzer

使用命令行分词

使用示例:python -m jieba news.txt > cut_result.txt

命令行选项(翻译): 使用: python -m jieba [options] filename 结巴命令行界面。 固定参数: filename 输入文件 可选参数: -h, --help 显示此帮助信息并退出 -d [DELIM], --delimiter [DELIM] 使用 DELIM 分隔词语,而不是用默认的’ / '。 若不指定 DELIM,则使用一个空格分隔。 -p [DELIM], --pos [DELIM] 启用词性标注;如果指定 DELIM,词语和词性之间 用它分隔,否则用 _ 分隔 -D DICT, --dict DICT 使用 DICT 代替默认词典 -u USER_DICT, --user-dict USER_DICT 使用 USER_DICT 作为附加词典,与默认词典或自定义词典配合使用 -a, --cut-all 全模式分词(不支持词性标注) -n, --no-hmm 不使用隐含马尔可夫模型 -q, --quiet 不输出载入信息到 STDERR -V, --version 显示版本信息并退出

如果没有指定文件名,则使用标准输入。 –help 选项输出: $> python -m jieba --help Jieba command line interface.

positional arguments: filename input file

optional arguments: -h, --help show this help message and exit -d [DELIM], --delimiter [DELIM] use DELIM instead of ’ / ’ for word delimiter; or a space if it is used without DELIM -p [DELIM], --pos [DELIM] enable POS tagging; if DELIM is specified, use DELIM instead of ‘_’ for POS delimiter -D DICT, --dict DICT use DICT as dictionary -u USER_DICT, --user-dict USER_DICT use USER_DICT together with the default dictionary or DICT (if specified) -a, --cut-all full pattern cutting (ignored with POS tagging) -n, --no-hmm don’t use the Hidden Markov Model -q, --quiet don’t print loading messages to stderr -V, --version show program’s version number and exit

If no filename specified, use STDIN instead.

最后:这部分内容整理自Julyedu的课程笔记,接下来将整理关键词提取算法;



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3