- 深度學(xué)習(xí)進(jìn)階:自然語(yǔ)言處理
- (日)齋藤康毅
- 4723字
- 2021-02-07 09:25:58
2.3 基于計(jì)數(shù)的方法
從介紹基于計(jì)數(shù)的方法開(kāi)始,我們將使用語(yǔ)料庫(kù)(corpus)。簡(jiǎn)而言之,語(yǔ)料庫(kù)就是大量的文本數(shù)據(jù)。不過(guò),語(yǔ)料庫(kù)并不是胡亂收集數(shù)據(jù),一般收集的都是用于自然語(yǔ)言處理研究和應(yīng)用的文本數(shù)據(jù)。
說(shuō)到底,語(yǔ)料庫(kù)只是一些文本數(shù)據(jù)而已。不過(guò),其中的文章都是由人寫(xiě)出來(lái)的。換句話說(shuō),語(yǔ)料庫(kù)中包含了大量的關(guān)于自然語(yǔ)言的實(shí)踐知識(shí),即文章的寫(xiě)作方法、單詞的選擇方法和單詞含義等。基于計(jì)數(shù)的方法的目標(biāo)就是從這些富有實(shí)踐知識(shí)的語(yǔ)料庫(kù)中,自動(dòng)且高效地提取本質(zhì)。
自然語(yǔ)言處理領(lǐng)域中使用的語(yǔ)料庫(kù)有時(shí)會(huì)給文本數(shù)據(jù)添加額外的信息。比如,可以給文本數(shù)據(jù)的各個(gè)單詞標(biāo)記詞性。在這種情況下,為了方便計(jì)算機(jī)處理,語(yǔ)料庫(kù)通常會(huì)被結(jié)構(gòu)化(比如,采用樹(shù)結(jié)構(gòu)等數(shù)據(jù)形式)。這里,假定我們使用的語(yǔ)料庫(kù)沒(méi)有添加標(biāo)簽,而是作為一個(gè)大的文本文件,只包含簡(jiǎn)單的文本數(shù)據(jù)。
2.3.1 基于Python的語(yǔ)料庫(kù)的預(yù)處理
自然語(yǔ)言處理領(lǐng)域存在各種各樣的語(yǔ)料庫(kù)。說(shuō)到有名的語(yǔ)料庫(kù),有Wikipedia和Google News等。另外,莎士比亞、夏目漱石等偉大作家的作品集也會(huì)被用作語(yǔ)料庫(kù)。本章我們先使用僅包含一個(gè)句子的簡(jiǎn)單文本作為語(yǔ)料庫(kù),然后再處理更實(shí)用的語(yǔ)料庫(kù)。
現(xiàn)在,我們使用Python的交互模式,對(duì)一個(gè)非常小的文本數(shù)據(jù)(語(yǔ)料庫(kù))進(jìn)行預(yù)處理。這里所說(shuō)的預(yù)處理是指,將文本分割為單詞(分詞),并將分割后的單詞列表轉(zhuǎn)化為單詞ID列表。
下面,我們一邊確認(rèn)一邊實(shí)現(xiàn)。首先來(lái)看一下作為語(yǔ)料庫(kù)的樣本文章。
>>> text = 'You say goodbye and I say hello.'
這里我們使用由單個(gè)句子構(gòu)成的文本作為語(yǔ)料庫(kù)。本來(lái)文本(text)應(yīng)該包含成千上萬(wàn)個(gè)(連續(xù)的)句子,但是,考慮到簡(jiǎn)潔性,這里先對(duì)這個(gè)小的文本數(shù)據(jù)進(jìn)行預(yù)處理。下面,我們對(duì)上面的text進(jìn)行分詞。
>>> text = text.lower() >>> text = text.replace('.' , ' .') >>> text 'you say goodbye and i say hello .' >>> words = text.split(' ') >>> words ['you', 'say', 'goodbye', 'and', 'i', 'say', 'hello', '.']
首先,使用lower()方法將所有字母轉(zhuǎn)化為小寫(xiě),這樣可以將句子開(kāi)頭的單詞也作為常規(guī)單詞處理。然后,將空格作為分隔符,通過(guò)split(' ')切分句子。考慮到句子結(jié)尾處的句號(hào)(.),我們先在句號(hào)前插入一個(gè)空格(即用“ .”替換“.”),再進(jìn)行分詞。
這里,在進(jìn)行分詞時(shí),我們采用了一種在句號(hào)前插入空格的“臨時(shí)對(duì)策”,其實(shí)還有更加聰明、更加通用的實(shí)現(xiàn)方式,比如使用正則表達(dá)式。通過(guò)導(dǎo)入正則表達(dá)式的re模塊,使用re.split('(\W+)?', text)也可以進(jìn)行分詞。關(guān)于正則表達(dá)式的詳細(xì)信息,可以參考文獻(xiàn)[15]。
現(xiàn)在,我們已經(jīng)可以將原始文章作為單詞列表使用了。雖然分詞后文本更容易處理了,但是直接以文本的形式操作單詞,總感覺(jué)有些不方便。因此,我們進(jìn)一步給單詞標(biāo)上ID,以便使用單詞ID列表。為此,我們使用Python的字典來(lái)創(chuàng)建單詞ID和單詞的對(duì)應(yīng)表。
>>> word to id = {} >>> id to word = {} >>> >>> for word in words : ... if word not in word to id: ... new id = len(word to id) ... word to id[word] = new id ... id to word[new id] = word
變量id_to_word負(fù)責(zé)將單詞ID轉(zhuǎn)化為單詞(鍵是單詞ID,值是單詞), word_to_id負(fù)責(zé)將單詞轉(zhuǎn)化為單詞ID。這里,我們從頭開(kāi)始逐一觀察分詞后的words的各個(gè)元素,如果單詞不在word_to_id中,則分別向word_to_id和id_to_word添加新ID和單詞。另外,我們將字典的長(zhǎng)度設(shè)為新的單詞ID,單詞ID按0, 1, 2,···逐漸增加。
這樣一來(lái),我們就創(chuàng)建好了單詞ID和單詞的對(duì)應(yīng)表。下面,我們來(lái)實(shí)際看一下它們的內(nèi)容。
>>> id to word {0: 'you', 1: 'say', 2: 'goodbye', 3: 'and', 4: 'i', 5: 'hello', 6:'.'} >>> word to id {'you': 0, 'say': 1, 'goodbye': 2, 'and': 3, 'i': 4, 'hello': 5, '.': 6}
使用這些詞典,可以根據(jù)單詞檢索單詞ID,或者反過(guò)來(lái)根據(jù)單詞ID檢索單詞。我們實(shí)際嘗試一下,如下所示。
>>> id to word[1] 'say' >>> word to id['hello'] 5
最后,我們將單詞列表轉(zhuǎn)化為單詞ID列表。這里,我們使用Python的列表解析式將單詞列表轉(zhuǎn)化為單詞ID列表,然后再將其轉(zhuǎn)化為NumPy數(shù)組。
>>> import numpy as np >>> corpus = [word to id[w] for w in words] >>> corpus = np.array(corpus) >>> corpus array([0, 1, 2, 3, 4, 1, 5, 6])
列表解析式(list comprehension)或字典解析式(dict comprehension)是一種便于對(duì)列表或字典進(jìn)行循環(huán)處理的寫(xiě)法。比如,要?jiǎng)?chuàng)建元素為列表xs = [1,2,3,4]中各個(gè)元素的平方的新列表,可以寫(xiě)成 [x**2 for x in xs]。
至此,我們就完成了利用語(yǔ)料庫(kù)的準(zhǔn)備工作。現(xiàn)在,我們將上述一系列處理實(shí)現(xiàn)為preprocess()函數(shù)( common/util.py)。
def preprocess(text): text = text.lower() text = text.replace('.', ' .') words = text.split(' ') word_to_id = {} id_to_word = {} for word in words: if word not in word_to_id: new_id = len(word_to_id) word_to_id[word] = new_id id_to_word[new_id] = word corpus = np.array([word_to_id[w] for w in words]) return corpus, word_to_id, id_to_word
使用這個(gè)函數(shù),可以按如下方式對(duì)語(yǔ)料庫(kù)進(jìn)行預(yù)處理。
>>> text = 'You say goodbye and I say hello.' >>> corpus , word to id , id to word = preprocess(text)
到這里,語(yǔ)料庫(kù)的預(yù)處理就結(jié)束了。這里準(zhǔn)備的corpus、word_to_id和id_to_word這3個(gè)變量名在本書(shū)接下來(lái)的很多地方都會(huì)用到。corpus是單詞ID列表,word_to_id是單詞到單詞ID的字典,id_to_word是單詞ID到單詞的字典。
現(xiàn)在,我們已經(jīng)做好了操作語(yǔ)料庫(kù)的準(zhǔn)備,接下來(lái)的目標(biāo)就是使用語(yǔ)料庫(kù)提取單詞含義。為此,本節(jié)我們將考察基于計(jì)數(shù)的方法。采用這種方法,我們能夠?qū)卧~表示為向量。
2.3.2 單詞的分布式表示
世界上存在各種各樣的顏色,有的顏色被賦予了固定的名字,比如鈷藍(lán)(cobalt blue)或者鋅紅(zinc red);顏色也可以通過(guò)RGB(Red/Green/Blue)三原色分別存在多少來(lái)表示。前者為不同的顏色賦予不同的名字,有多少種顏色,就需要有多少個(gè)不同的名字;后者則將顏色表示為三維向量。
需要注意的是,使用RGB這樣的向量表示可以更準(zhǔn)確地指定顏色,并且這種基于三原色的表示方式很緊湊,也更容易讓人想象到具體是什么顏色。比如,即便不知道“深緋”是什么樣的顏色,但如果知道它的(R, G, B)=(201, 23, 30),就至少可以知道它是紅色系的顏色。此外,顏色之間的關(guān)聯(lián)性(是否是相似的顏色)也更容易通過(guò)向量表示來(lái)判斷和量化。
那么,能不能將類(lèi)似于顏色的向量表示方法運(yùn)用到單詞上呢?更準(zhǔn)確地說(shuō),可否在單詞領(lǐng)域構(gòu)建緊湊合理的向量表示呢?接下來(lái),我們將關(guān)注能準(zhǔn)確把握單詞含義的向量表示。在自然語(yǔ)言處理領(lǐng)域,這稱(chēng)為分布式表示。
單詞的分布式表示將單詞表示為固定長(zhǎng)度的向量。這種向量的特征在于它是用密集向量表示的。密集向量的意思是,向量的各個(gè)元素(大多數(shù))是由非0實(shí)數(shù)表示的。例如,三維分布式表示是[0.21,-0.45,0.83]。如何構(gòu)建這樣的單詞的分布式表示是我們接下來(lái)的一個(gè)重要課題。
2.3.3 分布式假設(shè)
在自然語(yǔ)言處理的歷史中,用向量表示單詞的研究有很多。如果仔細(xì)看一下這些研究,就會(huì)發(fā)現(xiàn)幾乎所有的重要方法都基于一個(gè)簡(jiǎn)單的想法,這個(gè)想法就是“某個(gè)單詞的含義由它周?chē)膯卧~形成”,稱(chēng)為分布式假設(shè)(distributional hypothesis)。許多用向量表示單詞的近期研究也基于該假設(shè)。
分布式假設(shè)所表達(dá)的理念非常簡(jiǎn)單。單詞本身沒(méi)有含義,單詞含義由它所在的上下文(語(yǔ)境)形成。的確,含義相同的單詞經(jīng)常出現(xiàn)在相同的語(yǔ)境中。比如“I drink beer.”“We drink wine.”,drink的附近常有飲料出現(xiàn)。另外,從“I guzzle beer.”“We guzzle wine.”可知,guzzle和drink所在的語(yǔ)境相似。進(jìn)而我們可以推測(cè)出,guzzle和drink是近義詞(順便說(shuō)一下,guzzle是“大口喝”的意思)。
從現(xiàn)在開(kāi)始,我們會(huì)經(jīng)常使用“上下文”一詞。本章說(shuō)的上下文是指某個(gè)單詞(關(guān)注詞)周?chē)膯卧~。在圖2-3的例子中,左側(cè)和右側(cè)的2個(gè)單詞就是上下文。

