詞義消岐簡(jiǎn)介
??詞義消岐,英文名稱為Word Sense Disambiguation,英語縮寫為WSD,是自然語言處理(NLP)中一個(gè)非常有趣的基本任務(wù)。
??那么,什么是詞義消岐呢?通常,在我們的自然語言中,不管是英語,還是中文,都有多義詞存在。這些多義詞的存在,會(huì)讓人對(duì)句子的意思產(chǎn)生混淆,但人通過學(xué)習(xí)又是可以正確地區(qū)分出來的。
??以“小米”這個(gè)詞為例,如果僅僅只是說“小米”這個(gè)詞語,你并不知道它實(shí)際指的到底是小米科技公司還是谷物。但當(dāng)我們把詞語置于某個(gè)特定的語境中,我們能很好地區(qū)分出這個(gè)詞語的意思。比如,
雷軍是小米的創(chuàng)始人。
在這個(gè)句子中,我們知道這個(gè)“小米”指的是小米科技公司。比如
我今天早上喝了一碗小米粥。
在這個(gè)句子中,“小米”指的是谷物、農(nóng)作物。
??所謂詞義消岐,指的是在特定的語境中,識(shí)別出某個(gè)歧義詞的正確含義。
??那么,詞義消岐有什么作用呢?詞義消岐可以很好地服務(wù)于語言翻譯和智能問答領(lǐng)域,當(dāng)然,還有許多應(yīng)用有待開發(fā)~
詞義消岐實(shí)現(xiàn)
??在目前的詞義消岐算法中,有不少原創(chuàng)算法,有些實(shí)現(xiàn)起來比較簡(jiǎn)單,有些想法較為復(fù)雜,但實(shí)現(xiàn)的效果普遍都不是很好。比較經(jīng)典的詞義消岐的算法為L(zhǎng)esk算法,該算法的想法很簡(jiǎn)單,通過對(duì)某個(gè)歧義詞構(gòu)建不同含義的語料及待判別句子中該詞語與語料的重合程度來實(shí)現(xiàn),具體的算法原理可參考網(wǎng)址:https://en.wikipedia.org/wiki/Lesk_algorithm .
??在下面的部分中,筆者將會(huì)介紹自己想的一種實(shí)現(xiàn)詞義消岐的算法,僅僅是一個(gè)想法,僅供參考。
??我們以詞語“火箭”為例,選取其中的兩個(gè)義項(xiàng)(同一個(gè)詞語的不同含義):NBA球隊(duì)名 和 燃?xì)馔七M(jìn)裝置 ,如下:

