深度學習第二篇---文本預處理

本文認識文本預處理以及它的作用、以及文本預處理有哪些主要環節。文本預處理是指在將文本數據用于深度學習模型訓練之前,對文本數據進行一系列的清洗、轉換和處理操作,以消除非結構化文本的噪聲和不必要的信息,并將文本數據轉化為適合模型訓練的格式。總的來說,文本預處理的目的是將原始的非結構化文本數據轉化為結構化的數值數據,從而提高模型的性能和準確度。

一、 文本處理的基本方法

image.png

假設我們要對以下句子進行分詞:“今天的天氣真好呀”。采用正向最大匹配算法,我們可以按照以下步驟進行分詞:

  1. 確定最大分詞長度。假設我們設定最大分詞長度為3。
  2. 從左往右掃描句子,取出前3個字符“今天的”。
  3. 查找詞庫,發現“今天的”不是一個詞,因此縮小分詞長度,取出前2個字符“今天”。
  4. 查找詞庫,發現“今天”是一個單字詞,因此將“今天”作為一個詞。
  5. 繼續掃描剩下的字符,取出前3個字符“的天氣”。
  6. 查找詞庫,發現“的天氣”不是一個詞,因此縮小分詞長度,取出前2個字符“的天”。
  7. 查找詞庫,發現“的天”不是一個詞,因此縮小分詞長度,取出前1個字符“的”。
  8. 查找詞庫,發現“的”是一個詞,因此將“的”作為一個詞。

最終的分詞結果是:“今天/的/天氣/真好/呀”。可以看到,這個過程會依賴一個詞典,但是詞典具有一定的缺點,尤其對于一些專有名詞,比如“央視新聞客戶端”,央視新聞是一個詞,不能分成兩個詞網絡名詞,比如你耗子尾汁,會被分割成耗子,尾汁歧義分割,比如羽毛球拍賣完了,會被分割成,羽毛球,拍賣,完,了

1.1 Jieba 分詞

Jieba提供了三種分詞模式:
● 精確模式:試圖將句子最精確地切開,適合文本分析。
● 全模式:把句子中所有可以成詞的詞語都掃描出來,速度非常快,但是不能解決歧義。
● 搜索引擎模式:在精確模式的基礎上,對長詞再次切分,提高召回率,適合用于搜索引擎分詞。

安裝:pip install jieba

import jieba

sent = '南京市長江大橋'

seg_list = jieba.cut(sent, cut_all=True)

print('全模式:', '/ '.join(seg_list))

seg_list = jieba.cut(sent, cut_all=False)
print('精確模式:', '/ '.join(seg_list))

seg_list = jieba.cut(sent)
print('默認精確模式:', '/ '.join(seg_list))

seg_list = jieba.cut_for_search(sent)
print('搜索引擎模式', '/ '.join(seg_list))

輸出結果:
全模式: 南京/ 南京市/ 京市/ 市長/ 長江/ 長江大橋/ 大橋
精確模式: 南京市/ 長江大橋
默認精確模式: 南京市/ 長江大橋
搜索引擎模式 南京/ 京市/ 南京市/ 長江/ 大橋/ 長江大橋

jieba支持用戶自定義詞典開發者可以指定自己自定義的詞典,以便包含 jieba 詞庫里沒有的詞。雖然 jieba 有新詞識別能力,但是自行添加新詞可以保證更高的正確率。比如我們自定義如下的user_dict.txt

創新辦 3 i
云計算 5 n

一個詞占一行;每一行分三部分:詞語、詞頻(可省略)、詞性(可省略),用空格隔開,順序不可顛倒。

import jieba
sent = '北上資金凈流入200億,同比增長15%,云計算板塊漲的最多'

#先導入詞典
jieba.load_userdict("./user_dict.txt")
seg_list = jieba.cut(sent)
print('精確模式:', '/ '.join(seg_list))

不加詞典分詞: 北上/ 資金/ 凈流入/ 200/ 億/ ,/ 同比/ 增長/ 15%/ ,/ 云/ 計算/ 板塊/ 漲/ 的/ 最/ 多
加上自定義詞典分詞: 北上/ 資金/ 凈流入/ 200/ 億/ ,/ 同比/ 增長/ 15%/ ,/ 云計算/ 板塊/ 漲/ 的/ 最/ 多.

1.2 pyltp 分詞

