词义消岐简介

  词义消岐,英文名称为Word Sense Disambiguation,英语缩写为WSD,是自然语言处理(NLP)中一个非常有趣的基本任务。

  那么,什么是词义消岐呢?通常,在我们的自然语言中,不管是英语,还是中文,都有多义词存在。这些多义词的存在,会让人对句子的意思产生混淆,但人通过学习又是可以正确地区分出来的。

  以“小米”这个词为例,如果仅仅只是说“小米”这个词语,你并不知道它实际指的到底是小米科技公司还是谷物。但当我们把词语置于某个特定的语境中,我们能很好地区分出这个词语的意思。比如,

雷军是小米的创始人。

在这个句子中,我们知道这个“小米”指的是小米科技公司。比如

我今天早上喝了一碗小米粥。

在这个句子中,“小米”指的是谷物、农作物。

  所谓词义消岐,指的是在特定的语境中,识别出某个歧义词的正确含义。

  那么,词义消岐有什么作用呢?词义消岐可以很好地服务于语言翻译和智能问答领域,当然,还有许多应用有待开发~

词义消岐实现

  在目前的词义消岐算法中,有不少原创算法,有些实现起来比较简单,有些想法较为复杂,但实现的效果普遍都不是很好。比较经典的词义消岐的算法为Lesk算法,该算法的想法很简单,通过对某个歧义词构建不同含义的语料及待判别句子中该词语与语料的重合程度来实现,具体的算法原理可参考网址:https://en.wikipedia.org/wiki/Lesk_algorithm .

  在下面的部分中,笔者将会介绍自己想的一种实现词义消岐的算法,仅仅是一个想法,仅供参考。

  我们以词语“火箭”为例,选取其中的两个义项(同一个词语的不同含义):NBA球队名燃气推进装置 ,如下:

获取语料

  首先,我们利用爬虫爬取这两个义项的百度百科网页,以句子为单位,只要句子中出现该词语,则把这句话加入到这个义项的预料中。爬虫的完整Python代码如下:

  1. import requests
  2. from bs4 import BeautifulSoup
  3. from pyltp import SentenceSplitter
  4. class WebScrape(object):
  5. def __init__(self, word, url):
  6. self.url = url
  7. self.word = word
  8. # 爬取百度百科页面
  9. def web_parse(self):
  10. headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 \
  11. (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'}
  12. req = requests.get(url=self.url, headers=headers)
  13. # 解析网页,定位到main-content部分
  14. if req.status_code == 200:
  15. soup = BeautifulSoup(req.text.encode(req.encoding), 'lxml')
  16. return soup
  17. return None
  18. # 获取该词语的义项
  19. def get_gloss(self):
  20. soup = self.web_parse()
  21. if soup:
  22. lis = soup.find('ul', class_="polysemantList-wrapper cmn-clearfix")
  23. if lis:
  24. for li in lis('li'):
  25. if '<a' not in str(li):
  26. gloss = li.text.replace('▪', '')
  27. return gloss
  28. return None
  29. # 获取该义项的语料,以句子为单位
  30. def get_content(self):
  31. # 发送HTTP请求
  32. result = []
  33. soup = self.web_parse()
  34. if soup:
  35. paras = soup.find('div', class_='main-content').text.split('\n')
  36. for para in paras:
  37. if self.word in para:
  38. sents = list(SentenceSplitter.split(para))
  39. for sent in sents:
  40. if self.word in sent:
  41. sent = sent.replace('\xa0', '').replace('\u3000', '')
  42. result.append(sent)
  43. result = list(set(result))
  44. return result
  45. # 将该义项的语料写入到txt
  46. def write_2_file(self):
  47. gloss = self.get_gloss()
  48. result = self.get_content()
  49. print(gloss)
  50. print(result)
  51. if result and gloss:
  52. with open('./%s_%s.txt'% (self.word, gloss), 'w', encoding='utf-8') as f:
  53. f.writelines([_+'\n' for _ in result])
  54. def run(self):
  55. self.write_2_file()
  56. # NBA球队名
  57. #url = 'https://baike.baidu.com/item/%E4%BC%91%E6%96%AF%E6%95%A6%E7%81%AB%E7%AE%AD%E9%98%9F/370758?fromtitle=%E7%81%AB%E7%AE%AD&fromid=8794081#viewPageContent'
  58. # 燃气推进装置
  59. url = 'https://baike.baidu.com/item/%E7%81%AB%E7%AE%AD/6308#viewPageContent'
  60. WebScrape('火箭', url).run()

利用这个爬虫,我们爬取了“火箭”这个词语的两个义项的语料,生成了火箭_燃气推进装置.txt文件和火箭_NBA球队名.txt文件,这两个文件分别含有361和171个句子。以火箭_燃气推进装置.txt文件为例,前10个句子如下:

火箭技术的飞速发展,不仅可提供更加完善的各类导弹和推动相关科学的发展,还将使开发空间资源、建立空间产业、空间基地及星际航行等成为可能。

火箭技术是一项十分复杂的综合性技术,主要包括火箭推进技术、总体设计技术、火箭结构技术、控制和制导技术、计划管理技术、可靠性和质量控制技术、试验技术,对导弹来说还有弹头制导和控制、

1903年,俄国的К.E.齐奥尔科夫斯基提出了制造大型液体火箭的设想和设计原理。

火箭有很多种,原始的火箭是用引火物附在弓箭头上,然后射到敌人身上引起焚烧的一种箭矢。

“长征三号丙”火箭是在 “长征三号乙”火箭的基础上, 减少了两个助推器并取消了助推器上的尾翼。

火箭与导弹有什么区别

为了能够在未来大规模的将人类送入太空,不可能依赖传统的火箭和飞船。

火箭V2火箭

探测高层大气的物理特征(如气压、温度、湿度等)和现象的探空火箭。

可一次发射一发至数十发火箭弹。

实现算法

  我们以句子为单位进行词义消岐,即输入一句话,识别出该句子中某个歧义词的含义。笔者使用的算法比较简单,是以TF-IDF为权重的频数判别。以句子

赛季初的时候,火箭是众望所归的西部决赛球队。

为例,对该句子分词后,去掉停用词(stopwords),然后分别统计除了“火箭”这个词以外的TF-IDF值,累加起来,比较在两个义项下这个值的大小即可。

  实现这个算法的完整Python代码如下:

  1. import os
  2. import jieba
  3. from math import log2
  4. # 读取每个义项的语料
  5. def read_file(path):
  6. with open(path, 'r', encoding='utf-8') as f:
  7. lines = [_.strip() for _ in f.readlines()]
  8. return lines
  9. # 对示例句子分词
  10. sent = '赛季初的时候,火箭是众望所归的西部决赛球队。'
  11. wsd_word = '火箭'
  12. jieba.add_word(wsd_word)
  13. sent_words = list(jieba.cut(sent, cut_all=False))
  14. # 去掉停用词
  15. stopwords = [wsd_word, '我', '你', '它', '他', '她', '了', '是', '的', '啊', '谁', '什么','都',\
  16. '很', '个', '之', '人', '在', '上', '下', '左', '右', '。', ',', '!', '?']
  17. sent_cut = []
  18. for word in sent_words:
  19. if word not in stopwords:
  20. sent_cut.append(word)
  21. print(sent_cut)
  22. # 计算其他词的TF-IDF以及频数
  23. wsd_dict = {}
  24. for file in os.listdir('.'):
  25. if wsd_word in file:
  26. wsd_dict[file.replace('.txt', '')] = read_file(file)
  27. # 统计每个词语在语料中出现的次数
  28. tf_dict = {}
  29. for meaning, sents in wsd_dict.items():
  30. tf_dict[meaning] = []
  31. for word in sent_cut:
  32. word_count = 0
  33. for sent in sents:
  34. example = list(jieba.cut(sent, cut_all=False))
  35. word_count += example.count(word)
  36. if word_count:
  37. tf_dict[meaning].append((word, word_count))
  38. idf_dict = {}
  39. for word in sent_cut:
  40. document_count = 0
  41. for meaning, sents in wsd_dict.items():
  42. for sent in sents:
  43. if word in sent:
  44. document_count += 1
  45. idf_dict[word] = document_count
  46. # 输出值
  47. total_document = 0
  48. for meaning, sents in wsd_dict.items():
  49. total_document += len(sents)
  50. # 计算tf_idf值
  51. mean_tf_idf = []
  52. for k, v in tf_dict.items():
  53. print(k+':')
  54. tf_idf_sum = 0
  55. for item in v:
  56. word = item[0]
  57. tf = item[1]
  58. tf_idf = item[1]*log2(total_document/(1+idf_dict[word]))
  59. tf_idf_sum += tf_idf
  60. print('%s, 频数为: %s, TF-IDF值为: %s'% (word, tf, tf_idf))
  61. mean_tf_idf.append((k, tf_idf_sum))
  62. sort_array = sorted(mean_tf_idf, key=lambda x:x[1], reverse=True)
  63. true_meaning = sort_array[0][0].split('_')[1]
  64. print('\n经过词义消岐,%s在该句子中的意思为 %s .' % (wsd_word, true_meaning))

输出结果如下:

  1. ['赛季', '初', '时候', '众望所归', '西部', '决赛', '球队']
  2. 火箭_燃气推进装置:
  3. 初, 频数为: 2, TF-IDF值为: 12.49585502688717
  4. 火箭_NBA球队名:
  5. 赛季, 频数为: 63, TF-IDF值为: 204.6194333469459
  6. 初, 频数为: 1, TF-IDF值为: 6.247927513443585
  7. 时候, 频数为: 1, TF-IDF值为: 8.055282435501189
  8. 西部, 频数为: 16, TF-IDF值为: 80.88451896801904
  9. 决赛, 频数为: 7, TF-IDF值为: 33.13348038429679
  10. 球队, 频数为: 40, TF-IDF值为: 158.712783770034
  11. 经过词义消岐,火箭在该句子中的意思为 NBA球队名 .

测试

  接着,我们对上面的算法和程序进行更多的测试。

输入句子为:

三十多年前,战士们在戈壁滩白手起家,建起了我国的火箭发射基地。

输出结果为:

  1. ['三十多年', '前', '战士', '们', '戈壁滩', '白手起家', '建起', '我国', '发射', '基地']
  2. 火箭_燃气推进装置:
  3. 前, 频数为: 2, TF-IDF值为: 9.063440958888354
  4. 们, 频数为: 1, TF-IDF值为: 6.05528243550119
  5. 我国, 频数为: 3, TF-IDF值为: 22.410959804340102
  6. 发射, 频数为: 89, TF-IDF值为: 253.27878721862933
  7. 基地, 频数为: 7, TF-IDF值为: 42.38697704850833
  8. 火箭_NBA球队名:
  9. 前, 频数为: 3, TF-IDF值为: 13.59516143833253
  10. 们, 频数为: 1, TF-IDF值为: 6.05528243550119
  11. 经过词义消岐,火箭在该句子中的意思为 燃气推进装置 .

输入句子为:

对于马刺这样级别的球队,常规赛只有屈指可数的几次交锋具有真正的意义,今天对火箭一役是其中之一。

输出结果为:

  1. ['对于', '马刺', '这样', '级别', '球队', '常规赛', '只有', '屈指可数', '几次', '交锋', '具有', '真正', '意义', '今天', '对', '一役', '其中', '之一']
  2. 火箭_燃气推进装置:
  3. 只有, 频数为: 1, TF-IDF值为: 7.470319934780034
  4. 具有, 频数为: 5, TF-IDF值为: 32.35159967390017
  5. 真正, 频数为: 2, TF-IDF值为: 14.940639869560068
  6. 意义, 频数为: 1, TF-IDF值为: 8.055282435501189
  7. 对, 频数为: 5, TF-IDF值为: 24.03677461028802
  8. 其中, 频数为: 3, TF-IDF值为: 21.16584730650357
  9. 之一, 频数为: 2, TF-IDF值为: 14.11056487100238
  10. 火箭_NBA球队名:
  11. 马刺, 频数为: 1, TF-IDF值为: 7.470319934780034
  12. 球队, 频数为: 40, TF-IDF值为: 158.712783770034
  13. 常规赛, 频数为: 14, TF-IDF值为: 73.4709851882102
  14. 只有, 频数为: 1, TF-IDF值为: 7.470319934780034
  15. 对, 频数为: 10, TF-IDF值为: 48.07354922057604
  16. 之一, 频数为: 1, TF-IDF值为: 7.05528243550119
  17. 经过词义消岐,火箭在该句子中的意思为 NBA球队名 .

输入句子为:

姚明是火箭队的主要得分手之一。

输出结果为:

  1. ['姚明', '火箭队', '主要', '得分手', '之一']
  2. 火箭_燃气推进装置:
  3. 主要, 频数为: 9, TF-IDF值为: 51.60018906552445
  4. 之一, 频数为: 2, TF-IDF值为: 14.11056487100238
  5. 火箭_NBA球队名:
  6. 姚明, 频数为: 18, TF-IDF值为: 90.99508383902142
  7. 火箭队, 频数为: 133, TF-IDF值为: 284.1437533641371
  8. 之一, 频数为: 1, TF-IDF值为: 7.05528243550119
  9. 经过词义消岐,火箭在该句子中的意思为 NBA球队名 .

输入的句子为:

从1992年开始研制的长征二号F型火箭,是中国航天史上技术最复杂、可靠性和安全性指标最高的运载火箭。

输出结果为:

  1. ['从', '1992', '年', '开始', '研制', '长征二号', 'F', '型', '中国', '航天史', '技术', '最', '复杂', '、', '可靠性', '和', '安全性', '指标', '最高', '运载火箭']
  2. 火箭_燃气推进装置:
  3. 从, 频数为: 6, TF-IDF值为: 29.312144604353264
  4. 1992, 频数为: 1, TF-IDF值为: 6.733354340613827
  5. 年, 频数为: 43, TF-IDF值为: 107.52982410441274
  6. 开始, 频数为: 5, TF-IDF值为: 30.27641217750595
  7. 研制, 频数为: 25, TF-IDF值为: 110.28565614316162
  8. 长征二号, 频数为: 37, TF-IDF值为: 159.11461253349566
  9. F, 频数为: 7, TF-IDF值为: 40.13348038429679
  10. 中国, 频数为: 45, TF-IDF值为: 153.51418105769093
  11. 技术, 频数为: 27, TF-IDF值为: 119.10850863461454
  12. 最, 频数为: 2, TF-IDF值为: 7.614709844115208
  13. 、, 频数为: 117, TF-IDF值为: 335.25857156467714
  14. 可靠性, 频数为: 5, TF-IDF值为: 30.27641217750595
  15. 和, 频数为: 76, TF-IDF值为: 191.22539545388003
  16. 安全性, 频数为: 2, TF-IDF值为: 14.940639869560068
  17. 运载火箭, 频数为: 95, TF-IDF值为: 256.28439093389505
  18. 火箭_NBA球队名:
  19. 从, 频数为: 5, TF-IDF值为: 24.42678717029439
  20. 1992, 频数为: 2, TF-IDF值为: 13.466708681227654
  21. 年, 频数为: 52, TF-IDF值为: 130.0360663588247
  22. 开始, 频数为: 2, TF-IDF值为: 12.11056487100238
  23. 中国, 频数为: 4, TF-IDF值为: 13.64570498290586
  24. 最, 频数为: 3, TF-IDF值为: 11.422064766172813
  25. 、, 频数为: 16, TF-IDF值为: 45.847326025938756
  26. 和, 频数为: 31, TF-IDF值为: 77.99983235618791
  27. 最高, 频数为: 8, TF-IDF值为: 59.76255947824027
  28. 经过词义消岐,火箭在该句子中的意思为 燃气推进装置 .

输入句子为:

到目前为止火箭已经在休斯顿进行了电视宣传,并在大街小巷竖起广告栏。

输出结果为:

  1. ['到', '目前为止', '已经', '休斯顿', '进行', '电视', '宣传', '并', '大街小巷', '竖起', '广告栏']
  2. 火箭_燃气推进装置:
  3. 到, 频数为: 11, TF-IDF值为: 39.19772273088667
  4. 已经, 频数为: 2, TF-IDF值为: 13.466708681227654
  5. 进行, 频数为: 14, TF-IDF值为: 68.39500407682429
  6. 并, 频数为: 11, TF-IDF值为: 49.17351928258037
  7. 火箭_NBA球队名:
  8. 到, 频数为: 6, TF-IDF值为: 21.38057603502909
  9. 已经, 频数为: 2, TF-IDF值为: 13.466708681227654
  10. 休斯顿, 频数为: 2, TF-IDF值为: 14.940639869560068
  11. 进行, 频数为: 2, TF-IDF值为: 9.770714868117755
  12. 并, 频数为: 5, TF-IDF值为: 22.351599673900168
  13. 经过词义消岐,火箭在该句子中的意思为 燃气推进装置 .

总结

  对于笔者的这个算法,虽然有一定的效果,但是也不总是识别正确。比如,对于最后一个测试的句子,识别的结果就是错误的,其实“休斯顿”才是识别该词语义项的关键词,但很遗憾,在笔者的算法中,“休斯顿”的权重并不高。

  对于词义消岐算法,如果还是笔者的这个思路,那么有以下几方面需要改进:

  • 语料大小及丰富程度;
  • 停用词的扩充;
  • 更好的算法。

  笔者的这篇文章仅作为词义消岐的简介以及简单实现,希望能对读者有所启发~

注意:本人现已开通微信公众号: Python爬虫与算法(微信号为:easy_web_scrape), 欢迎大家关注哦~~

NLP入门(九)词义消岐(WSD)的简介与实现的更多相关文章

  1. cips2016+学习笔记︱NLP中的消岐方法总结(词典、有监督、半监督)

    歧义问题方面,笔者一直比较关注利用词向量解决歧义问题: 也许你寄希望于一个词向量能捕获所有的语义信息(例如run即是动车也是名词),但是什么样的词向量都不能很好地进行凸显. 这篇论文有一些利用词向量的 ...

  2. NLP入门资料

    <统计自然语言处理> 一些基础理论概念,涉及统计自然语言处理的基本概念.理论方法和新研究进展,内容包括形式语言与自动机及其在自然语言处理中的应用.语言模型.隐马尔可夫模型.语料库技术.汉语 ...

  3. 学习笔记CB008:词义消歧、有监督、无监督、语义角色标注、信息检索、TF-IDF、隐含语义索引模型

    词义消歧,句子.篇章语义理解基础,必须解决.语言都有大量多种含义词汇.词义消歧,可通过机器学习方法解决.词义消歧有监督机器学习分类算法,判断词义所属分类.词义消歧无监督机器学习聚类算法,把词义聚成多类 ...

  4. 网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?

    1.前言 标题虽然是为了解释有了 IP 地址,为什么还要用 MAC 地址,但是本文的重点在于理解为什么要有 IP 这样的东西.本文对读者的定位是知道 MAC 地址是什么,IP 地址是什么. (本文同步 ...

  5. NLP入门(五)用深度学习实现命名实体识别(NER)

    前言   在文章:NLP入门(四)命名实体识别(NER)中,笔者介绍了两个实现命名实体识别的工具--NLTK和Stanford NLP.在本文中,我们将会学习到如何使用深度学习工具来自己一步步地实现N ...

  6. NLP入门(一)词袋模型及句子相似度

      本文作为笔者NLP入门系列文章第一篇,以后我们就要步入NLP时代.   本文将会介绍NLP中常见的词袋模型(Bag of Words)以及如何利用词袋模型来计算句子间的相似度(余弦相似度,cosi ...

  7. NLP入门(八)使用CRF++实现命名实体识别(NER)

    CRF与NER简介   CRF,英文全称为conditional random field, 中文名为条件随机场,是给定一组输入随机变量条件下另一组输出随机变量的条件概率分布模型,其特点是假设输出随机 ...

  8. C#基础入门 九

    C#基础入门 九 集合 对于很多应用程序,需要创建和管理相关对象组,有两种方式可以将对象分组,一是创建对象数组,如 object[] obj=new object[3]{1,2.33,"st ...

  9. cesium编程入门(九)实体 Entity

    cesium编程入门(九)实体 Entity 在cesium编程入门(五)绘制形状提到过添加实体的方法,这一节聊一聊实体相关的一些内容: 先来看 Entity 的各个属性 id 唯一标志,如果没设置, ...

随机推荐

  1. 5个点彻底搞清楚SpringBoot注解

    作者:张伯毅 一.注解(annotations)列表 @SpringBootApplication:包含了@ComponentScan.@Configuration和@EnableAutoConfig ...

  2. exports、module.exports 和 export、export default

    先了解他们的使用范围. require: node 和 es6 都支持的引入export / import : 只有es6 支持的导出引入module.exports / exports: 只有 no ...

  3. CCF-CSP题解 201503-3 节日

    模拟题. 良心出题人并没有\(y_1>y_2\)的样例.注意闰年的处理. #include <bits/stdc++.h> using namespace std; int dayO ...

  4. CSS | 圣杯布局、双飞翼布局 | 自适应三栏布局

    圣杯布局和双飞翼布局是前端工程师需要日常掌握的重要布局方式.两者的功能相同,都是为了实现一个两侧宽度固定,中间宽度自适应的三栏布局 虽然两者的实现方法略有差异,不过都遵循了以下要点: 1.两侧宽度固定 ...

  5. python基础知识第二篇(字符串)

    基本数据类型 数字                  整形 int                             ---int                            将字符串 ...

  6. Activiti架构分析及源码详解

    目录 Activiti架构分析及源码详解 引言 一.Activiti设计解析-架构&领域模型 1.1 架构 1.2 领域模型 二.Activiti设计解析-PVM执行树 2.1 核心理念 2. ...

  7. hadoop集群搭建教程

    1. 相关软件准备: VMware-workstation-full-15.0.4-12990004.exe CentOS-7-x86_64-DVD-1810.iso jdk-8u231-linux- ...

  8. 基于V6的中移动物联测试例子,当前测试还挺稳定

    下载: 链接:https://pan.baidu.com/s/1Gz8mEffDGXNSK8lIsAIUEg   提取码:2sur 测试步骤看此贴,跟V7开发板是一样的: 基于H7的中移动物联例子以及 ...

  9. 美团点评Kubernetes集群管理实践

    背景 作为国内领先的生活服务平台,美团点评很多业务都具有非常显著.规律的”高峰“和”低谷“特征.尤其遇到节假日或促销活动,流量还会在短时间内出现爆发式的增长.这对集群中心的资源弹性和可用性有非常高的要 ...

  10. TypeScript 参数属性

    假设类中创建的 readonly 类型的属性,该类型的属性只能在声明处或构造器中进行初始化. class Octopus { readonly name: string; readonly numbe ...