獲取語料
??首先,我們利用爬蟲爬取這兩個(gè)義項(xiàng)的百度百科網(wǎng)頁(yè),以句子為單位,只要句子中出現(xiàn)該詞語,則把這句話加入到這個(gè)義項(xiàng)的預(yù)料中。爬蟲的完整Python代碼如下:
import requests
from bs4 import BeautifulSoup
from pyltp import SentenceSplitter
class WebScrape(object):
def __init__(self, word, url):
self.url = url
self.word = word
# 爬取百度百科頁(yè)面
def web_parse(self):
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 \
(KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'}
req = requests.get(url=self.url, headers=headers)
# 解析網(wǎng)頁(yè),定位到main-content部分
if req.status_code == 200:
soup = BeautifulSoup(req.text.encode(req.encoding), 'lxml')
return soup
return None
# 獲取該詞語的義項(xiàng)
def get_gloss(self):
soup = self.web_parse()
if soup:
lis = soup.find('ul', class_="polysemantList-wrapper cmn-clearfix")
if lis:
for li in lis('li'):
if '<a' not in str(li):
gloss = li.text.replace('?', '')
return gloss
return None
# 獲取該義項(xiàng)的語料,以句子為單位
def get_content(self):
# 發(fā)送HTTP請(qǐng)求
result = []
soup = self.web_parse()
if soup:
paras = soup.find('div', class_='main-content').text.split('\n')
for para in paras:
if self.word in para:
sents = list(SentenceSplitter.split(para))
for sent in sents:
if self.word in sent:
sent = sent.replace('\xa0', '').replace('\u3000', '')
result.append(sent)
result = list(set(result))
return result
# 將該義項(xiàng)的語料寫入到txt
def write_2_file(self):
gloss = self.get_gloss()
result = self.get_content()
print(gloss)
print(result)
if result and gloss:
with open('./%s_%s.txt'% (self.word, gloss), 'w', encoding='utf-8') as f:
f.writelines([_+'\n' for _ in result])
def run(self):
self.write_2_file()
# NBA球隊(duì)名
#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'
# 燃?xì)馔七M(jìn)裝置
url = 'https://baike.baidu.com/item/%E7%81%AB%E7%AE%AD/6308#viewPageContent'
WebScrape('火箭', url).run()
利用這個(gè)爬蟲,我們爬取了“火箭”這個(gè)詞語的兩個(gè)義項(xiàng)的語料,生成了火箭_燃?xì)馔七M(jìn)裝置.txt文件和火箭NBA球隊(duì)名.txt文件,這兩個(gè)文件分別含有361和171個(gè)句子。以火箭燃?xì)馔七M(jìn)裝置.txt文件為例,前10個(gè)句子如下:
火箭技術(shù)的飛速發(fā)展,不僅可提供更加完善的各類導(dǎo)彈和推動(dòng)相關(guān)科學(xué)的發(fā)展,還將使開發(fā)空間資源、建立空間產(chǎn)業(yè)、空間基地及星際航行等成為可能。
火箭技術(shù)是一項(xiàng)十分復(fù)雜的綜合性技術(shù),主要包括火箭推進(jìn)技術(shù)、總體設(shè)計(jì)技術(shù)、火箭結(jié)構(gòu)技術(shù)、控制和制導(dǎo)技術(shù)、計(jì)劃管理技術(shù)、可靠性和質(zhì)量控制技術(shù)、試驗(yàn)技術(shù),對(duì)導(dǎo)彈來說還有彈頭制導(dǎo)和控制、
1903年,俄國(guó)的К.E.齊奧爾科夫斯基提出了制造大型液體火箭的設(shè)想和設(shè)計(jì)原理。
火箭有很多種,原始的火箭是用引火物附在弓箭頭上,然后射到敵人身上引起焚燒的一種箭矢。
“長(zhǎng)征三號(hào)丙”火箭是在 “長(zhǎng)征三號(hào)乙”火箭的基礎(chǔ)上, 減少了兩個(gè)助推器并取消了助推器上的尾翼。
火箭與導(dǎo)彈有什么區(qū)別
為了能夠在未來大規(guī)模的將人類送入太空,不可能依賴傳統(tǒng)的火箭和飛船。
火箭V2火箭
探測(cè)高層大氣的物理特征(如氣壓、溫度、濕度等)和現(xiàn)象的探空火箭。
可一次發(fā)射一發(fā)至數(shù)十發(fā)火箭彈。
實(shí)現(xiàn)算法
??我們以句子為單位進(jìn)行詞義消岐,即輸入一句話,識(shí)別出該句子中某個(gè)歧義詞的含義。筆者使用的算法比較簡(jiǎn)單,是以TF-IDF為權(quán)重的頻數(shù)判別。以句子
賽季初的時(shí)候,火箭是眾望所歸的西部決賽球隊(duì)。
為例,對(duì)該句子分詞后,去掉停用詞(stopwords),然后分別統(tǒng)計(jì)除了“火箭”這個(gè)詞以外的TF-IDF值,累加起來,比較在兩個(gè)義項(xiàng)下這個(gè)值的大小即可。
??實(shí)現(xiàn)這個(gè)算法的完整Python代碼如下:
import os
import jieba
from math import log2
# 讀取每個(gè)義項(xiàng)的語料
def read_file(path):
with open(path, 'r', encoding='utf-8') as f:
lines = [_.strip() for _ in f.readlines()]
return lines
# 對(duì)示例句子分詞
sent = '賽季初的時(shí)候,火箭是眾望所歸的西部決賽球隊(duì)。'
wsd_word = '火箭'
jieba.add_word(wsd_word)
sent_words = list(jieba.cut(sent, cut_all=False))
# 去掉停用詞
stopwords = [wsd_word, '我', '你', '它', '他', '她', '了', '是', '的', '啊', '誰', '什么','都',\
'很', '個(gè)', '之', '人', '在', '上', '下', '左', '右', '。', ',', '!', '?']
sent_cut = []
for word in sent_words:
if word not in stopwords:
sent_cut.append(word)
print(sent_cut)
# 計(jì)算其他詞的TF-IDF以及頻數(shù)
wsd_dict = {}
for file in os.listdir('.'):
if wsd_word in file:
wsd_dict[file.replace('.txt', '')] = read_file(file)
# 統(tǒng)計(jì)每個(gè)詞語在語料中出現(xiàn)的次數(shù)
tf_dict = {}
for meaning, sents in wsd_dict.items():
tf_dict[meaning] = []
for word in sent_cut:
word_count = 0
for sent in sents:
example = list(jieba.cut(sent, cut_all=False))
word_count += example.count(word)
if word_count:
tf_dict[meaning].append((word, word_count))
idf_dict = {}
for word in sent_cut:
document_count = 0
for meaning, sents in wsd_dict.items():
for sent in sents:
if word in sent:
document_count += 1
idf_dict[word] = document_count
# 輸出值
total_document = 0
for meaning, sents in wsd_dict.items():
total_document += len(sents)
# 計(jì)算tf_idf值
mean_tf_idf = []
for k, v in tf_dict.items():
print(k+':')
tf_idf_sum = 0
for item in v:
word = item[0]
tf = item[1]
tf_idf = item[1]*log2(total_document/(1+idf_dict[word]))
tf_idf_sum += tf_idf
print('%s, 頻數(shù)為: %s, TF-IDF值為: %s'% (word, tf, tf_idf))
mean_tf_idf.append((k, tf_idf_sum))
sort_array = sorted(mean_tf_idf, key=lambda x:x[1], reverse=True)
true_meaning = sort_array[0][0].split('_')[1]
print('\n經(jīng)過詞義消岐,%s在該句子中的意思為 %s .' % (wsd_word, true_meaning))
輸出結(jié)果如下:
['賽季', '初', '時(shí)候', '眾望所歸', '西部', '決賽', '球隊(duì)']
火箭_燃?xì)馔七M(jìn)裝置:
初, 頻數(shù)為: 2, TF-IDF值為: 12.49585502688717
火箭_NBA球隊(duì)名:
賽季, 頻數(shù)為: 63, TF-IDF值為: 204.6194333469459
初, 頻數(shù)為: 1, TF-IDF值為: 6.247927513443585
時(shí)候, 頻數(shù)為: 1, TF-IDF值為: 8.055282435501189
西部, 頻數(shù)為: 16, TF-IDF值為: 80.88451896801904
決賽, 頻數(shù)為: 7, TF-IDF值為: 33.13348038429679
球隊(duì), 頻數(shù)為: 40, TF-IDF值為: 158.712783770034
經(jīng)過詞義消岐,火箭在該句子中的意思為 NBA球隊(duì)名 .
測(cè)試
??接著,我們對(duì)上面的算法和程序進(jìn)行更多的測(cè)試。
輸入句子為:
三十多年前,戰(zhàn)士們?cè)诟瓯跒┌资制鸺?,建起了我?guó)的火箭發(fā)射基地。
輸出結(jié)果為:
['三十多年', '前', '戰(zhàn)士', '們', '戈壁灘', '白手起家', '建起', '我國(guó)', '發(fā)射', '基地']
火箭_燃?xì)馔七M(jìn)裝置:
前, 頻數(shù)為: 2, TF-IDF值為: 9.063440958888354
們, 頻數(shù)為: 1, TF-IDF值為: 6.05528243550119
我國(guó), 頻數(shù)為: 3, TF-IDF值為: 22.410959804340102
發(fā)射, 頻數(shù)為: 89, TF-IDF值為: 253.27878721862933
基地, 頻數(shù)為: 7, TF-IDF值為: 42.38697704850833
火箭_NBA球隊(duì)名:
前, 頻數(shù)為: 3, TF-IDF值為: 13.59516143833253
們, 頻數(shù)為: 1, TF-IDF值為: 6.05528243550119
經(jīng)過詞義消岐,火箭在該句子中的意思為 燃?xì)馔七M(jìn)裝置 .
輸入句子為:
對(duì)于馬刺這樣級(jí)別的球隊(duì),常規(guī)賽只有屈指可數(shù)的幾次交鋒具有真正的意義,今天對(duì)火箭一役是其中之一。
輸出結(jié)果為:
['對(duì)于', '馬刺', '這樣', '級(jí)別', '球隊(duì)', '常規(guī)賽', '只有', '屈指可數(shù)', '幾次', '交鋒', '具有', '真正', '意義', '今天', '對(duì)', '一役', '其中', '之一']
火箭_燃?xì)馔七M(jìn)裝置:
只有, 頻數(shù)為: 1, TF-IDF值為: 7.470319934780034
具有, 頻數(shù)為: 5, TF-IDF值為: 32.35159967390017
真正, 頻數(shù)為: 2, TF-IDF值為: 14.940639869560068
意義, 頻數(shù)為: 1, TF-IDF值為: 8.055282435501189
對(duì), 頻數(shù)為: 5, TF-IDF值為: 24.03677461028802
其中, 頻數(shù)為: 3, TF-IDF值為: 21.16584730650357
之一, 頻數(shù)為: 2, TF-IDF值為: 14.11056487100238
火箭_NBA球隊(duì)名:
馬刺, 頻數(shù)為: 1, TF-IDF值為: 7.470319934780034
球隊(duì), 頻數(shù)為: 40, TF-IDF值為: 158.712783770034
常規(guī)賽, 頻數(shù)為: 14, TF-IDF值為: 73.4709851882102
只有, 頻數(shù)為: 1, TF-IDF值為: 7.470319934780034
對(duì), 頻數(shù)為: 10, TF-IDF值為: 48.07354922057604
之一, 頻數(shù)為: 1, TF-IDF值為: 7.05528243550119
經(jīng)過詞義消岐,火箭在該句子中的意思為 NBA球隊(duì)名 .
輸入句子為:
姚明是火箭隊(duì)的主要得分手之一。
輸出結(jié)果為:
['姚明', '火箭隊(duì)', '主要', '得分手', '之一']
火箭_燃?xì)馔七M(jìn)裝置:
主要, 頻數(shù)為: 9, TF-IDF值為: 51.60018906552445
之一, 頻數(shù)為: 2, TF-IDF值為: 14.11056487100238
火箭_NBA球隊(duì)名:
姚明, 頻數(shù)為: 18, TF-IDF值為: 90.99508383902142
火箭隊(duì), 頻數(shù)為: 133, TF-IDF值為: 284.1437533641371
之一, 頻數(shù)為: 1, TF-IDF值為: 7.05528243550119
經(jīng)過詞義消岐,火箭在該句子中的意思為 NBA球隊(duì)名 .
輸入的句子為:
從1992年開始研制的長(zhǎng)征二號(hào)F型火箭,是中國(guó)航天史上技術(shù)最復(fù)雜、可靠性和安全性指標(biāo)最高的運(yùn)載火箭。
輸出結(jié)果為:
['從', '1992', '年', '開始', '研制', '長(zhǎng)征二號(hào)', 'F', '型', '中國(guó)', '航天史', '技術(shù)', '最', '復(fù)雜', '、', '可靠性', '和', '安全性', '指標(biāo)', '最高', '運(yùn)載火箭']
火箭_燃?xì)馔七M(jìn)裝置:
從, 頻數(shù)為: 6, TF-IDF值為: 29.312144604353264
1992, 頻數(shù)為: 1, TF-IDF值為: 6.733354340613827
年, 頻數(shù)為: 43, TF-IDF值為: 107.52982410441274
開始, 頻數(shù)為: 5, TF-IDF值為: 30.27641217750595
研制, 頻數(shù)為: 25, TF-IDF值為: 110.28565614316162
長(zhǎng)征二號(hào), 頻數(shù)為: 37, TF-IDF值為: 159.11461253349566
F, 頻數(shù)為: 7, TF-IDF值為: 40.13348038429679
中國(guó), 頻數(shù)為: 45, TF-IDF值為: 153.51418105769093
技術(shù), 頻數(shù)為: 27, TF-IDF值為: 119.10850863461454
最, 頻數(shù)為: 2, TF-IDF值為: 7.614709844115208
、, 頻數(shù)為: 117, TF-IDF值為: 335.25857156467714
可靠性, 頻數(shù)為: 5, TF-IDF值為: 30.27641217750595
和, 頻數(shù)為: 76, TF-IDF值為: 191.22539545388003
安全性, 頻數(shù)為: 2, TF-IDF值為: 14.940639869560068
運(yùn)載火箭, 頻數(shù)為: 95, TF-IDF值為: 256.28439093389505
火箭_NBA球隊(duì)名:
從, 頻數(shù)為: 5, TF-IDF值為: 24.42678717029439
1992, 頻數(shù)為: 2, TF-IDF值為: 13.466708681227654
年, 頻數(shù)為: 52, TF-IDF值為: 130.0360663588247
開始, 頻數(shù)為: 2, TF-IDF值為: 12.11056487100238
中國(guó), 頻數(shù)為: 4, TF-IDF值為: 13.64570498290586
最, 頻數(shù)為: 3, TF-IDF值為: 11.422064766172813
、, 頻數(shù)為: 16, TF-IDF值為: 45.847326025938756
和, 頻數(shù)為: 31, TF-IDF值為: 77.99983235618791
最高, 頻數(shù)為: 8, TF-IDF值為: 59.76255947824027
經(jīng)過詞義消岐,火箭在該句子中的意思為 燃?xì)馔七M(jìn)裝置 .
輸入句子為:
到目前為止火箭已經(jīng)在休斯頓進(jìn)行了電視宣傳,并在大街小巷豎起廣告欄。
輸出結(jié)果為:
['到', '目前為止', '已經(jīng)', '休斯頓', '進(jìn)行', '電視', '宣傳', '并', '大街小巷', '豎起', '廣告欄']
火箭_燃?xì)馔七M(jìn)裝置:
到, 頻數(shù)為: 11, TF-IDF值為: 39.19772273088667
已經(jīng), 頻數(shù)為: 2, TF-IDF值為: 13.466708681227654
進(jìn)行, 頻數(shù)為: 14, TF-IDF值為: 68.39500407682429
并, 頻數(shù)為: 11, TF-IDF值為: 49.17351928258037
火箭_NBA球隊(duì)名:
到, 頻數(shù)為: 6, TF-IDF值為: 21.38057603502909
已經(jīng), 頻數(shù)為: 2, TF-IDF值為: 13.466708681227654
休斯頓, 頻數(shù)為: 2, TF-IDF值為: 14.940639869560068
進(jìn)行, 頻數(shù)為: 2, TF-IDF值為: 9.770714868117755
并, 頻數(shù)為: 5, TF-IDF值為: 22.351599673900168
經(jīng)過詞義消岐,火箭在該句子中的意思為 燃?xì)馔七M(jìn)裝置 .
總結(jié)
??對(duì)于筆者的這個(gè)算法,雖然有一定的效果,但是也不總是識(shí)別正確。比如,對(duì)于最后一個(gè)測(cè)試的句子,識(shí)別的結(jié)果就是錯(cuò)誤的,其實(shí)“休斯頓”才是識(shí)別該詞語義項(xiàng)的關(guān)鍵詞,但很遺憾,在筆者的算法中,“休斯頓”的權(quán)重并不高。
??對(duì)于詞義消岐算法,如果還是筆者的這個(gè)思路,那么有以下幾方面需要改進(jìn):
- 語料大小及豐富程度;
- 停用詞的擴(kuò)充;
- 更好的算法。
??筆者的這篇文章僅作為詞義消岐的簡(jiǎn)介以及簡(jiǎn)單實(shí)現(xiàn),希望能對(duì)讀者有所啟發(fā)~
注意:本人現(xiàn)已開通微信公眾號(hào): Python爬蟲與算法(微信號(hào)為:easy_web_scrape), 歡迎大家關(guān)注哦~~