圖2-3 窗口大小為2的上下文例子。在關(guān)注goodbye時(shí),將其左右各2個(gè)單詞用作上下文
如圖2-3所示,上下文是指某個(gè)居中單詞的周?chē)~匯。這里,我們將上下文的大小(即周?chē)膯卧~有多少個(gè))稱(chēng)為窗口大小(window size)。窗口大小為1,上下文包含左右各1個(gè)單詞;窗口大小為2,上下文包含左右各2個(gè)單詞,以此類(lèi)推。
這里,我們將左右兩邊相同數(shù)量的單詞作為上下文。但是,根據(jù)具體情況,也可以?xún)H將左邊的單詞或者右邊的單詞作為上下文。此外,也可以使用考慮了句子分隔符的上下文。簡(jiǎn)單起見(jiàn),本書(shū)僅處理不考慮句子分隔符、左右單詞數(shù)量相同的上下文。
2.3.4 共現(xiàn)矩陣
下面,我們來(lái)考慮如何基于分布式假設(shè)使用向量表示單詞,最直截了當(dāng)?shù)膶?shí)現(xiàn)方法是對(duì)周?chē)鷨卧~的數(shù)量進(jìn)行計(jì)數(shù)。具體來(lái)說(shuō),在關(guān)注某個(gè)單詞的情況下,對(duì)它的周?chē)霈F(xiàn)了多少次什么單詞進(jìn)行計(jì)數(shù),然后再匯總。這里,我們將這種做法稱(chēng)為“基于計(jì)數(shù)的方法”,在有的文獻(xiàn)中也稱(chēng)為“基于統(tǒng)計(jì)的方法”。
現(xiàn)在,我們就來(lái)看一下基于計(jì)數(shù)的方法。這里我們使用2.3.1節(jié)的語(yǔ)料庫(kù)和preprocess()函數(shù),再次進(jìn)行預(yù)處理。
import sys sys.path.append('..') import numpy as np from common.util import preprocess text = 'You say goodbye and I say hello.' corpus, word_to_id, id_to_word = preprocess(text) print (corpus) # [0 1 2 3 4 1 5 6] print (id_to_word) # {0: 'you', 1: 'say', 2: 'goodbye', 3: 'and', 4: 'i', 5: 'hello', 6: ? '.'}
從上面的結(jié)果可以看出,詞匯總數(shù)為7個(gè)。下面,我們計(jì)算每個(gè)單詞的上下文所包含的單詞的頻數(shù)。在這個(gè)例子中,我們將窗口大小設(shè)為1,從單詞ID為0的you開(kāi)始。
從圖2-4可以清楚地看到,單詞you的上下文僅有say這個(gè)單詞。用表格表示的話,如圖2-5所示。

