前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >用HarvestText自动识别实体及人物别名,用于实体链接分析

用HarvestText自动识别实体及人物别名,用于实体链接分析

作者头像
blmoistawinde
发布2020-02-14 17:49:11
1.7K0
发布2020-02-14 17:49:11
举报
文章被收录于专栏:润风拂过存甘霖

用HarvestText自动识别实体及人物别名,用于实体链接分析

可以在这里找到本文对应的Jupyter Notebook.

要运行这个例子,需要更新HarvestText到V0.7及以上版本

代码语言:javascript
复制
pip install --upgrade harvesttext

并且,在这里下载数据集,放到与本文件同一路径下。

代码语言:javascript
复制
from harvesttext import HarvestText
代码语言:javascript
复制
ht = HarvestText()

数据预览

代码语言:javascript
复制
with open("all_comments.txt", encoding="utf-8") as f:
    for i, line in enumerate(f):
        if i >= 10:
            break
        print(f"{i}: {line}")
代码语言:javascript
复制
0: 特神牛逼

1: 请教下,叶尔凡去了哪里?也不见替补哇

2: 下场上!

3: 11号请在东看台26区找我不见不散!//<a href="https://home.zhibo8.cc/user.html?platform=mobile&uid=3348048">@江苏苏宁俱乐部</a>:下场上!

4: 这场看了20分钟就走了。还好是免费的![笑哭]

5: 心疼我的筱婷

6: 卡佩罗牛逼,敢上三个U23球员!为你****?

7: 恭喜特谢拉加入“我奶奶都能进”系列[滑稽][捂脸]

8: 视频裁判这么好用居然还有人喷,减少很多争议。耗时间只是刚开始不够专业需要时间来优化。

9: 就算耗时间得到公正判罚也值得了。

可以看到,这里的数据有以下特点:

  1. 包含了许多原始的网络格式。如HTML,还有@和转发等格式。在处理时保留这些东西可能会导致不鲁棒的程序崩溃,或者挖掘出一些无关实体的副作用,所以需要合理的文本清洗。
  2. 网络语言的不正规特点,导致对于同一个对象会有不同的称谓,如示例中的“特神”就是球员“特谢拉”的别名。如果要针对实体进行分析,必须要进行规整。

处理1需要文本清洗,处理2需要挖掘出人物别名,HarvestText提供了能够方便处理这些问题的接口:

文本清洗

ht.clean_text的默认配置就可以处理这类评论和微博类的数据:

代码语言:javascript
复制
sample = '11号请在东看台26区找我不见不散!//<a href="https://home.zhibo8.cc/user.html?platform=mobile&uid=3348048">@江苏苏宁俱乐部</a>:下场上!'
print(ht.clean_text(sample))
代码语言:javascript
复制
11号请在东看台26区找我不见不散! 下场上!

上面的例子就演示了去除HTML代码,以及回复其他用户的特殊格式"//@user",这些信息一般是无用的干扰信息。

函数还提供了更多其他参数,来处理包括:网址;email;html代码中的 一类的特殊字符;网址内的%20一类的特殊字符等问题,可以使用help方法来看函数的注释,以及参照README上的例子

代码语言:javascript
复制
help(ht.clean_text)
代码语言:javascript
复制
Help on method clean_text in module harvesttext.harvesttext:

clean_text(text, remove_url=True, email=True, weibo_at=True, stop_terms=('转发微博',), emoji=True, weibo_topic=False, deduplicate_space=True, norm_url=False, norm_html=False, to_url=False, remove_puncts=False, remove_tags=True) method of harvesttext.harvesttext.HarvestText instance
    进行各种文本清洗操作,微博中的特殊格式,网址,email,html代码,等等
    
    :param text: 输入文本
    :param remove_url: (默认使用)是否去除网址
    :param email: (默认使用)是否去除email
    :param weibo_at: (默认使用)是否去除微博的\@相关文本
    :param stop_terms: 去除文本中的一些特定词语,默认参数为("转发微博",)
    :param emoji: (默认使用)去除\[\]包围的文本,一般是表情符号
    :param weibo_topic: (默认不使用)去除##包围的文本,一般是微博话题
    :param deduplicate_space: (默认使用)合并文本中间的多个空格为一个
    :param norm_url: (默认不使用)还原URL中的特殊字符为普通格式,如(%20转为空格)
    :param norm_html: (默认不使用)还原HTML中的特殊字符为普通格式,如(\&nbsp;转为空格)
    :param to_url: (默认不使用)将普通格式的字符转为还原URL中的特殊字符,用于请求,如(空格转为%20)
    :param remove_puncts: (默认不使用)移除所有标点符号
    :param remove_tags: (默认使用)移除所有html块
    :return: 清洗后的文本

