第一弹----NLP基础知识

字符串相关操作

我们一起回顾一下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.

猜你喜欢

转载自blog.csdn.net/weixin_41931540/article/details/87524169
今日推荐