圖2-4 單詞you的上下文

圖2-5 用表格表示單詞you的上下文中包含的單詞的頻數(shù)
圖2-5表示的是作為單詞you的上下文共現(xiàn)的單詞的頻數(shù)。同時(shí),這也意味著可以用向量[0, 1, 0, 0, 0, 0, 0]表示單詞you。
接著對(duì)單詞ID為1的say進(jìn)行同樣的處理,結(jié)果如圖2-6所示。

圖2-6 用表格表示單詞say的上下文中包含的單詞的頻數(shù)
從上面的結(jié)果可知,單詞say可以表示為向量[1, 0, 1, 0, 1, 1, 0]。對(duì)所有的7個(gè)單詞進(jìn)行上述操作,會(huì)得到如圖2-7所示的結(jié)果。

圖2-7 用表格匯總各個(gè)單詞的上下文中包含的單詞的頻數(shù)
圖2-7是匯總了所有單詞的共現(xiàn)單詞的表格。這個(gè)表格的各行對(duì)應(yīng)相應(yīng)單詞的向量。因?yàn)閳D2-7的表格呈矩陣狀,所以稱(chēng)為共現(xiàn)矩陣(co-occurence matrix)。
接下來(lái),我們來(lái)實(shí)際創(chuàng)建一下上面的共現(xiàn)矩陣。這里,將圖2-7的結(jié)果按原樣手動(dòng)輸入。
C = np.array([ [0, 1, 0, 0, 0, 0, 0], [1, 0, 1, 0, 1, 1, 0], [0, 1, 0, 1, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0], [0, 1, 0, 1, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 1, 0], ], dtype=np.int32)
這就是共現(xiàn)矩陣。使用這個(gè)共現(xiàn)矩陣,可以獲得各個(gè)單詞的向量,如下所示。
print (C[0]) # 單詞ID為0的向量 # [0 1 0 0 0 0 0] print (C[4]) # 單詞ID為4的向量 # [0 1 0 1 0 0 0] print (C[word_to_id['goodbye']]) # goodbye的向量 # [0 1 0 1 0 0 0]
至此,我們通過(guò)共現(xiàn)矩陣成功地用向量表示了單詞。上面我們是手動(dòng)輸入共現(xiàn)矩陣的,但這一操作顯然可以自動(dòng)化。下面,我們來(lái)實(shí)現(xiàn)一個(gè)能直接從語(yǔ)料庫(kù)生成共現(xiàn)矩陣的函數(shù)。我們把這個(gè)函數(shù)稱(chēng)為create_co_matrix(corpus, vocab_size, window_size=1),其中參數(shù)corpus是單詞ID列表,參數(shù)vocab_size是詞匯個(gè)數(shù),window_size是窗口大小(common/util.py)。
def create_co_matrix(corpus, vocab_size, window_size=1): corpus_size = len(corpus) co_matrix = np.zeros((vocab_size, vocab_size), dtype=np.int32) for idx, word_id in enumerate(corpus): for i in range(1, window_size + 1): left_idx = idx - i right_idx = idx + i if left_idx >= 0: left_word_id = corpus[left_idx] co_matrix[word_id, left_word_id] += 1 if right_idx < corpus_size: right_word_id = corpus[right_idx] co_matrix[word_id, right_word_id] += 1 return co_matrix
首先,用元素為0的二維數(shù)組對(duì)co_matrix進(jìn)行初始化。然后,針對(duì)語(yǔ)料庫(kù)中的每一個(gè)單詞,計(jì)算它的窗口中包含的單詞。同時(shí),檢查窗口內(nèi)的單詞是否超出了語(yǔ)料庫(kù)的左端和右端。
這樣一來(lái),無(wú)論語(yǔ)料庫(kù)多大,都可以自動(dòng)生成共現(xiàn)矩陣。之后,我們都將使用這個(gè)函數(shù)生成共現(xiàn)矩陣。
2.3.5 向量間的相似度
前面我們通過(guò)共現(xiàn)矩陣將單詞表示為了向量。下面,我們看一下如何測(cè)量向量間的相似度。
測(cè)量向量間的相似度有很多方法,其中具有代表性的方法有向量?jī)?nèi)積或歐式距離等。雖然除此之外還有很多方法,但是在測(cè)量單詞的向量表示的相似度方面,余弦相似度(cosine similarity)是很常用的。設(shè)有x=(x1, x2, x3,···, xn)和y=(y1, y2, y3,···, yn)兩個(gè)向量,它們之間的余弦相似度的定義如下式所示。

