第6課:面向非結(jié)構(gòu)化數(shù)據(jù)轉(zhuǎn)換的詞袋和詞向量模型

通過(guò)前面幾個(gè)小節(jié)的學(xué)習(xí),我們現(xiàn)在已經(jīng)學(xué)會(huì)了如何獲取文本預(yù)料,然后分詞,在分詞之后的結(jié)果上,我們可以提取文本的關(guān)鍵詞查看文本核心思想,進(jìn)而可以通過(guò)可視化技術(shù)把文檔從視覺(jué)的角度表達(dá)出來(lái)。

下面,我們來(lái)看看,文本數(shù)據(jù)如何轉(zhuǎn)換成計(jì)算機(jī)能夠計(jì)算的數(shù)據(jù)。這里介紹兩種常用的模型:詞袋和詞向量模型。

詞袋模型(Bag of Words Model)

詞袋模型的概念

先來(lái)看張圖,從視覺(jué)上感受一下詞袋模型的樣子。

enter image description here

詞袋模型看起來(lái)好像一個(gè)口袋把所有詞都裝進(jìn)去,但卻不完全如此。在自然語(yǔ)言處理和信息檢索中作為一種簡(jiǎn)單假設(shè),詞袋模型把文本(段落或者文檔)被看作是無(wú)序的詞匯集合,忽略語(yǔ)法甚至是單詞的順序,把每一個(gè)單詞都進(jìn)行統(tǒng)計(jì),同時(shí)計(jì)算每個(gè)單詞出現(xiàn)的次數(shù),常常被用在文本分類中,如貝葉斯算法、LDA 和 LSA 等。

動(dòng)手實(shí)戰(zhàn)詞袋模型

(1)詞袋模型

本例中,我們自己動(dòng)手寫代碼看看詞袋模型是如何操作的。

首先,引入 jieba 分詞器、語(yǔ)料和停用詞(標(biāo)點(diǎn)符號(hào)集合,自己可以手動(dòng)添加或者用一個(gè)文本字典代替)。

    import jieba
    #定義停用詞、標(biāo)點(diǎn)符號(hào)
    punctuation = [",","。", ":", ";", "?"]
    #定義語(yǔ)料
    content = ["機(jī)器學(xué)習(xí)帶動(dòng)人工智能飛速的發(fā)展。",
               "深度學(xué)習(xí)帶動(dòng)人工智能飛速的發(fā)展。",
               "機(jī)器學(xué)習(xí)和深度學(xué)習(xí)帶動(dòng)人工智能飛速的發(fā)展。"
              ]

接下來(lái),我們先對(duì)語(yǔ)料進(jìn)行分詞操作,這里用到 lcut() 方法:

    #分詞
    segs_1 = [jieba.lcut(con) for con in content]
    print(segs_1)

得到分詞后的結(jié)果如下:

[['機(jī)器', '學(xué)習(xí)', '帶動(dòng)', '人工智能', '飛速', '的', '發(fā)展', '。'], ['深度', '學(xué)習(xí)', '帶動(dòng)', '人工智能', '飛速', '的', '發(fā)展', '。'], ['機(jī)器', '學(xué)習(xí)', '和', '深度', '學(xué)習(xí)', '帶動(dòng)', '人工智能', '飛速', '的', '發(fā)展', '。']]

因?yàn)橹形恼Z(yǔ)料帶有停用詞和標(biāo)點(diǎn)符號(hào),所以需要去停用詞和標(biāo)點(diǎn)符號(hào),這里語(yǔ)料很小,我們直接去標(biāo)點(diǎn)符號(hào):

    tokenized = []
    for sentence in segs_1:
        words = []
        for word in sentence:
            if word not in punctuation:          
                words.append(word)
        tokenized.append(words)
    print(tokenized)

去標(biāo)點(diǎn)符號(hào)后,我們得到結(jié)果如下:

[['機(jī)器', '學(xué)習(xí)', '帶動(dòng)', '人工智能', '飛速', '的', '發(fā)展'], ['深度', '學(xué)習(xí)', '帶動(dòng)', '人工智能', '飛速', '的', '發(fā)展'], ['機(jī)器', '學(xué)習(xí)', '和', '深度', '學(xué)習(xí)', '帶動(dòng)', '人工智能', '飛速', '的', '發(fā)展']]

下面操作就是把所有的分詞結(jié)果放到一個(gè)袋子(List)里面,也就是取并集,再去重,獲取對(duì)應(yīng)的特征詞。

    #求并集
    bag_of_words = [ x for item in segs_1 for x in item if x not in punctuation]
    #去重
    bag_of_words = list(set(bag_of_words))
    print(bag_of_words)

得到的特征詞結(jié)果如下:

['飛速', '的', '深度', '人工智能', '發(fā)展', '和', '機(jī)器', '學(xué)習(xí)', '帶動(dòng)']

我們以上面特征詞的順序,完成詞袋化:

    bag_of_word2vec = []
    for sentence in tokenized:
        tokens = [1 if token in sentence else 0 for token in bag_of_words ]
        bag_of_word2vec.append(tokens)

最后得到詞袋向量:

[[1, 1, 0, 1, 1, 0, 1, 1, 1], [1, 1, 1, 1, 1, 0, 0, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1]]

上面的例子在編碼時(shí),對(duì)于 for 循環(huán)多次直接用到列表推導(dǎo)式。在 Python 中,列表推導(dǎo)式的效率比 for 快很多,尤其在數(shù)據(jù)量大的時(shí)候效果更明顯,建議多使用列表推導(dǎo)式。

(2)Gensim 構(gòu)建詞袋模型

下面我們介紹 Gensim 庫(kù)的使用,繼續(xù)沿用上面的例子:

    from gensim import corpora
    import gensim
    #tokenized是去標(biāo)點(diǎn)之后的
    dictionary = corpora.Dictionary(tokenized)
    #保存詞典
    dictionary.save('deerwester.dict') 
    print(dictionary)

這時(shí)我們得到的結(jié)果不全,但通過(guò)提示信息可知道共9個(gè)獨(dú)立的詞:

Dictionary(9 unique tokens: ['人工智能', '發(fā)展', '學(xué)習(xí)', '帶動(dòng)', '機(jī)器']...)

那我們?nèi)绾尾榭此性~呢?通過(guò)下面方法,可以查看到所有詞和對(duì)應(yīng)的下標(biāo):

    #查看詞典和下標(biāo) id 的映射
    print(dictionary.token2id)

最后結(jié)果如下:

{'人工智能': 0, '發(fā)展': 1, '學(xué)習(xí)': 2, '帶動(dòng)': 3, '機(jī)器': 4, '的': 5, '飛速': 6, '深度': 7, '和': 8}

根據(jù)得到的結(jié)果,我們同樣可以得到詞袋模型的特征向量。這里順帶提一下函數(shù) doc2bow(),作用只是計(jì)算每個(gè)不同單詞的出現(xiàn)次數(shù),將單詞轉(zhuǎn)換為其整數(shù)單詞 id 并將結(jié)果作為稀疏向量返回。

corpus = [dictionary.doc2bow(sentence) for sentence in segs_1]
    print(corpus )

得到的稀疏向量結(jié)果如下:

[[(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (6, 1)], [(0, 1), (1, 1), (2, 1), (3, 1), (5, 1), (6, 1), (7, 1)], [(0, 1), (1, 1), (2, 2), (3, 1), (4, 1), (5, 1), (6, 1), (7, 1), (8, 1)]]

詞向量 (Word Embedding)

深度學(xué)習(xí)帶給自然語(yǔ)言處理最令人興奮的突破是詞向量(Word Embedding)技術(shù)。詞向量技術(shù)是將詞語(yǔ)轉(zhuǎn)化成為稠密向量。在自然語(yǔ)言處理應(yīng)用中,詞向量作為機(jī)器學(xué)習(xí)、深度學(xué)習(xí)模型的特征進(jìn)行輸入。因此,最終模型的效果很大程度上取決于詞向量的效果。

詞向量的概念

在 Word2Vec 出現(xiàn)之前,自然語(yǔ)言處理經(jīng)常把字詞進(jìn)行獨(dú)熱編碼,也就是 One-Hot Encoder。

大數(shù)據(jù) [0,0,0,0,0,0,0,1,0,……,0,0,0,0,0,0,0]

云計(jì)算[0,0,0,0,1,0,0,0,0,……,0,0,0,0,0,0,0]

機(jī)器學(xué)習(xí)[0,0,0,1,0,0,0,0,0,……,0,0,0,0,0,0,0]

人工智能[0,0,0,0,0,0,0,0,0,……,1,0,0,0,0,0,0]

比如上面的例子中,大數(shù)據(jù) 、云計(jì)算、機(jī)器學(xué)習(xí)和人工智能各對(duì)應(yīng)一個(gè)向量,向量中只有一個(gè)值為1,其余都為0。所以使用 One-Hot Encoder有以下問(wèn)題:

  • 第一,詞語(yǔ)編碼是隨機(jī)的,向量之間相互獨(dú)立,看不出詞語(yǔ)之間可能存在的關(guān)聯(lián)關(guān)系。
  • 第二,向量維度的大小取決于語(yǔ)料庫(kù)中詞語(yǔ)的多少,如果語(yǔ)料包含的所有詞語(yǔ)對(duì)應(yīng)的向量合為一個(gè)矩陣的話,那這個(gè)矩陣過(guò)于稀疏,并且會(huì)造成維度災(zāi)難。

而解決這個(gè)問(wèn)題的手段,就是使用向量表示(Vector Representations)。比如 Word2Vec 可以將 One-Hot Encoder 轉(zhuǎn)化為低維度的連續(xù)值,也就是稠密向量,并且其中意思相近的詞也將被映射到向量空間中相近的位置。經(jīng)過(guò)降維,在二維空間中,相似的單詞在空間中的距離也很接近。

這里簡(jiǎn)單給詞向量一個(gè)定義,詞向量就是要用某個(gè)固定維度的向量去表示單詞。也就是說(shuō)要把單詞變成固定維度的向量,作為機(jī)器學(xué)習(xí)(Machine Learning)或深度學(xué)習(xí)模型的特征向量輸入。

動(dòng)手實(shí)戰(zhàn)詞向量

(1)Word2Vec

Word2Vec 是 Google 團(tuán)隊(duì)2013年推出的,自提出后被廣泛應(yīng)用在自然語(yǔ)言處理任務(wù)中,并且受到它的啟發(fā),后續(xù)出現(xiàn)了更多形式的詞向量模型。Word2Vec 主要包含兩種模型:Skip-Gram 和 CBOW,值得一提的是,Word2Vec 詞向量可以較好地表達(dá)不同詞之間的相似和類比關(guān)系。

下面我們通過(guò)代碼實(shí)戰(zhàn)來(lái)體驗(yàn)一下 Word2Vec。通過(guò) pip install gensim 安裝好庫(kù)后,即可導(dǎo)入使用。

enter image description here

先導(dǎo)入 Gensim 中的 Word2Vec 和 jieba 分詞器,再引入從百度百科抓取的黃河和長(zhǎng)江的語(yǔ)料:

    from gensim.models import Word2Vec  
    import jieba
    #定義停用詞、標(biāo)點(diǎn)符號(hào)
    punctuation = [",","。", ":", ";", ".", "'", '"', "’", "?", "/", "-", "+", "&", "(", ")"]
    sentences = [
    "長(zhǎng)江是中國(guó)第一大河,干流全長(zhǎng)6397公里(以沱沱河為源),一般稱6300公里。流域總面積一百八十余萬(wàn)平方公里,年平均入海水量約九千六百余億立方米。以干流長(zhǎng)度和入海水量論,長(zhǎng)江均居世界第三位。",
    "黃河,中國(guó)古代也稱河,發(fā)源于中華人民共和國(guó)青海省巴顏喀拉山脈,流經(jīng)青海、四川、甘肅、寧夏、內(nèi)蒙古、陜西、山西、河南、山東9個(gè)省區(qū),最后于山東省東營(yíng)墾利縣注入渤海。干流河道全長(zhǎng)5464千米,僅次于長(zhǎng)江,為中國(guó)第二長(zhǎng)河。黃河還是世界第五長(zhǎng)河。",
    "黃河,是中華民族的母親河。作為中華文明的發(fā)祥地,維系炎黃子孫的血脈.是中華民族民族精神與民族情感的象征。",
    "黃河被稱為中華文明的母親河。公元前2000多年華夏族在黃河領(lǐng)域的中原地區(qū)形成、繁衍。",
    "在蘭州的“黃河第一橋”內(nèi)蒙古托克托縣河口鎮(zhèn)以上的黃河河段為黃河上游。",
    "黃河上游根據(jù)河道特性的不同,又可分為河源段、峽谷段和沖積平原三部分。 ",
    "黃河,是中華民族的母親河。"
    ]

上面定義好語(yǔ)料,接下來(lái)進(jìn)行分詞,去標(biāo)點(diǎn)符號(hào)操作 :

    sentences = [jieba.lcut(sen) for sen in sentences]
    tokenized = []
    for sentence in sentences:
        words = []
        for word in sentence:
            if word not in punctuation:          
                words.append(word)
        tokenized.append(words)

這樣我們獲取的語(yǔ)料在分詞之后,去掉了標(biāo)點(diǎn)符號(hào),如果做得更嚴(yán)謹(jǐn),大家可以去停用詞,然后進(jìn)行模型訓(xùn)練:

    model = Word2Vec(tokenized, sg=1, size=100,  window=5,  min_count=2,  negative=1, sample=0.001, hs=1, workers=4)

參數(shù)解釋如下:

  • sg=1 是 skip-gram 算法,對(duì)低頻詞敏感;默認(rèn) sg=0 為 CBOW 算法。
  • size 是輸出詞向量的維數(shù),值太小會(huì)導(dǎo)致詞映射因?yàn)闆_突而影響結(jié)果,值太大則會(huì)耗內(nèi)存并使算法計(jì)算變慢,一般值取為100到200之間。
  • window 是句子中當(dāng)前詞與目標(biāo)詞之間的最大距離,3表示在目標(biāo)詞前看3-b 個(gè)詞,后面看 b 個(gè)詞(b 在0-3之間隨機(jī))。
  • min_count 是對(duì)詞進(jìn)行過(guò)濾,頻率小于 min-count 的單詞則會(huì)被忽視,默認(rèn)值為5。
  • negative 和 sample 可根據(jù)訓(xùn)練結(jié)果進(jìn)行微調(diào),sample 表示更高頻率的詞被隨機(jī)下采樣到所設(shè)置的閾值,默認(rèn)值為 1e-3。
  • hs=1 表示層級(jí) softmax 將會(huì)被使用,默認(rèn) hs=0 且 negative 不為0,則負(fù)采樣將會(huì)被選擇使用。
  • 詳細(xì)參數(shù)說(shuō)明可查看 Word2Vec 源代碼。

