######文本特徵提取

在自然語言處理中我們把文本數據變成向量數據,在向量數據中我們可以得到很多來自於文本數據當中的語言特性,這種方式叫做文本表示或文本特徵構造。
文本特徵的通用信息源

文本分類問題當中的對象

    詞:在英文文本處理當中面對的是單個詞組用空格隔開容易區分,在中文文本當中需要通過特定的詞庫如python中的jieba、中科院、清華、哈工大的一些分詞工具來進行分詞處理。在處理詞類時一般關注詞性、詞與上下文之間是否有強聯繫之類的問題。
    文本:一般需要判斷一段話當中他的情感狀況、它是正面或反面、中立之類的問題或者如判斷郵件是否爲垃圾郵件之類的,或者會給出一個詞或文本判斷兩個文本的相似性

如何構建NLP特徵

直接可觀測特徵
單獨詞特徵:如果觀測獨立與上下文的詞語時一般關注它的時態(ed、ing)前綴(un、字母大寫),如何找到他的詞元、關注他在文本中出現的次數。
文本特徵:主要考慮一個句子、一個段落或一篇文本時,觀察到的特徵是詞在文本中的數量和次序。
文本表示

文本表示,簡單的說就是不將文本視爲字符串,而視爲在數學上處理起來更爲方便的向量。而怎麼把字符串變爲向量,就是文本表示的核心問題。
文本表示的好處是什麼?

    根本原因是計算機不方便直接對文本字符串進行處理,因此需要進行數值化或者向量化。
    便於機器學習。
    不僅傳統的機器學習算法需要這個過程,深度學習也需要這個過程。良好的文本表示形式可以極大的提升算法效果。

文本表示分爲哪幾種呢?(基於類型)

    長文本表示
    短文本表示(句子)
    詞表示

文本表示分類(基於表示方法)
離散表示
One-hot表示Multi-hot表示
分佈式表示

    基於矩陣
    基於降維表示
    基於聚類表示
    基於神經網絡
    CBOW
    Skip-gram
    NNLM
    C&W

文本離散表示:詞袋模型與TF-IDF

詞袋子模型(bag of words)
詞袋子模型是一種非常經典的文本表示。顧名思義,它就是將字符串視爲一個 “裝滿字符(詞)的袋子” ,袋子裏的 詞語是隨便擺放的。而兩個詞袋子的相似程度就以它們重合的詞及其相關分佈進行判斷。
舉個例子,對於句子:“我們這些傻傻的路癡走啊走,好不容易找到了飯店的西門”。
我們先進行分詞,將所有出現的詞儲存爲一個詞表。然後依據 “詞語是否出現在詞表中” 可以將這句話變爲這樣的向量:
[1,0,1,1,1,0,0,1,…]
詞表:[我們,你們,走,西門,的,吃飯,旅遊,找到了,…]
其中向量的每個維度唯一對應着詞表中的一個詞。可見這個向量的大部分位置是0值,這種情況叫作“稀疏”。爲了減少存儲空間,我們也可以只儲存非零值的位置。
詞袋子模型的優缺點

優點

    簡單,方便,快速
    在語料充足的前提下,對於簡單的自然語言處理任務效果不錯。如文本分類。

缺點

    其準確率往往比較低。凡是出現在文本中的詞一視同仁,不能體現不同詞在一句話中的不同的重要性。
    無法關注詞語之間的順序關係,這是詞袋子模型最大的缺點。如“武松打老虎”跟“老虎打武松”在詞袋子模型中是認爲一樣的。

對詞袋子模型的改進:TF-IDF

基於 TF-IDF 算法的關鍵詞抽取
1.什麼是TF-IDF呢?