在式(2.1)中,分子是向量?jī)?nèi)積,分母是各個(gè)向量的范數(shù)。范數(shù)表示向量的大小,這里計(jì)算的是L2范數(shù)(即向量各個(gè)元素的平方和的平方根)。式(2.1)的要點(diǎn)是先對(duì)向量進(jìn)行正規(guī)化,再求它們的內(nèi)積。
余弦相似度直觀地表示了“兩個(gè)向量在多大程度上指向同一方向”。兩個(gè)向量完全指向相同的方向時(shí),余弦相似度為1;完全指向相反的方向時(shí),余弦相似度為-1。
現(xiàn)在,我們來(lái)實(shí)現(xiàn)余弦相似度。基于式(2.1),代碼如下所示。
def cos_similarity(x, y): nx = x / np.sqrt(np.sum(x**2)) # x的正規(guī)化 ny = y / np.sqrt(np.sum(y**2)) # y的正規(guī)化 return np.dot(nx, ny)
這里,我們假定參數(shù)x和y是NumPy數(shù)組。首先對(duì)向量進(jìn)行正規(guī)化,然后求兩個(gè)向量的內(nèi)積。這里余弦相似度的實(shí)現(xiàn)雖然完成了,但是還有一個(gè)問(wèn)題。那就是當(dāng)零向量(元素全部為0的向量)被賦值給參數(shù)時(shí),會(huì)出現(xiàn)“除數(shù)為0”(zero division)的錯(cuò)誤。
解決此類(lèi)問(wèn)題的一個(gè)常用方法是,在執(zhí)行除法時(shí)加上一個(gè)微小值。這里,通過(guò)參數(shù)指定一個(gè)微小值eps(eps是epsilon的縮寫(xiě)),并默認(rèn)eps=1e-8(=0.00000001)。這樣修改后的余弦相似度的實(shí)現(xiàn)如下所示(common/util.py)。
def cos_similarity(x, y, eps=1e-8): nx = x / (np.sqrt(np.sum(x ** 2)) + eps) ny = y / (np.sqrt(np.sum(y ** 2)) + eps) return np.dot(nx, ny)
這里我們用了1e-8作為微小值,在這么小的值的情況下,根據(jù)浮點(diǎn)數(shù)的舍入誤差,這個(gè)微小值會(huì)被其他值“吸收”掉。在上面的實(shí)現(xiàn)中,因?yàn)檫@個(gè)微小值會(huì)被向量的范數(shù)“吸收”掉,所以在絕大多數(shù)情況下,加上eps不會(huì)對(duì)最終的計(jì)算結(jié)果造成影響。而當(dāng)向量的范數(shù)為0時(shí),這個(gè)微小值可以防止“除數(shù)為0”的錯(cuò)誤。
利用這個(gè)函數(shù),可以如下求得單詞向量間的相似度。這里,我們嘗試求you和i(=I)的相似度(ch02/similarity.py)。
import sys sys.path.append('..') from common.util import preprocess, create_co_matrix, cos_similarity text = 'You say goodbye and I say hello.' corpus, word_to_id, id_to_word = preprocess(text) vocab_size = len(word_to_id) C = create_co_matrix(corpus, vocab_size) c0 = C[word_to_id['you']] # you的單詞向量 c1 = C[word_to_id['i']] # i的單詞向量 print (cos_similarity(c0, c1)) # 0.7071067691154799
從上面的結(jié)果可知,you和i的余弦相似度是0.70...。由于余弦相似度的取值范圍是-1到1,所以可以說(shuō)這個(gè)值是相對(duì)比較高的(存在相似性)。
2.3.6 相似單詞的排序
余弦相似度已經(jīng)實(shí)現(xiàn)好了,使用這個(gè)函數(shù),我們可以實(shí)現(xiàn)另一個(gè)便利的函數(shù):當(dāng)某個(gè)單詞被作為查詢(xún)?cè)~時(shí),將與這個(gè)查詢(xún)?cè)~相似的單詞按降序顯示出來(lái)。這里將這個(gè)函數(shù)稱(chēng)為most_similar(),通過(guò)下列參數(shù)進(jìn)行實(shí)現(xiàn)(表2-1)。
most_similar(query, word_to_id, id_to_word, word_matrix, top=5)
表2-1 most_similar()函數(shù)的參數(shù)

