字符串相关操作
我们一起回顾一下Python字符串的相关操作,这是非常基础的知识,但却是使用频度非常高的一些功能
- 去空格及特殊符号
s = 'hello world!'
#去掉相关的字符串
print(s.strip()) # 输出为:hello world!
print(s.lstrip('hello ')) # world!
print(s.rstrip('!')) # hello world
- 利用加号直接连接字符串
- 查找字符
str1 = 'strchar'
str2 = 'r'
npos = str1.index(str2) # 输出str2在str1中第一次出现的位置
print(npos) # 2
- 比较字符串,Python的cmp()函数用来比较两个对象,cmp(X, Y),如果X小于Y,那么返回一个负值,如果大于则返回一个正值,如果相等则返回0
str1 = 'strchr'
str2 = 'strch'
print(cmp(str1, str2)) # 1
print(cmp(str2, str1)) # -1
print(cmp(str1, str1)) # 0
- 翻转字符串
str1 = 'strchr'
str2 = str1[::-1]
print(str2) # rhcrts
- 查找字符串
str1 = 'abcdefg'
str2 = 'cde'
# 在str1中查找str2,并返回查找到的第一个字符的位置
print(str1.find(str2)) # 2
- 分割字符串
str1 = 'ab,cde,fgh,ijk'
str2 = ','
str1 = str1[str1.find(str2) + 1:]
print(str1)
# 或者
s = 'ab,cde,fgh,ijk'
print(s.split(',')) # 返回的是一个列表
- 计算字符串中出现频次最多的字母
import re
from collections import Counter
def get_max_value_vl(text):
text = text.lower()
# 将文本中的所有字母单独列出来,并放在一个列表中,可以理解是去掉符号(但是不准确)
result = re.findall('[a-zA-Z]', text) # 去掉列表中的符号
# 对分好的文本进行统计每个字符出现的次数,然后以字典的方式存储在count中
count = Counter(result)
# 将count中的所有的值存放到列表中
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]
if __name__ == '__main__':
max_value = get_max_value_vl('ac,f,srff,sf,.ff,fff.huyy')
print(max_value)
# version2ad
from collections import Counter
def get_max_value(text):
# isalpha()函数检测字符串是否只由字母组成
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]
if __name__ == '__main__':
print(get_max_value('dhuhf,jdfj,jcijf,huhfu'))
# version3
import string
def get_max_value(text):
text = text.lower()
# string.ascii_lowercase等价于'abcdefghijklmnopqrstuvwxyz'
# text.count是一个有返回值的函数
# 这句话的意思就是在26个英文字母中选择满足key参数条件的所有值,如果有多个值满足条件,那么久返回第一个
return max(string.ascii_lowercase, key=text.count)
if __name__ == '__main__':
print(get_max_value('hcdhcudhvud'))
- 查看字符串中出现次数最高的次数
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.cut以及jieba.cut_for_search返回的结构都是一个可迭代的generator,可以使用for循环来获得分词后得到的每一个词语(unicode)
jieba.cut方法接受三个输入参数
- 需要分词的字符串
- cut_all参数用来控制是否采用全模式,默认是False
- HMM参数用来控制是否使用HMM模型
jieba.cut_for search方法接受两个参数
- 需要分词的字符串
- 是否使用HMM模型
该方法适合用于搜索引擎构建倒排索引的分词,粒度比较细
# encoding=utf-8
import jieba
seg_list = jieba.cut("我在学习自然语言处理", cut_all=True)
print(seg_list)
print("Full Mode: " + "/ ".join(seg_list)) # 全模式
seg_list = jieba.cut("我在学习自然语言处理", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精确模式
seg_list = jieba.cut("他毕业于上海交通大学,在百度深度学习研究院进行研究") # 默认是精确模式
print(", ".join(seg_list))
seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所,后在哈佛大学深造") # 搜索引擎模式
print(", ".join(seg_list))
运行结果:
Full Mode: 我/ 在/ 学习/ 自然/ 自然语言/ 语言/ 处理
Default Mode: 我/ 在/ 学习/ 自然语言/ 处理
他, 毕业, 于, 上海交通大学, ,, 在, 百度, 深度, 学习, 研究院, 进行, 研究
小明, 硕士, 毕业, 于, 中国, 科学, 学院, 科学院, 中国科学院, 计算, 计算所, ,, 后, 在, 哈佛, 大学, 哈佛大学, 深造
注:
- 搜索引擎模式会将句子中所有有意义的词或者词组全部显示出来
- 全模式会从头到尾依次查找有意义的词组
- 精准模式会将句子完整的进行分割,不会产生多余的词组
- jieba.lcut以及jieba.lcut_for_search直接返回list
添加用户自定义词典
很多时候我们需要针对自己的场景进行分词,会有一些领域的专有词汇
- 可以用jieba.load_userdict(file_name)加载用户字典
- 少量的词汇可以自己用下面的方法手动添加
- 用add_word(word, freq=None, tag=None)和del_word(word)在程序中动态修改词典
- 用suggest_freq(segment, tune=True)可以调节单个词语的词频,使其能(或不能)被分出来
import jieba
print('/'.join(jieba.cut('如果放在旧字典中将出错', HMM=False)))
运行结果:
如果/放在/旧/字典/中将/出错
很明显中将二字不能放在一起进行处理,可通过修改词频来解决这个问题
# 如果直接进行精准分词的话,显然将‘中将’两个字放在一起是不合适的
jieba.suggest_freq(('中','将'), True) # 告诉程序中将两个字不能被分在一起
print('/'.join(jieba.cut('如果放在旧字典中将出错', HMM=False)))
运行结果:
如果/放在/旧/字典/中/将/出错
关键词提取
基于TF-IDF算法的关键词抽取
import jieba.analyse
- jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())
- sentence为待提取的文本
- topK为返回几个TF/IDF权重最大的关键词,默认值为20
- withWeight为是否一并返回关键词权重值,默认值为False
- allowPOS包含指定的词性,意味着筛选指定词性的词,默认值为空即不筛选
import jieba.analyse as analyse
lines = open('NBA.txt', 'rb').read()
print(' '.join(analyse.extract_tags(lines, topK=20, withWeight=False, allowPOS=())))
运行结果:
韦少 杜兰特 全明星 全明星赛 MVP 威少 正赛 科尔 投篮 勇士 球员 斯布鲁克 更衣柜 NBA 张卫平 三连庄 西部 指导 雷霆 明星队
关于TF-IDF算法的关键词提取补充
- 关键词提取所使用逆向文件频率(IDF)文本语料库可以切换成自定义语料库的路径
- 用法:jieba.analyse.set_idf_path(file_name) # file_name为自定义语料库的路径
- 关键词提取所使用停止词(STOP WORDS)文本语料库可以切换成自定义语料库的路径,停止词就是那些大量存在却没什么实际作用的词,比如说语气词,这些词在做文本分析的过程中是应该忽略的
- 用法:jieba.analyse.set_stop_words(file_name) # file_name为自定义路径
- 关键词一并返回关键词权重
使用TextRank算法的关键词抽取
- jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v')),直接使用,接口相同,注意默认过滤词性
- jieba.analyse.TextRank() 新建自定义TextRank实例
基本思想
- 将待抽取关键词的文本进行分词
- 以固定窗口大小(默认为5,使用span属性调整),词之间的共性关系,构建图
- 计算图中节点的PageRank,注意是无向带权图
import jieba.analyse as analyse
lines = open('NBA.txt', 'rb').read()
print(' '.join(analyse.textrank(lines, topK=20, withWeight=False, allowPOS=('v', 'n', 'ns','vn'))))
print('----------我是分割线-------------')
print(' '.join(analyse.textrank(lines, topK=20, withWeight=False, allowPOS=('v', 'n'))))
运行结果:
全明星赛 勇士 正赛 指导 对方 投篮 球员 没有 出现 时间 威少 认为 看来 结果 相隔 助攻 现场 三连庄 介绍 嘉宾
----------我是分割线-------------
全明星赛 勇士 指导 正赛 对方 投篮 球员 没有 认为 出现 威少 时间 现场 看来 相隔 不会 位置 结果 玩命 蝉联
词性标注
- jieba.posseg.POSTokenizer(tokenizer=None)新建自定义分词器,tokenizer参数可指定内部使用的jieba.Tokenizer分词器。jieba.posseg.dt为默认词性标注分词器
- 标注句子分词后每个词的词性,采用和ictclas兼容的标记法
import jieba.posseg as pseg
words = pseg.cut('我爱自然语言处理')
for word,flag in words:
print('%s %s'%(word,flag))
运行结果:
我 r
爱 v
自然语言 l
处理 v
并行分词
原理:将目标文件按行分割后,把各行文本分配到多个Python进程并行分词,然后归并结果,从而获得分词速度的可观提升,基于Python自带的multiprocessing模块,目前暂不支持windows
用法:
jieba.enable_parallel(4) # 开启并行分词模式,参数为并行进程数
jieba.disable_parallel() # 关闭并行分词模式
实验结果:在四核3.4GHZ的Linux机器上,对金庸全集进行精确分词,获得了1MB/s的速度,是单进程版的3.3倍
注意:并行分词仅支持默认分词器jieba.dt和jieba.posseg.dt
import sys
import time
import jieba
jieba.enable_parallel()
content = open(u'西游记.txt',"r").read()
t1 = time.time()
words = "/ ".join(jieba.cut(content))
t2 = time.time()
tm_cost = t2-t1
print('并行分词速度为 %s bytes/second' % (len(content)/tm_cost))
jieba.disable_parallel()
content = open(u'西游记.txt',"r").read()
t1 = time.time()
words = "/ ".join(jieba.cut(content))
t2 = time.time()
tm_cost = t2-t1
print('非并行分词速度为 %s bytes/second' % (len(content)/tm_cost))
运行结果:
并行分词速度为 830619.50933 bytes/second
非并行分词速度为 259941.448353 bytes/second
Tokenize:返回词语在原文的起止位置
注意:输入参数只接受unicode
print('这是默认模式的tokenize')
result = jieba.tokenize(u'自然语言处理非常有用')
for tk in result:
print('%s\t\tstart:%d\t\tend:%d'%(tk[0],tk[1],tk[2]))
print('\n------我是神奇的分割线------\n')
print('这是搜索模式的tokenize')
result = jieba.tokenize(u'自然语言处理非常有用', mode='search')
for tk in result:
print('%s\t\tstart:%d\t\tend:%d'%(tk[0], tk[1], tk[2]))
运行结果:
这是默认模式的tokenize
自然语言 start:0 end:4
处理 start:4 end:6
非常 start:6 end:8
有用 start:8 end:10
------我是神奇的分割线------
这是搜索模式的tokenize
自然 start:0 end:2
语言 start:2 end:4
自然语言 start:0 end:4
处理 start:4 end:6
非常 start:6 end:8
有用 start:8 end:10
命令行分词
使用示例: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.