訓(xùn)練后的模型可以保存與加載,如下代碼所示:

    model.save('model')  #保存模型
    model = Word2Vec.load('model')   #加載模型

模型訓(xùn)練好之后,接下來(lái)就可以使用模型,可以用來(lái)計(jì)算句子或者詞的相似性、最大匹配程度等。

例如,我們判斷一下黃河和黃河自己的相似度:

    print(model.similarity('黃河', '黃河'))

結(jié)果輸出為:

1.0000000000000002

例如,當(dāng)輸入黃河和長(zhǎng)江來(lái)計(jì)算相似度的時(shí)候,結(jié)果就比較小,因?yàn)槲覀兊恼Z(yǔ)料實(shí)在太小了。

    print(model.similarity('黃河', '長(zhǎng)江'))

結(jié)果輸出為:

-0.036808977457324699

下面我們預(yù)測(cè)最接近的詞,預(yù)測(cè)與黃河和母親河最接近,而與長(zhǎng)江不接近的詞:

print(model.most_similar(positive=['黃河', '母親河'], negative=['長(zhǎng)江']))

得到結(jié)果如下,可以根據(jù)相似度大小找到與黃河和母親河最接近的詞(實(shí)際處理建議增大數(shù)據(jù)量和去停用詞)。

[('是', 0.14632007479667664), ('以', 0.14630728960037231), ('長(zhǎng)河', 0.13878652453422546), ('河道', 0.13716217875480652), ('在', 0.11577725410461426), ('全長(zhǎng)', 0.10969121754169464), ('內(nèi)蒙古', 0.07590540498495102), ('入海', 0.06970417499542236), ('民族', 0.06064444035291672), ('中華文明', 0.057667165994644165)]