下面清洗所有文本并保存备用

代码语言:javascript
复制
processed_texts = []
with open("all_comments.txt", encoding="utf-8") as f:
    for line in f:
        line = ht.clean_text(line, remove_tags=True)
        if len(line) > 0:
            processed_texts.append(line)
print("\n".join(processed_texts[:10]))
代码语言:javascript
复制
特神牛逼
请教下,叶尔凡去了哪里?也不见替补哇
下场上!
11号请在东看台26区找我不见不散! 下场上!
这场看了20分钟就走了。还好是免费的!
心疼我的筱婷
卡佩罗牛逼,敢上三个U23球员!为你****?
恭喜特谢拉加入“我奶奶都能进”系列
视频裁判这么好用居然还有人喷,减少很多争议。耗时间只是刚开始不够专业需要时间来优化。
就算耗时间得到公正判罚也值得了。

实体发现与别名挖掘

实体的别名之所以会出现,有多种情况:

代码语言:javascript
复制
- 可能是拼写错误(“武磊”经常被写成“吴磊”)
- 是全名缩写等造成的长度变化(“广州恒大淘宝队”, “恒大淘宝队”, “恒大队”, “恒大”)
- 昵称(“特谢拉”, “特神”)
- 其他等等

从自然语言处理的角度来看,前两者是一些模式匹配的问题,而昵称的情况,则需要考虑语义来解决。

V0.7的HarvestText实现了一种我自己称为"NFL"的算法(NER+FastText+Louvain),参考Mining Entity Synonyms with Efficient Neural Set Generation一文中提出的其中一种baseline方法。虽然效果不是最佳的,但还算是一种相对快速且精度尚可的算法,而且很重要的是无监督。并且与原文不同的是,原文的实体发现需要基于知识库的entity linking,而这里我则使用NER来完成这一步,因而彻底摆脱了一切外部数据需求。我用这一算法来实现基于语义的人物别名挖掘。

另外,程序内也实现了一些常见的基于后缀和拼音近似的模式匹配。

ht.entity_discover的方法实现实体别名挖掘,设置参数method="NFL"就会使用上述语义与模式结合的实体发现与别名挖掘,而使用method="NERP"则单纯使用NER+Pattern匹配。

代码语言:javascript
复制
%%time
em_dict, et_dict = ht.entity_discover("\n".join(processed_texts), method="NFL", threshold=0.97)
all_mentions = set(x for enty, ments in em_dict.items() for x in ments)
print(f"Num entities: {len(em_dict)}, Num mentions: {len(all_mentions)}")
代码语言:javascript
复制
Doing NER
100%|██████████| 178290/178290 [01:27<00:00, 2043.79it/s]
Pattern matching
Training fasttext
Louvain clustering
Pattern matching
Num entities: 2284, Num mentions: 3795
Wall time: 2min 34s

在大约2分半的时间内,在178290句话里挖掘出了2240个实体的共3723个别名,还是比较高效的。

挑一些典型案例看看效果:

代码语言:javascript
复制
# 拼音的模式匹配得到
print(em_dict["武磊_人名"])
代码语言:javascript
复制
{'武磊', '吴磊'}
代码语言:javascript
复制
# 模式以及语义匹配得到
print(em_dict["恒大队_机构名"])
代码语言:javascript
复制
{'恒大队', '恒大!', '恒大', '恒大集团', '恒大淘宝队', '恒大女排'}
代码语言:javascript
复制
# 是错误的匹配,但是很有趣地体现出了语义/字面值的近似
print(em_dict["郑州_地名"])
print(em_dict["巴西国家队_机构名"])
代码语言:javascript
复制
{'郑州', '杭州', '苏州', '常州'}
{'巴西国家队', '阿根廷国家队', '韩国国家队', '西班牙国家队', '用国家队', '中国国家队', '罗国家队', '巴西国家', '国家队'}

调整知识库

尽管挖掘出了很多有意义的别名,但是错误也有很多,要用于后续的可靠挖掘,还可以手工调整。

ht提供了保存为易于阅读编辑的格式,并读取的API,用来帮助这个过程。