TF(Term Frequency)詞頻
IDF(Inverse Document Frequency)逆文檔頻率,表示一個詞的大小與常見詞的反比
假如我們需要通過計算機來找到文本的關鍵詞如何查找呢,一般是統計出現最高詞語的頻率也就是TF詞頻。但是在統計詞語的過程中通常會遇到如下問題—最高出現的詞彙可能是”停用詞”,如”的”,”是”,”在”,在文本當中有的詞的重要性是不同的,假如我們統計詞頻發現這五個詞的頻率最高,如”中國”、”土地”、”房子”、”蜜蜂”、”養殖”,其中中國、土地這些詞彙經常出現而蜜蜂、養殖等詞語不常出現。如果某個詞比較少見,但是它在這篇文章中多次出現,那麼它很可能就反映了這篇文章的特性,正是我們所需要的關鍵詞。
所以我們需要對文本詞語進行一個權重處理,給蜜蜂、養殖等詞語高權重,而”是”、”在”、”的”、”中國”等詞語低權重等方法來處理文本。
知道了"詞頻"(TF)和"逆文檔頻率"(IDF)以後,將這兩個值相乘,就得到了一個詞的TF-IDF值。某個詞對文章的重要性越高,它的TF-IDF值就越大。所以,排在最前面的幾個詞,就是這篇文章的關鍵詞。
2.如何進行TF-IDF算法?

第一步,計算詞頻。
TF=某詞在文章中出現的次數,考慮到文章有長短之分,爲了便於不同文章的比較,進行"詞頻"標準化。
TF = 某詞在文章中出現的次數/文章的總次數
第二步,計算逆文檔頻率。
這時,需要一個語料庫(corpus),用來模擬語言的使用環境。
逆文檔頻率(IDF)=log(語料庫的文檔總數/包含該詞的文檔數+1)
如果一個詞越常見,那麼分母就越大,逆文檔頻率就越小越接近0。分母之所以要加1,是爲了避免分母爲0(即所有文檔都不包含該詞)。log表示對得到的值取對數。
第三步,計算TF-IDF。
TF-IDF=TF*IDF
可以看到,TF-IDF與一個詞在文檔中的出現次數成正比,與該詞在整個語言中的出現次數成反比。所以,自動提取關鍵詞的算法就很清楚了,就是計算出文檔的每個詞的TF-IDF值,然後按降序排列,取排在最前面的幾個詞。
基於TextRank算法關鍵詞提取

簡單介紹PageRank
PageRank是google搜索引擎進行網頁排名的算法,是用來計算網頁重要性的,它將每一個網頁看作一個節點,將網頁之間的鏈接看作是節點之間的有向邊,網頁的重要性取決於鏈接到它的網頁數量以及這些網頁的重要性。其中它主要根據兩點來進行網頁排名1.指向該A網頁的其他網頁數量2.指向該A網頁的其他網頁質量
它的計算公式爲:

在這裏插入圖片描述
其中PR(A)指的是網頁(A)的排名,Ti是存在到A的鏈接的網頁。C(Ti)是網頁Ti中存在的鏈接的數量。d是阻尼係數,一般定義爲用戶隨機點擊鏈接的概率,根據工程經驗一般取0.85。而(1-d)代表着不考慮入站鏈接的情況下隨機進入一個頁面的概率。
d阻尼係數:現實網絡中,由於存在出鏈度數爲0,即不鏈接到任何網頁的頁面,但是很多網頁可以訪問它。鑑於這類情況,PageRank公式需要進行修正,修正的方法是,在簡單公式的基礎上增加阻尼係數。
TextRank原理

TextRank與PageRank相同,不過TextRank是以詞爲節點,建立起連接關係,而且TextRank當中是無向圖而PageRank當中是有向圖。
在TextRank當中建立了共現關係,其主要思路是設置一個滑動窗口,其中默認大小爲5,也就是最多出現5個詞然後給五個詞進行窗口滑動建立起無向圖的關係連接。

基於TextRank提取關鍵詞的主要步驟:

(1)把給定的文本T按照完整句子進行分割;

(2)對於每個句子,進行分詞和詞性標註處理,並過濾掉停用詞,只保留指定詞性的單詞,如名詞、動詞、形容詞等。這些詞形成候選關鍵詞;