pyltp 是 LTP 的 Python 封裝,提供了分詞,詞性標注,命名實體識別,依存句法分析,語義角色標注的功能。首先下載源碼,從源代碼編譯pyltp,python環境需要先裝cmake。官網:http://ltp.ai/

$ git clone https://github.com/HIT-SCIR/pyltp
$ git submodule init
$ git submodule update
$ python setup.py install
image.png

setup.py 執行成功之后,能進行import pyltp,說明就成功了。然后需要到http://ltp.ai/download.html 下載模型。

image.png

其中分詞用到的cws.model模型

from pyltp import Segmentor
if __name__ == '__main__':
    segmentor = Segmentor("./ltp_data_v3.4.0/cws.model")
    world_list = segmentor.segment("奧巴馬與克林頓昨晚在白宮發表了演說")
    print(world_list)

輸出:['奧巴馬', '與', '克林頓', '昨晚', '在', '白宮', '發表', '了', '演說']

除了pyltp之外,還有hanlp分詞,在此不一一列舉。

1.3 pyltp 命名實體識別和語義角色標注

命名實體識別 (Named Entity Recognition, NER) 是在句子的詞序列中定位并識別人名、地名、機構名等實體的任務。想要實現命名實體識別需要知道一個句子中的分詞和這些詞對應的詞性標注。
LTP 采用 BIESO標注體系。B 表示實體開始詞,I表示實體中間詞,E表示實體結束詞,S表示單獨成實體,O表示不構成命名實體。LTP 提供的命名實體類型為:人名(Nh)、地名(Ns)、機構名(Ni)。B、I、E、S位置標簽和實體類型標簽之間用一個橫線 - 相連;O標簽后沒有類型標簽。

if __name__ == '__main__':
    # 第一步分詞
    segmentor = Segmentor(MODEL_PATH + "/cws.model")
    world_list = segmentor.segment("奧巴馬與克林頓昨晚在白宮發表了演說")
    print(world_list)

    #  第二步,詞性標注
    postagger = Postagger(MODEL_PATH + "/pos.model")
    postag_list = list(postagger.postag(world_list))
    print(postag_list)

    # 第三步,命名實體識別
    recognizer = NamedEntityRecognizer(MODEL_PATH + "/ner.model")
    ner = recognizer.recognize(world_list, postag_list) 
    print("ner,", ner)

    # 第四步,句法依存分析
    parser = Parser(MODEL_PATH + "/parser.model")
    arcs = parser.parse(world_list, postag_list)  # 建立依存句法分析樹
    
    # 第五步,語義角色標注
    labeller = SementicRoleLabeller(MODEL_PATH + "/pisrl.model")
    roles = labeller.label(world_list, postag_list, arcs)
    print("roles", roles)

    # 釋放模型
    recognizer.release() 
    segmentor.release()
    postagger.release()
    parser.release()
    labeller.release()

輸出:
['奧巴馬', '與', '克林頓', '昨晚', '在', '白宮', '發表', '了', '演說']
['nh', 'p', 'nh', 'nt', 'p', 'n', 'v', 'u', 'v']
ner, ['S-Nh', 'O', 'S-Nh', 'O', 'O', 'O', 'O', 'O', 'O']
roles [(6, [('A0', (0, 2)), ('TMP', (3, 3)), ('LOC', (4, 5)), ('A1', (8, 8))])]

給定的句子是:"奧巴馬與克林頓昨晚在白宮發表了演說。"根據語義角色標注(SRL)任務的目標,我們需要分析句子的謂詞論元結構,也就是回答"誰對誰做了什么"這樣的語義問題。

首先,我們需要確定謂詞(predicate),即動作或狀態的核心詞。在這個句子中,謂詞是"上漲"。
然后,我們需要確定論元(argument),即與謂詞相關的詞語或短語。綜上所述,根據給定的句子,可以將謂詞論元結構分析如下:
謂詞(predicate):發表
論元(argument):
施事者 (Agent):奧巴馬與克林
受事者 (Patient):演說
在何時(when):昨晚
在何地 (where) :白宮

