背景:
ai浪潮滚滚
为了保住饭碗跟上潮流,所以我有兴趣,刚好工作需要这个。于是就来研究一下——从文章中提取专有名词。
那么我们先从简单的来,提取中文人名入手
本文使用python编写
如何提取人名
首先,我们要从文章内提取人名。因为人名大多是百家姓开头,所以可以根据这个筛选一下。
第一步,把文章充分的切成一个个小片段,一个词都不要漏
我吭哧吭哧的写了一个方法,来完成把内容切割为多个min_n到max_n长度的字符串的任务
代码语言:javascript复制def cut_by_ngram(sentence, min_n, max_n):
rst = []
# 遍历切分长度的范围
for length in range(min_n, min(len(sentence), max_n) 1):
# 按照此时切分长度进行切分
for idx in range(0, len(sentence) - length 1):
rst.append(sentence[idx: idx length])
return rst
因为中文名字大多2到4个字,所以我们可以这样调用
代码语言:javascript复制cut_by_ngram('测试一下'', 2, 4)
但是这样得到的名字,可能存在,但不一定是名字。还可能包含了标点符号,为了更好的观察,我们需要进一步过滤和统计出现次数
首先判断是否全是中文
判断是否中文,我们可以用Unicode的大小判断
代码语言:javascript复制def is_chinese(char):
if 'u4e00' <= char <= 'u9fff':
return True
else:
return False
人名整个是不是由中文组成,我们可以for循环判断,不是就中断方法好了
代码语言:javascript复制 if len(name) == 1:
return
for x in name:
if is_chinese(x) is False:
# print('not is_chinese')
return
然后我们还需要统计一下出现的次数
完整代码如下
代码语言:javascript复制# 通过这个方法,过滤名字,并计算出现次数
def getNameObj(slice_word):
name_obj = {}
# 通过这个方法,过滤名字,并计算出现次数
def filterName(name):
if len(name) == 1:
return
for x in name:
if is_chinese(x) is False:
# print('not is_chinese')
return
num = last_names[name[0]]
# print('filterName:' name)
if num is None or math.isinf(num):
# print('error:',name)
pass
else:
if name in name_obj:
name_obj[name] = name_obj[name] 1
else:
name_obj[name] = 1
return name
content2_arr = list(filter(filterName, slice_word))
# print(content2_arr)
return name_obj
既然我们计算了次数,那么我们就要用上,比如给他排序
代码语言:javascript复制name_obj = {"李相":1,"李亮":2}
def sort_name(name):
return name_obj[name]
names = sorted(list(name_obj), key=sort_name, reverse=True )
sort_sign_names = []
for index,item in enumerate(names, 0):
sort_sign_names.append( item '-' str(name_obj[item]))
最后输出,["李亮","李相":1]
最后,贴一下完整的代码,如下
代码语言:javascript复制import math
# 把内容切割为多个min_n到max_n长度的字符串
def cut_by_ngram(sentence, min_n, max_n):
rst = []
# 遍历切分长度的范围
for length in range(min_n, min(len(sentence), max_n) 1):
# 按照此时切分长度进行切分
for idx in range(0, len(sentence) - length 1):
rst.append(sentence[idx: idx length])
return rst
# 方便排序,如果没有值的情况下返回无穷大
class my_dict(dict):
def __missing__(self, key):
self[key] = float("Inf")
return self[key]
# 百家姓
content = '赵 钱 孙 李 周 吴 郑 王'
# 读取百家姓文件,这个文件里面的姓氏
# file = open('./baijiaxing.txt',mode='r',encoding='utf-8')
# content = file.read()
last_name_arr = content.replace('n', ' ').replace(' ', ' ').split(' ')
# last_name_arr = content.replace('n', ' ').replace(' ', ' ').split(' ')[0:100]
# 生成对象 格式为{"赵":1,"钱":2}
# 1.方便后续排序(没有用上这个功能)
# 2.数组转对象,提升匹配速度
last_name_obj = {}
for index,last_name in enumerate(last_name_arr, 1):
last_name_obj[last_name]=index
last_names = my_dict(last_name_obj)
# print(last_names)
def is_chinese(char):
if 'u4e00' <= char <= 'u9fff':
return True
else:
return False
def getNameObj(slice_word):
name_obj = {}
# 通过这个方法,过滤名字,并计算出现次数
def filterName(name):
if len(name) == 1:
return
for x in name:
if is_chinese(x) is False:
# print('not is_chinese')
return
num = last_names[name[0]]
# print('filterName:' name)
if num is None or math.isinf(num):
# print('error:',name)
pass
else:
if name in name_obj:
name_obj[name] = name_obj[name] 1
else:
name_obj[name] = 1
return name
content2_arr = list(filter(filterName, slice_word))
# print(content2_arr)
return name_obj
# 读取文章
# file2 = open('./名人传记62本(合集)_001.txt',mode='r',encoding='utf-8')
# content2 = file2.read()
# slice_word = cut_by_ngram(content2,2,4)
slice_word = cut_by_ngram('我喜欢李相,李亮,李亮',2,3)
name_obj = getNameObj(slice_word)
# print(slice_word)
# print(name_obj)
def sort_name(name):
return name_obj[name]
names = sorted(list(name_obj), key=sort_name, reverse=True )
sort_sign_names = []
for index,item in enumerate(names, 0):
sort_sign_names.append( item '-' str(name_obj[item]))
# 按照名字出现次数的高低排序,出现次数越多越是考前
print(sort_sign_names)
# 把结果写入文件
file=open('data.json',mode='w',encoding='utf-8')
file.write(str(sort_sign_names));
file.close()
但是,大家会发现这样依然有一些问题,比如有些人名符合规则,但是可能不是人名,是专有名词,比如 高考,云南等。
大家可以尝试自己优化,我这边也会接着出新的文章来完善这一主题。