(3)構建候選關鍵詞圖G = (V,E),其中V爲節點集,由(2)生成的候選關鍵詞組成,然後採用共現關係(co-occurrence)構造任兩點之間的邊,兩個節點之間存在邊僅當它們對應的詞彙在長度爲K的窗口中共現;

(4)根據PageRank原理中的衡量重要性的公式,初始化各節點的權重,然後迭代計算各節點的權重,直至收斂;

(5)對節點權重進行倒序排序,從而得到最重要的T個單詞,作爲候選關鍵詞;

(6)由(5)得到最重要的T個單詞,在原始文本中進行標記,若形成相鄰詞組,則組合成多詞關鍵詞。例如,文本中有句子“Matlab code for plotting ambiguity function”,如果“Matlab”和“code”均屬於候選關鍵詞,則組合成“Matlab code”加入關鍵詞序列。
詞向量的one-hot表示

假設我們的詞庫總共有n個詞,那我們開一個1*n的高維向量,而每個詞都會在某個索引index下取到1,其餘位置全部都取值爲0.詞向量在這種類型的編碼中如下圖所示:
加粗樣式
這種方式非常簡單但是並沒有解決詞組之間的相關性問題。因此我們需要嘗試將詞向量的維度降低一些,在一個子空間內可能將詞組關聯性體現出來。
基於SVD降維的表示方法

這是一種構造詞嵌入(即詞向量)的方法,步驟如下:
1.遍歷所有的文本數據集,統計詞出現的次數
2.用一個矩陣X來表示所有的次數情況
3.對X進行奇異值分解得到一個的分解
4.用U的行(rows)作爲所有詞表中詞的詞向量
有兩種方法來構造矩陣X
方法一:詞-文檔矩陣
最初的想法是,我們猜測相互關聯的詞組同時出現在相同的文件中的概率很高。例如,“銀行”、“債券”、“股票”、“錢”等都可能出現在一起。但是,“銀行”、“章魚”、“香蕉”和“曲棍球”可能不會一直一起出現。基於這個想法,我們建立一個詞組文檔矩陣X,具體是這麼做的:遍歷海量的文件,每次詞組i出現在文件j中時,將Xij的值加1。不過大家可想而知,這會是個很大的矩陣,而且矩陣大小還和文檔個數M有關係。
方法二:基於窗口的共現矩陣X
我們還是用一樣的邏輯,不過換一種統計方式,把矩陣X記錄的詞頻變成一個相關性矩陣。我們先規定一個固定大小的窗口,然後統計每個詞出現在窗口中次數,這個計數是針對整個語料集做的。可能說得有點含糊,咱們一起來看個例子,假定我們有如下的3個句子,同時我們的窗口大小設定爲1(把原始的句子分拆成一個一個的詞):
1.I enjoy flying.
2.I like NLP.
3.I like deep learning. 由此產生的計數矩陣如下:
在這裏插入圖片描述
然後我們對X做奇異值分解,觀察觀察奇異值(矩陣的對角元素),並根據我們期待保留的百分比來進行截斷(只保留前k個維度):
在這裏插入圖片描述
然後我們把子矩陣1:||,1:U1:|V|,1:k視作我們的詞嵌入矩陣。也就是說,對於詞表中的每一個詞,我們都用一個k維的向量來表達了。
對X採用奇異值分解
在這裏插入圖片描述

通過選擇前K個奇異向量來進行降維:
在這裏插入圖片描述
這兩種方法都能產生詞向量,它們能夠充分地編碼語義和句法的信息,但同時也帶來了其他的問題:

    矩陣的維度會經常變化(新的詞語經常會增加,語料庫的大小也會隨時變化)。
    矩陣是非常稀疏的,因爲大多數詞並不同時出現。
    矩陣的維度通常非常高(≈106×106) 訓練需要O(n2)的複雜度(比如SVD)
    需要專門對矩陣X進行特殊處理,以應對詞組頻率的極度不平衡的狀況

