title: nlp分词词性标注及命名实体
date: 2019-08-27 14:26:38
categories: 人工智能
tags:
- nlp
cover: https://www.github.com/OneJane/blog/raw/master/小书匠/5f549e01ba4ba668ee78d415b042a010_hd.jpg
分词
中文分词(Chinese Word Segmentation)
指的是将一个汉字序列切分成一个一个单独的词。分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。
词性标注
词性标注(Part-of-Speech tagging 或POS tagging)
又称词类标注或者简称标注,是指为分词结果中的每个单词标注一个正确的词性的程 序,也即确定每个词是名词、动词、形容词或其他词性的过程。在汉语中,词性标注比较简单,因为汉语词汇词性多变的情况比较少见,大多词语只有一个词性,或者出现频次最高的词性远远高于第二位的词性。据说,只需选取最高频词性,即可实现80%准确率的中文词性标注程序。
命名实体识别
命名实体识别(Named Entity Recognition,简称NER)
又称作“专名识别”,是指识别文本中具有特定意义的实体,主要包括人名、地名、机构名、专有名词等。一般来说,命名实体识别的任务就是识别出待处理文本中三大类(实体类、时间类和数字类)、七小类(人名、机构名、地名、时间、日期、货币和百分比)命名实体。 在不同的顷目中,命名实体类别具有不同的定义。
准确分词之加载自定义字典分词
当分词工具分词不准确时,该怎么办? 加载自定义字典?该如何加载?
cut_data.py
# -*- coding=utf8 -*-
import jieba
import re
from tokenizer import cut_hanlp
# 加载字典
jieba.load_userdict("dict.txt")
# 交叉拼接list,把FLAG*替换成*期
def merge_two_list(a, b):
c = []
len_a, len_b = len(a), len(b)
minlen = min(len_a, len_b)
for i in range(minlen):
c.append(a[i])
c.append(b[i])
if len_a > len_b:
for i in range(minlen, len_a):
c.append(a[i])
else:
for i in range(minlen, len_b):
c.append(b[i])
return c
if __name__ == "__main__":
fp = open("text.txt", "r", encoding="utf8")
fout = open("result_cut.txt", "w", encoding="utf8")
# 特殊符号字典无法分离,正则区分
regex1 = u'(?:[^\u4e00-\u9fa5()*&……%¥$,,。.@! !]){1,5}期' # 非汉字xxx期
regex2 = r'(?:[0-9]{1,3}[.]?[0-9]{1,3})%' # xx.xx%
p1 = re.compile(regex1)
p2 = re.compile(regex2)
for line in fp.readlines(): # 逐行读取
result1 = p1.findall(line) # 返回匹配到的list
if result1:
regex_re1 = result1
line = p1.sub("FLAG1", line) # 将匹配到的替换成FLAG1
result2 = p2.findall(line)
if result2:
line = p2.sub("FLAG2", line)
words = jieba.cut(line) # 结巴分词,type(word)返回一个generator object
result = " ".join(words) # 结巴分词结果 本身是一个generator object,所以使用 “ ”.join() 拼接起来
# E:\hanlp\data\dictionary\custom\resume_nouns.txt在E:\hanlp\hanlp.properties配置
# CustomDictionaryPath=data/dictionary/custom/CustomDictionary.txt; 现代汉语补充词库.txt; 全国地名大全.txt ns; 人名词典.txt; 机构名词典.txt; resume_nouns.txt; 上海地名.txt ns;data/dictionary/person/nrf.txt nrf;
words1 = cut_hanlp(line) # hanlp分词结果,返回的是str
if "FLAG1" in result:
result = result.split("FLAG1")
result = merge_two_list(result, result1)
ss = result
result = "".join(result) # 本身是个list,我们需要的是str,所以使用 "".join() 拼接起来
if "FLAG2" in result:
result = result.split("FLAG2")
result = merge_two_list(result, result2)
result = "".join(result)
# print(result)
fout.write("jieba:" + result)
fout.write("hanlp:" + words1)
fout.close()
tokenizer.py
# encoding=utf8
import os, gc, re, sys
from jpype import *
root_path = "E:/hanlp"
djclass_path = "-Djava.class.path=" + root_path + os.sep + "hanlp-1.7.4.jar;" + root_path
startJVM(getDefaultJVMPath(), djclass_path, "-Xms1g", "-Xmx1g")
Tokenizer = JClass('com.hankcs.hanlp.tokenizer.StandardTokenizer')
def to_string(sentence, return_generator=False):
if return_generator:
return (word_pos_item.toString().split('/') for word_pos_item in Tokenizer.segment(sentence))
else:
return " ".join([word_pos_item.toString().split('/')[0] for word_pos_item in Tokenizer.segment(sentence)])
# 这里的“”.split('/')可以将string拆分成list 如:'ssfa/fsss'.split('/') => ['ssfa', 'fsss']
def seg_sentences(sentence, with_filter=True, return_generator=False):
segs = to_string(sentence, return_generator=return_generator)
if with_filter:
g = [word_pos_pair[0] for word_pos_pair in segs if
len(word_pos_pair) == 2 and word_pos_pair[0] != ' ' and word_pos_pair[1] not in drop_pos_set]
else:
g = [word_pos_pair[0] for word_pos_pair in segs if len(word_pos_pair) == 2 and word_pos_pair[0] != ' ']
return iter(g) if return_generator else g
def cut_hanlp(raw_sentence, return_list=True):
if len(raw_sentence.strip()) > 0:
return to_string(raw_sentence) if return_list else iter(to_string(raw_sentence))
准确分词之动态调整词频和字典顺序
当分词字典的词冲突,相互影响该怎么办? 调整词频和字典顺序。
cut_data.py
# -*- coding=utf8 -*-
import jieba
import re
from tokenizer import cut_hanlp
jieba.load_userdict("dict.txt")
# # 设置高词频:一个
# jieba.suggest_freq('台中',tune=True)
# 设置高词频:dict.txt中的每一行都设置一下
# fp=open("dict.txt", 'r', encoding='utf8')
# for line in fp:
# line = line.strip()
# jieba.suggest_freq(line, tune=True)
# # 设置高词频:dict.txt中的每一行都设置一下快速方法
[jieba.suggest_freq(line.strip(), tune=True) for line in open("dict.txt", 'r', encoding='utf8')]
if __name__ == "__main__":
string = "台中正确应该不会被切开。"
# 通过调整词频 suggest_freq(line, tune=True)
words_jieba = " ".join(jieba.cut(string, HMM=False))
# 通过排序sort_dict_by_lenth,优先按照长的字典项匹配
words_hanlp = cut_hanlp(string)
print("words_jieba:" + words_jieba, '\n', "words_hanlp:" + words_hanlp)
sort_dict_by_lenth.py
# encoding=utf8
import os
dict_file = open(
"E:" + os.sep + "hanlp" + os.sep + "data" + os.sep + "dictionary" + os.sep + "custom" + os.sep + "resume_nouns.txt",
'r', encoding='utf8')
d = {}
[d.update({line: len(line.split(" ")[0])}) for line in dict_file]
# 读取源字典文件并从长到短排序 优先匹配长字典项
f = sorted(d.items(), key=lambda x: x[1], reverse=True)
dict_file = open(
"E:" + os.sep + "hanlp" + os.sep + "data" + os.sep + "dictionary" + os.sep + "custom" + os.sep + "resume_nouns1.txt",
'w', encoding='utf8')
[dict_file.write(item[0]) for item in f]
dict_file.close()
词性标注代码实现及信息提取
extract_data.py
# -*- coding=utf8 -*-
import jieba
import re
from tokenizer import seg_sentences
fp = open("text.txt", 'r', encoding='utf8')
fout = open("out.txt", 'w', encoding='utf8')
for line in fp:
line = line.strip()
if len(line) > 0:
fout.write(' '.join(seg_sentences(line)) + "\n")
fout.close()
if __name__ == "__main__":
pass
tokenizer.py
# encoding=utf8
import os, gc, re, sys
from jpype import *
root_path = "E:/hanlp"
djclass_path = "-Djava.class.path=" + root_path + os.sep + "hanlp-1.7.4.jar;" + root_path
startJVM(getDefaultJVMPath(), djclass_path, "-Xms1g", "-Xmx1g")
Tokenizer = JClass('com.hankcs.hanlp.tokenizer.StandardTokenizer')
keep_pos = "q,qg,qt,qv,s,t,tg,g,gb,gbc,gc,gg,gm,gp,m,mg,Mg,mq,n,an,vn,ude1,nr,ns,nt,nz,nb,nba,nbc,nbp,nf,ng,nh,nhd,o,nz,nx,ntu,nts,nto,nth,ntch,ntcf,ntcb,ntc,nt,nsf,ns,nrj,nrf,nr2,nr1,nr,nnt,nnd,nn,nmc,nm,nl,nit,nis,nic,ni,nhm,nhd"
keep_pos_nouns = set(keep_pos.split(","))
keep_pos_v = "v,vd,vg,vf,vl,vshi,vyou,vx,vi"
keep_pos_v = set(keep_pos_v.split(","))
keep_pos_p = set(['p', 'pbei', 'pba'])
drop_pos_set = set(
['xu', 'xx', 'y', 'yg', 'wh', 'wky', 'wkz', 'wp', 'ws', 'wyy', 'wyz', 'wb', 'u', 'ud', 'ude1', 'ude2', 'ude3',
'udeng', 'udh', 'p', 'rr', 'w'])
han_pattern = re.compile(r'[^\dA-Za-z\u3007\u4E00-\u9FCB\uE815-\uE864]+')
HanLP = JClass('com.hankcs.hanlp.HanLP')
def to_string(sentence, return_generator=False):
if return_generator:
return (word_pos_item.toString().split('/') for word_pos_item in Tokenizer.segment(sentence))
else:
return [(word_pos_item.toString().split('/')[0], word_pos_item.toString().split('/')[1]) for word_pos_item in
Tokenizer.segment(sentence)]
def seg_sentences(sentence, with_filter=True, return_generator=False):
segs = to_string(sentence, return_generator=return_generator)
if with_filter:
g = [word_pos_pair[0] for word_pos_pair in segs if
len(word_pos_pair) == 2 and word_pos_pair[0] != ' ' and word_pos_pair[1] not in drop_pos_set]
else:
g = [word_pos_pair[0] for word_pos_pair in segs if len(word_pos_pair) == 2 and word_pos_pair[0] != ' ']
return iter(g) if return_generator else g
TextRank算法原理介绍
tex_rank.py
# -*- coding=utf8 -*-
from jieba import analyse
# 引入TextRank关键词抽取接口
textrank = analyse.textrank # 原始文本
text = "非常线程是程序执行时的最小单位,它是进程的一个执行流,\ 是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,\ 线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。\ 线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。\ 同样多线程也可以实现并发操作,每个请求分配一个线程来处理。"
print("\nkeywords by textrank:") # 基于TextRank算法进行关键词抽取
keywords = textrank(text, topK=10, withWeight=True, allowPOS=('ns', 'n'))
# 输出抽取出的关键词 f
words = [keyword for keyword, w in keywords if w > 0.2]
print(' '.join(words) + "\n")
jieba 词性标注
标注 | 含义 | 来源 |
---|---|---|
Ag | 形语素 | 形容词性语素形容词代码为 a,语素代码g前面置以A |
a | 形容词 | 取英语形容词 adjective的第1个字母 |
ad | 副形词 | 直接作状语的形容词形容词代码 a和副词代码d并在一起 |
an | 名形词 | 具有名词功能的形容词形容词代码 a和名词代码n并在一起 |
b | 区别词 | 取汉字“别”的声母 |
c | 连词 | 取英语连词 conjunction的第1个字母 |
dg | 副语素 | 副词性语素副词代码为 d,语素代码g前面置以D |
d | 副词 | 取 adverb的第2个字母,因其第1个字母已用于形容词 |
e | 叹词 | 取英语叹词 exclamation的第1个字母 |
f | 方位词 | 取汉字“方” |
g | 语素 | 绝大多数语素都能作为合成词的“词根”,取汉字“根”的声母 |
h | 前接成分 | 取英语 head的第1个字母 |
i | 成语 | 取英语成语 idiom的第1个字母 |
j | 简称略语 | 取汉字“简”的声母 |
k | 后接成分 | |
l | 习用语 | 习用语尚未成为成语,有点“临时性”,取“临”的声母 |
m | 数词 | 取英语 numeral的第3个字母,n,u已有他用 |
Ng | 名语素 | 名词性语素名词代码为 n,语素代码g前面置以N |
n | 名词 | 取英语名词 noun的第1个字母 |
nr | 人名 | 名词代码 n和“人(ren)”的声母并在一起 |
ns | 地名 | 名词代码 n和处所词代码s并在一起 |
nt | 机构团体 | “团”的声母为 t,名词代码n和t并在一起 |
nz | 其他丏名 | “丏”的声母的第 1个字母为z,名词代码n和z并在一起 |
o | 拟声词 | 取英语拟声词 onomatopoeia的第1个字母 |
p | 介词 | 取英语介词 prepositional的第1个字母 |
q | 量词 | 取英语 quantity的第1个字母 |
r | 代词 | 取英语代词 pronoun的第2个字母,因p已用于介词 |
s | 处所词 | 取英语 space的第1个字母 |
tg | 时语素 | 时间词性语素时间词代码为 t,在语素的代码g前面置以T |
t | 时间词 | 取英语 time的第1个字母 |
u | 助词 | 取英语助词 auxiliary |
vg | 动语素 | 动词性语素动词代码为 v在语素的代码g前面置以V |
v | 动词 | 取英语动词 verb的第一个字母 |
vd | 副动词 | 直接作状语的动词动词和副词的代码并在一起 |
vn | 名动词 | 指具有名词功能的动词动词和名词的代码并在一起 |
w | 标点符号 | |
x | 非语素字 | 非语素字只是一个符号,字母 x通常用于代表未知数、符号 |
y | 语气词 | 取汉字“语”的声母 |
z | 状态词 | 取汉字“状”的声母的前一个字母 |
un | 未知词 | 不可识别词及用户自定义词组取英文Unkonwn首两个字母(非北大标准,CSW分词中定义) |
来源:CSDN
作者:布丁和尚
链接:https://blog.csdn.net/welggy/article/details/100104184