其中(6, [('A0', (0, 2)的含義是,謂詞的索引是6(發表),A0是受試者,索引是從0到2,那么施事者是('奧巴馬', '與', '克林頓')。A1是受試者,索引是8(演說),那么組成一句話為:奧巴馬與克林頓發表演說。TMP代表時間,索引是3(昨晚),LOC是地點,索引是4-5(在白宮)。

二、文本詞向量表示方法

什么是詞向量?文本詞向量的表示是指在文本詞向量模型中,每個詞被映射到的一個固定長度的向量。比如”孫悟空“被映射成向量[2.22,1222,3.444,0.9999],常見的文本詞向量模型有Word2Vec、GloVe、FastText等。在這些模型中,每個詞都會被映射到一個固定長度的向量,通常是幾十或幾百維。
實現詞向量有2大挑戰。1、如何把詞轉換成向量?比如,孫悟空,白骨精,豬八戒是3個離散變量,如何把每個離散變量轉換成一個向量表示2、如何讓向量具有語義信息?比如,孫悟空,白骨精,豬八戒3個離散變量,孫悟空把豬八戒是師兄弟關系,更相近,我們改如何讓詞向量具備這樣的語義相似關系?下面我介紹兩種詞向量表示方法,one-hot與word2vec

2.1 獨熱編碼(one-hot encoding)

獨熱編碼是將每個詞表示成具有n個元素的向量,這個詞向量中只有一個元素是1,其他的元素都是0,不同的詞元素的為0的位置不同,其中n的大小是整個詞料中不同詞匯的總數。
以下是一個使用Python實現獨熱編碼的示例:給定一句話“在nlp任務中,首先需要考慮詞如何在計算機中表示”,首先分詞,然后進行one-hot 編碼。

image.png
import numpy as np
import jieba

# 定義一個函數來進行獨熱編碼
def one_hot_encode(word, vocab):
   # 創建一個全零的向量
   one_hot = np.zeros(len(vocab))
   # 獲取單詞在詞匯表中的位置
   index = vocab.index(word)
   # 將對應位置設為1
   one_hot[index] = 1
   return one_hot


if __name__ == '__main__':
   sent = '在nlp任務中,首先需要考慮詞如何在計算機中表示'
   vocab = jieba.lcut(sent)
   print('分詞結果', '/ '.join(vocab))
   for word in vocab:
       one_hot = one_hot_encode(word, vocab)
       print(one_hot)

輸出:
分詞結果 在/ nlp/ 任務/ 中/ ,/ 首先/ 需要/ 考慮/ 詞/ 如何/ 在/ 計算機/ 中/ 表示
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 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. 0. 0. 0. 1. 0. 0.]
[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. 0. 0. 1.]
可以看到,獨熱編碼將每一個詞轉換為了一個長度為12的向量,向量中只有對應位置的元素為1,其他元素均為0,這個位置表示單詞在詞匯表中的位置。
在舉一個例子,假設我們有四個樣本(行),每個樣本有三個特征(列),如圖:


image.png

特征1,代表性別,取值有2個,分別是【男,女】,男用1表示,女用2表示,特征二代表愛好,取值有4個,分別是【籃球,足球,乒乓球,羽毛球】分別用數字1,2,3,4表示,特征3是 愛好程度,取值有3個,分別是【不喜歡,喜歡,特別喜歡】,分別用數字1,2,3表示
將它換成獨熱編碼后,應該如下:


image.png

onehot編碼的優勢:
● 操作簡單,容易理解。
劣勢:
● 第一:維度災難,有多少個詞,我們的矩陣就要擴大多少維度就得是多少,造成每個向量的長度過大,占據大量內存。
● 第二:無法計算詞語之間的相似度
正因為one-hot編碼時明顯的劣勢,這種編碼的方式被應用的地方越來越少,取而代之的是word2vec和word embedding.

2.2 word2vec

word2vec是一種用于將詞語表示為連續向量的技術,它能夠將語義相似的詞語映射到向量空間中的相鄰位置。word2vec模型通常分為兩種:跳字模型(Skip-gram)和連續詞袋模型(Continuous Bag of Words,CBOW),其中Skip-gram模型更為常用。
Skip-gram模型的基本思想是通過給定中心詞來預測周圍的上下文詞;而CBOW模型則是通過給定周圍的上下文詞來預測中心詞。這兩種模型都會生成一個詞嵌入矩陣,其中每個詞都被表示為一個向量。
比如:在/ nlp/ 任務/ 中/ ,/ 首先/ 需要/ 考慮/ 詞/ 如何/ 在/ 計算機/ 中/ 表示


image.png

怎么確定哪些詞是上下文詞呢?需要指定一個窗口大小。圖中”首先“是中心詞,窗口大小是2,窗口范圍內是上下文詞,窗口范圍外的是非上下文詞,其中CBOW算法是通過上下文詞預測中心詞,skip-gram算法是通過中心詞預測上下文詞。
下面是一個使用Python和gensim庫進行word2vec模型訓練和使用的示例代碼:

import re
import numpy as np
import jieba
import gensim
from gensim.models import word2vec
from gensim.models import Word2Vec
import os

PATH = "./data/xi_you_ji.txt"


def read_crops():
    file = open(PATH, encoding="utf-8")
    lines = []
    for line in file:
        line_word_list = jieba.lcut(line)
        current_word_list = []
        for word in line_word_list:
            # 定義正則表達式
            pattern = re.compile('[^\w\s]')
            # 過濾所有標點符號
            text = pattern.sub('', word)
            if text == "\n" or text == ' ':
                continue
            if len(text) > 0:
                current_word_list.append(text)
        if len(current_word_list) > 0:
            lines.append(current_word_list)
    print(lines[0:10])
    return lines


def train(lines):
    print("開始訓練模型")
    model = Word2Vec(lines, vector_size=40, window=5, min_count=3, epochs=40, negative=10)
    print("孫悟空的詞向量是:\n", model.wv.get_vector("悟空"))
    print("孫悟空相關性最高的前10個詞語是:")
    word_list = model.wv.most_similar("孫悟空", topn=10)
    for item in word_list:
        print(item)
    # 保存model
    model.save('word2vec_model')  # 保存模型


def load_model():
    model = None
    if os.path.exists("word2vec_model"):
        print("模型存在,直接加載模型")
        model = word2vec.Word2Vec.load('word2vec_model')  # 加載模型
    else:
        print("模型不存在")
    return model


if __name__ == '__main__':
    # 讀取語料
    lines = read_crops()
    model = load_model()
    if model == None:
        train(lines)
    else:
        word_list = model.wv.most_similar("孫悟空", topn=10)
        for item in word_list:
            print(item)

其中,/data/xi_you_ji.txt是從網絡上下載的西游記第一章內容。


image.png

輸出:


image.png

看到孫悟空相關詞的預測還是可以的,說明模型效果不錯。

2.13 詞嵌入(word embedding)

有四個單詞:“貓”、“狗”、“魚”、“跑”。首先,用數字表示這些單詞:- 貓:1- 狗:2- 魚:3 - 跑:4。如果我們只是用數字表示,那么計算機只能知道它們是不同的單詞,無法確定“貓”和“狗”更接近,還是“魚”和“跑”更接近,因為他們之間的數值都相差1。現在我們來用 word embedding 方法來表示這些單詞,詞向量可能是:

  • 貓:[1, 0,0,0]
  • 狗:[0, 1,0,0]
  • 魚:[0, 0,1,0]
  • 跑:[0, 0,0,1]
image.png

“貓”和“狗”這兩個向量非常接近,因為它們都屬于動物,“魚”和“跑”這兩個向量則相距很遠,因為它們不論屬性還是含義都相差很遠。接下來看看word2vec。所以詞嵌入(Word Embedding)是將詞語映射到一個高維向量空間的技術。在自然語言處理(NLP)任務中,詞嵌入可以將文本中的詞語轉化為計算機可以理解和處理的向量表示。

import torch
import jieba

from torch.utils.tensorboard import SummaryWriter

if __name__ == '__main__':
    sent = '眾猴拍手稱揚道:“好水!好水!原來此處遠通山腳之下直接大海之波。”又道:“那一個有本事的鉆進去尋個源頭出來不傷身體者我等即拜他為王。”連呼了三聲忽見叢雜中跳出一名石猴應聲高叫道:“我進去!我進去!”好猴!也是他:'
    seg_list = jieba.lcut(sent)
    print(seg_list)
    writer = SummaryWriter()
    embedded = torch.randn(len(seg_list), 50)
    writer.add_embedding(embedded, metadata=seg_list)
    writer.close()

運行成功之后,在當前文件夾下會有runs目錄,然后啟動tensorboard。


image.png

游覽器訪問http://0.0.0.0:7777/#projector

image.png

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,156評論 6 529
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 97,866評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 174,880評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,398評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,202評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,743評論 1 320
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,822評論 3 438
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 41,962評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,476評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,444評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,579評論 1 365
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,129評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,840評論 3 344
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,231評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,487評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,177評論 3 388
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,568評論 2 370

推薦閱讀更多精彩內容