當然,有一些辦法可以緩解一下上述提到的問題:

    忽視諸如“he”、“the” 、“has”等功能詞。
    應用“傾斜窗口”(ramp window),即:根據文件中詞組之間的距離給它們的共現次數增加相應的權重。
    使用皮爾森的相關性(Pearson correlation),將0記爲負數,而不是它原來的數值。

基於神經網絡的表示方法(當前流行方法)

基於神經網絡的方法是創建一個模型,他能夠一步步迭代地進行學習,最終得出每個單詞基於其上下文的條件概率。
我們想建立一個概率模型,它包含已知和未知參數。每增加一個訓練樣本,它就能從模型的輸入、輸出和期望輸出(標籤),多學到一點點未知參數的信息。在每次迭代過程中,這個模型都能夠評估其誤差,並按照一定的更新規則,懲罰那些導致誤差的參數。
兩種應用場景
1.CBOW—基於上下文預測詞語
我們知道一些上下文的單詞如{“my”,”is”,”dulp”}我要預測中間的單詞{“name”}這種模型叫做連續詞袋子模型(CBOW).
1.它們就是將句子表示爲一些one-hot向量,作爲模型的輸入,咱們記爲x©,模型的輸出記爲y©吧。因爲連續詞袋模型只有一個輸出,所以其實我們只需記錄它爲y。y是已經知道並且有標籤的中心詞。
2.下一步定義模型中其他未知參數,建立兩矩陣,和 。其中的n是可以任意指定的,它用來定義我們“嵌入空間”的維度。V是輸入詞矩陣。當詞語wi(譯註:wi是隻有第i維是1其他維是0的one-hot向量)作爲模型的一個輸入的時候,V的第i列就是它的n維“嵌入向量”(embedded vector)。我們將V的這一列表示爲vi。類似的,U是輸出矩陣。當wj作爲模型輸出的時候,U的第j行就是它的n維“嵌入向量”。我們將U的這一行表示爲uj。要注意我們實際上對於每個詞語wi學習了兩個向量。(作爲輸入詞的向量vi,和作爲輸出詞的向量uj)。
連續詞袋模型(CBOW)中的各個記號:
wi:單詞表V中的第i個單詞
在這裏插入圖片描述:輸入詞矩陣
vi:V的第i列,單詞wi的輸入向量
在這裏插入圖片描述:輸出詞矩陣
ui:U的第i行,單詞wi的輸出向量
CBOW計算步驟:
1.對於m個詞長度的輸入上下文,我們產生它們的one-hot向量
在這裏插入圖片描述
2.我們得到上下文的嵌入詞向量
在這裏插入圖片描述
3.將這些向量取平均
在這裏插入圖片描述
4.產生一個得分向量
在這裏插入圖片描述
5.將得分向量轉換成概率分佈形式
在這裏插入圖片描述
6.我們希望我們產生的概率分佈 ,與真實概率分佈Y相匹配。而y剛好也就是我們期望的真實詞語的one-hot向量。
用一幅圖來表示就是下面這個樣子:
在這裏插入圖片描述
通過上面說的種種步驟,我們知道有了矩陣U、V整個過程是如何運作的,那我們怎樣找到U和V呢?——我們需要有一個目標函數。通常來說,當我們試圖從已知概率學習一個新的概率時,最常見的是從信息論的角度尋找方法來評估兩個概率分佈的差距。也就是使用交叉熵
在這裏插入圖片描述
結合我們當下的例子,y只是一個one-hot向量,於是上面的損失函數就可以簡化爲:
在這裏插入圖片描述
於是我們最終的優化函數爲:
在這裏插入圖片描述
之後用SGD去更新每一個相關的詞向量uc和vj 。
2.skip-gram—基於詞語預測上下文
Skip-gram是CBOW的逆向過程,我們把”name”當成中心詞將預測它周圍的詞語“my”,”is”,”dulp”。這個模型的建立與連續詞袋模型(CBOW)非常相似,但本質上是交換了輸入和輸出的位置。我們令輸入的one-hot向量(中心詞)爲x(因爲它只有一個),輸出向量爲y(j)。U和V的定義與連續詞袋模型一樣。
它的具體過程爲:
1.生成one-hot輸入向量x。
2.得到上下文的嵌入詞向量Vc=Vx。
3.因爲這裏不需要取平均值的操作,所以直接是v=Vc。
4.通過u=UVc產生2m個得分向量
5.將得分向量轉換成概率分佈形式y=softmax(u)。
6.我們希望我們產生的概率分佈與真實概率分佈 相匹配,也就是我們真實輸出結果的one-hot向量。
在這裏插入圖片描述
像連續詞袋模型一樣,我們需要爲模型設定一個目標/損失函數。不過不同的地方是我們這裏需要引入樸素貝葉斯假設來將聯合概率拆分成獨立概率相乘。如果你之前不瞭解它,可以先跳過。這是一個非常強的條件獨立性假設。也就是說只要給出了中心詞,所有的輸出詞是完全獨立的。
在這裏插入圖片描述
中文文本向量化

