前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从文章中提取人物姓名(一)

从文章中提取人物姓名(一)

作者头像
爱吃大橘
发布2023-10-16 15:23:27
3270
发布2023-10-16 15:23:27
举报
文章被收录于专栏:前端笔记薄前端笔记薄

背景:

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()  

但是,大家会发现这样依然有一些问题,比如有些人名符合规则,但是可能不是人名,是专有名词,比如 高考,云南等。

大家可以尝试自己优化,我这边也会接着出新的文章来完善这一主题。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-10-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景:
  • 如何提取人名
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档