代码语言:javascript
复制
ht.save_entity_info('./entity_info_v1.txt', em_dict, et_dict)
代码语言:javascript
复制
print("\n".join(open("./entity_info_v1.txt", encoding="utf-8").readlines(100)))
代码语言:javascript
复制
放低_其他专名||其他专名 放低||其他专名

捧杀_其他专名||其他专名 捧杀||其他专名 专杀||其他专名

更容易_其他专名||其他专名 更早||其他专名 更爽||其他专名 更容易||其他专名

双冠王_其他专名||其他专名 双冠王||其他专名

格式:

代码语言:javascript
复制
entity||类别 mention||类别 mention||类别

entity||类别 mention||类别

每行第一个是实体名,其后都是对应的mention名,用一个空格分隔,每个名称后面都对应了其类别。

我们选取和编辑一部分的别名,得到entity_info_v2.txt用于后续分析

代码语言:javascript
复制
print(open("./entity_info_v2.txt", encoding="utf-8").read())
代码语言:javascript
复制
武磊_人名||人名 武磊||人名 吴磊||人名
郜林_人名||人名 郜林||人名
上港队_机构名||机构名 上港队||机构名 上港||机构名
恒大队_机构名||机构名 恒大||机构名 恒大队||机构名 恒大淘宝队||机构名
代码语言:javascript
复制
# 读取加载入模型
ht.load_entities("./entity_info_v2.txt")
print(ht.entity_mention_dict)
print(ht.entity_type_dict)
代码语言:javascript
复制
defaultdict(<class 'set'>, {'武磊_人名': {'武磊', '吴磊'}, '郜林_人名': {'郜林'}, '上港队_机构名': {'上港队', '上港'}, '恒大队_机构名': {'恒大淘宝队', '恒大队', '恒大'}})
{'武磊_人名': '人名', '郜林_人名': '人名', '上港队_机构名': '机构名', '恒大队_机构名': '机构名'}

应用

有了挖掘出的实体别名和清洗好的文本,我们就可以相对放心的对其进行进一步的挖掘了。

ht提供了一些挖掘功能,下面以词频和情感分析为例。上面选取了两个球员和球队,哪个人/球队在球迷心目中更被热议,更受好评呢?

热议度(词频统计)

代码语言:javascript
复制
inv_index = ht.build_index(processed_texts)
print(ht.get_entity_counts(processed_texts, inv_index))
代码语言:javascript
复制
{'武磊_人名': 3565, '郜林_人名': 1492, '上港队_机构名': 6517, '恒大队_机构名': 13022}

好评度(情感分析)

代码语言:javascript
复制
# 使用默认的内置资源建立情感词典,最负面为-1,最正面为+1
senti_dict = ht.build_sent_dict(processed_texts, scale="+-1")
# 假设实体出现的句子的情感都是体现了对其的情感,所有句子的情感的平均值代表了总体好评度
for entity in ht.entity_type_dict:
    entity_appeared_docs = ht.search_entity(entity, processed_texts, inv_index)
    docs_senti = [ht.analyse_sent(doc) for doc in entity_appeared_docs]
    avg_senti = sum(docs_senti) / len(docs_senti)
    print(f"{entity}的好评度为:{avg_senti}")
代码语言:javascript
复制
武磊_人名的好评度为:0.3005335343653094
郜林_人名的好评度为:0.2780580786707832
上港队_机构名的好评度为:0.27413765970801507
恒大队_机构名的好评度为:0.26715797690707327

选取数据所在的赛季,武磊的表现确实比郜林更加出彩,而上港则是力压恒大获得了冠军,与我们的情感分析结果恰好吻合。看来我们做了一个基本正确的情感分析,其基础就是我们之前做的数据清洗以及实体别名发现。

进一步还可以实现这样的数据分析: 一文看评论里的中超风云

2018中超舆情展示系统
2018中超舆情展示系统

期待大家能够用HarvestText做出更多有趣有用的数据分析项目!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 用HarvestText自动识别实体及人物别名,用于实体链接分析
    • 数据预览
      • 文本清洗
        • 实体发现与别名挖掘
          • 调整知识库
            • 应用
              • 热议度(词频统计)
              • 好评度(情感分析)
          相关产品与服务
          NLP 服务
          NLP 服务(Natural Language Process,NLP)深度整合了腾讯内部的 NLP 技术,提供多项智能文本处理和文本生成能力,包括词法分析、相似词召回、词相似度、句子相似度、文本润色、句子纠错、文本补全、句子生成等。满足各行业的文本智能需求。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档