第一步導入包
import sys,codecs
import pandas as pd
import numpy as np
import jieba.posseg
import jieba.analyse
from sklearn import feature_extraction
from sklearn.feature_extraction.text import TfidfTransformer#構建tfidf權重計算
from sklearn.feature_extraction.text import CountVectorizer#構建詞頻矩陣

# 數據預處理操作:分詞,詞性篩選
def dataPrepos(text):
    l = []
    pos = ['n','nz','v','vd','vn','l','a','d']#定義選取的詞性
    seg = jieba.posseg.cut(text)
    for i in seg:
        if i.word and i.flag in pos:
            l.append(i.word)
        return l
# tf-idf獲取文本top10關鍵詞
def getKeywords_tfidf(data,topK):
    idList, titleList, abstractList = data['id'], data['title'], data['abstract']
    corpus = [] # 將所有文檔輸出到一個list中,一行就是一個文檔
    for index in range(len(idList)):
        text = '%s。%s' % (titleList[index], abstractList[index]) # 拼接標題和摘要
        text = dataPrepos(text) # 文本預處理
        text = " ".join(text) # 連接成字符串,空格分隔
        corpus.append(text)
# tf-idf獲取文本top10關鍵詞
def getKeywords_tfidf(data,topK):
    idList, titleList, abstractList = data['id'], data['title'], data['abstract']
    corpus = [] # 將所有文檔輸出到一個list中,一行就是一個文檔
    for index in range(len(idList)):
        text = '%s。%s' % (titleList[index], abstractList[index]) # 拼接標題和摘要
        text = dataPrepos(text) # 文本預處理
        text = " ".join(text) # 連接成字符串,空格分隔
        corpus.append(text)

    # 1、構建詞頻矩陣,將文本中的詞語轉換成詞頻矩陣
    vectorizer = CountVectorizer()
    X = vectorizer.fit_transform(corpus) # 詞頻矩陣,a[i][j]:表示j詞在第i個文本中的詞頻
    # 2、統計每個詞的tf-idf權值
    transformer = TfidfTransformer()
    tfidf = transformer.fit_transform(X)
    # 3、獲取詞袋模型中的關鍵詞
    word = vectorizer.get_feature_names()
    # 4、獲取tf-idf矩陣,a[i][j]表示j詞在i篇文本中的tf-idf權重
    weight = tfidf.toarray()
    # 5、打印詞語權重
    ids, titles, keys = [], [], []
    for i in range(len(weight)):
        print(u"-------這裏輸出第", i+1 , u"篇文本的詞語tf-idf------")
        ids.append(idList[i])
        titles.append(titleList[i])
        df_word,df_weight = [],[] # 當前文章的所有詞彙列表、詞彙對應權重列表
        for j in range(len(word)):
            print (word[j],weight[i][j])
    
    return corpus
def main():
    # 讀取數據集
    dataFile = '/data/NLP/sample_data.csv'
    data = pd.read_csv(dataFile)
    # tf-idf關鍵詞抽取
    global corpusA
    corpusA = getKeywords_tfidf(data,10)
    print(corpusA)
    
corpusA = []
main()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章