上面通過(guò)小數(shù)據(jù)量的語(yǔ)料實(shí)戰(zhàn),加強(qiáng)了對(duì) Word2Vec 的理解,總之 Word2Vec 是一種將詞變成詞向量的工具。通俗點(diǎn)說(shuō),只有這樣文本預(yù)料才轉(zhuǎn)化為計(jì)算機(jī)能夠計(jì)算的矩陣向量。

(2)Doc2Vec

Doc2Vec 是 Mikolov 在 Word2Vec 基礎(chǔ)上提出的另一個(gè)用于計(jì)算長(zhǎng)文本向量的工具。在 Gensim 庫(kù)中,Doc2Vec 與 Word2Vec 都極為相似。但兩者在對(duì)輸入數(shù)據(jù)的預(yù)處理上稍有不同,Doc2vec 接收一個(gè)由 LabeledSentence 對(duì)象組成的迭代器作為其構(gòu)造函數(shù)的輸入?yún)?shù)。其中,LabeledSentence 是 Gensim 內(nèi)建的一個(gè)類,它接收兩個(gè) List 作為其初始化的參數(shù):word list 和 label list。

Doc2Vec 也包括兩種實(shí)現(xiàn)方式:DBOW(Distributed Bag of Words)和 DM (Distributed Memory)。DBOW 和 DM 的實(shí)現(xiàn),二者在 gensim 庫(kù)中的實(shí)現(xiàn)用的是同一個(gè)方法,該方法中參數(shù) dm = 0 或者 dm=1 決定調(diào)用 DBOW 還是 DM。Doc2Vec 將文檔語(yǔ)料通過(guò)一個(gè)固定長(zhǎng)度的向量表達(dá)。

下面是 Gensim 中 Doc2Vec 模型的實(shí)戰(zhàn),我們把上述語(yǔ)料每一句話當(dāng)做一個(gè)文本,添加上對(duì)應(yīng)的標(biāo)簽。接下來(lái),定義數(shù)據(jù)預(yù)處理類,作用是給每個(gè)文章添加對(duì)應(yīng)的標(biāo)簽:

    #定義數(shù)據(jù)預(yù)處理類,作用是給每個(gè)文章添加對(duì)應(yīng)的標(biāo)簽
    from gensim.models.doc2vec import Doc2Vec,LabeledSentence
    doc_labels = ["長(zhǎng)江","黃河","黃河","黃河","黃河","黃河","黃河"]
    class LabeledLineSentence(object):
        def __init__(self, doc_list, labels_list):
           self.labels_list = labels_list
           self.doc_list = doc_list
        def __iter__(self):
            for idx, doc in enumerate(self.doc_list):
                yield LabeledSentence(words=doc,tags=[self.labels_list[idx]])

        model = Doc2Vec(documents,dm=1, size=100, window=8, min_count=5, workers=4)
        model.save('model')
        model = Doc2Vec.load('model')  

上面定義好了數(shù)據(jù)預(yù)處理函數(shù),我們將 Word2Vec 中分詞去標(biāo)點(diǎn)后的數(shù)據(jù),進(jìn)行轉(zhuǎn)換:

    iter_data = LabeledLineSentence(tokenized, doc_labels)