這里我們直接給出most_similar()函數(shù)的實(shí)現(xiàn),如下所示(common/util.py)。
def most_similar(query, word_to_id, id_to_word, word_matrix, top=5): # ?取出查詢(xún)?cè)~ if query not in word_to_id: print ('%s is not found' % query) return print ('\n[query] ' + query) query_id = word_to_id[query] query_vec = word_matrix[query_id] # ?計(jì)算余弦相似度 vocab_size = len(id_to_word) similarity = np.zeros(vocab_size) for i in range(vocab_size): similarity[i] = cos_similarity(word_matrix[i], query_vec) # ?基于余弦相似度,按降序輸出值 count = 0 for i in (-1 * similarity).argsort(): if id_to_word[i] == query: continue print (' %s: %s' % (id_to_word[i], similarity[i])) count += 1 if count >= top: return
上述實(shí)現(xiàn)按如下順序執(zhí)行。
?取出查詢(xún)?cè)~的單詞向量。
?分別求得查詢(xún)?cè)~的單詞向量和其他所有單詞向量的余弦相似度。
?基于余弦相似度的結(jié)果,按降序顯示它們的值。
我們僅對(duì)步驟?進(jìn)行補(bǔ)充說(shuō)明。在步驟?中,將similarity數(shù)組中的元素索引按降序重新排列,并輸出頂部的單詞。這里使用argsort()方法對(duì)數(shù)組的索引進(jìn)行了重排。這個(gè)argsort()方法可以按升序?qū)umPy數(shù)組的元素進(jìn)行排序(不過(guò),返回值是數(shù)組的索引)。下面是一個(gè)例子。
>>> x = np.array([100 , -20 , 2]) >>> x.argsort() array([1, 2, 0])
上述代碼對(duì)NumPy數(shù)組[100,-20, 2]的各個(gè)元素按升序進(jìn)行了排列。此時(shí),返回的數(shù)組的各個(gè)元素對(duì)應(yīng)原數(shù)組的索引。上述結(jié)果的順序是“第1個(gè)元素(-20)”“第2個(gè)元素(2)”“第0個(gè)元素(100)”。現(xiàn)在我們想做的是將單詞的相似度按降序排列,因此,將NumPy數(shù)組的各個(gè)元素乘以-1后,再使用argsort()方法。接著上面的例子,有如下代碼。
>>> (-x).argsort()
array([0, 2, 1])
使用這個(gè)argsort(),可以按降序輸出單詞相似度。以上就是most_similar()函數(shù)的實(shí)現(xiàn),下面我們來(lái)試著使用一下。這里將you作為查詢(xún)?cè)~,顯示與其相似的單詞,代碼如下所示(ch02/most_similar.py)。
import sys
sys.path.append('..')
from common.util import preprocess, create_co_matrix, most_similar
text = 'You say goodbye and I say hello.'
corpus, word_to_id, id_to_word = preprocess(text)
vocab_size = len(word_to_id)
C = create_co_matrix(corpus, vocab_size)
most_similar('you', word_to_id, id_to_word, C, top=5)
執(zhí)行代碼后,會(huì)得到如下結(jié)果。
[query] you goodbye: 0.7071067691154799 i: 0.7071067691154799 hello: 0.7071067691154799 say: 0.0 and: 0.0
這個(gè)結(jié)果只按降序顯示了you這個(gè)查詢(xún)?cè)~的前5個(gè)相似單詞,各個(gè)單詞旁邊的值是余弦相似度。觀察上面的結(jié)果可知,和you最接近的單詞有3個(gè),分別是goodbye、i(=I)和hello。因?yàn)閕和you都是人稱(chēng)代詞,所以二者相似可以理解。但是,goodbye和hello的余弦相似度也很高,這和我們的感覺(jué)存在很大的差異。一個(gè)可能的原因是,這里的語(yǔ)料庫(kù)太小了。后面我們會(huì)用更大的語(yǔ)料庫(kù)進(jìn)行相同的實(shí)驗(yàn)。
如上所述,我們通過(guò)共現(xiàn)矩陣成功地將單詞表示為了向量。至此,基于計(jì)數(shù)的方法的基本內(nèi)容就介紹完了。之所以說(shuō)“基本”,是因?yàn)檫€有許多事情需要討論。下一節(jié),我們將說(shuō)明當(dāng)前方法的改進(jìn)思路,并實(shí)現(xiàn)這個(gè)改進(jìn)思路。
- DeepSeek算力革命簡(jiǎn)史
- 解構(gòu)ChatGPT
- 智能制造時(shí)代的研發(fā)智慧:知識(shí)工程2.0
- 新一代人工智能:無(wú)代碼人工智能開(kāi)發(fā)平臺(tái)實(shí)踐
- DeepSeek實(shí)戰(zhàn):操作攻略與商業(yè)應(yīng)用
- GPT圖解:大模型是怎樣構(gòu)建的
- 洞見(jiàn)未來(lái)的“元宇宙”世界(套裝8冊(cè))
- Chatbot從0到1(第2版):對(duì)話式交互實(shí)踐指南
- 樹(shù)莓派創(chuàng)客:手把手教你搭建機(jī)器人
- 機(jī)器學(xué)習(xí)中的數(shù)學(xué)修煉
- 通用人工智能:初心與未來(lái)
- 被人工智能操控的金融業(yè)
- 人工智能編程實(shí)踐:Python編程5級(jí)
- 新機(jī)器智能
- 人工智能數(shù)據(jù)處理