得到一個(gè)數(shù)據(jù)集,我開(kāi)始定義模型參數(shù),這里 dm=1,采用了 Gensim 中的 DM 實(shí)現(xiàn)。

    model = Doc2Vec(dm=1, size=100, window=8, min_count=5, workers=4)
    model.build_vocab(iter_data)

接下來(lái)訓(xùn)練模型, 設(shè)置迭代次數(shù)1000次,start_alpha 為開(kāi)始學(xué)習(xí)率,end_alphastart_alpha 線性遞減。

    model.train(iter_data,total_examples=model.corpus_count,epochs=1000,start_alpha=0.01,end_alpha =0.001)

最后我們對(duì)模型進(jìn)行一些預(yù)測(cè):

    #根據(jù)標(biāo)簽找最相似的,這里只有黃河和長(zhǎng)江,所以結(jié)果為長(zhǎng)江,并計(jì)算出了相似度
    print(model.docvecs.most_similar('黃河'))

得到的結(jié)果:

[('長(zhǎng)江', 0.25543850660324097)]

然后對(duì)黃河和長(zhǎng)江標(biāo)簽做相似性計(jì)算:

print(model.docvecs.similarity('黃河','長(zhǎng)江'))

得到的結(jié)果:

0.25543848271351405

上面只是在小數(shù)據(jù)量進(jìn)行的小練習(xí),而最終影響模型準(zhǔn)確率的因素有:文檔的數(shù)量越多,文檔的相似性越好,也就是基于大數(shù)據(jù)量的模型訓(xùn)練。在工業(yè)界,Word2Vec 和 Doc2Vec 常見(jiàn)的應(yīng)用有:做相似詞計(jì)算;相關(guān)詞挖掘,在推薦系統(tǒng)中用在品牌、用戶、商品挖掘中;上下文預(yù)測(cè)句子;機(jī)器翻譯;作為特征輸入其他模型等。

總結(jié),本文只是簡(jiǎn)單的介紹了詞袋和詞向量模型的典型應(yīng)用,對(duì)于兩者的理論和其他詞向量模型,比如 TextRank 、FastText 和 GloVe 等,閱讀文末給出參考文獻(xiàn)將了解更多。

參考文獻(xiàn):

  1. https://radimrehurek.com/gensim/tut1.html
  2. https://radimrehurek.com/gensim/models/word2vec.html
  3. https://radimrehurek.com/gensim/summarization/summariser.html
  4. https://radimrehurek.com/gensim/models/fasttext.html
  5. https://nlp.stanford.edu/projects/glove/

如有侵權(quán)請(qǐng)聯(lián)系QQ:758230255刪除

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 通過(guò)前面幾個(gè)小節(jié)的學(xué)習(xí),我們現(xiàn)在已經(jīng)學(xué)會(huì)了如何獲取文本預(yù)料,然后分詞,在分詞之后的結(jié)果上,我們可以提取文本的關(guān)鍵詞...
    Element靜婷閱讀 1,074評(píng)論 0 1
  • 目前詞向量主要用的技術(shù) word2vec fasttext glove 1 one-host編碼 one-hot編...
    georgeguo閱讀 2,615評(píng)論 0 2
  • 自然語(yǔ)言處理中的輿情分析、情感分析有很多種方法,但是基于模型的方法對(duì)語(yǔ)料的質(zhì)量要求高,如果不能弄到高質(zhì)量的語(yǔ)料,很...
    wong11閱讀 15,436評(píng)論 4 18
  • 前面的文章主要從理論的角度介紹了自然語(yǔ)言人機(jī)對(duì)話系統(tǒng)所可能涉及到的多個(gè)領(lǐng)域的經(jīng)典模型和基礎(chǔ)知識(shí)。這篇文章,甚至之后...
    我偏笑_NSNirvana閱讀 14,453評(píng)論 2 64
  • 已經(jīng)不是第一次看這本書(shū),其實(shí)只是一本普普通通的言情小說(shuō),若說(shuō)非要加一個(gè)標(biāo)簽,也只不過(guò)是一本甜甜的文章,是什么魅力讓...
    跟我一起走吧閱讀 525評(píng)論 0 0

友情鏈接更多精彩內(nèi)容