1. 程式人生 > 其它 >nlp資料預處理:詞庫、詞典與語料庫

nlp資料預處理:詞庫、詞典與語料庫

在nlp的資料預處理中,我們通常需要根據原始資料集做出如題目所示的三種結構。但是新手(我自己)常常會感到混亂,因此特意整理一下

1.詞庫

詞庫是最先需要處理出的資料形式,即將原資料集按空格分詞或者使用分詞的包如jieba等,將原始文章分割成一個個詞語所表示的list,一般是一維或者二維的,二維詞庫往往是以行為第一維。
比如下面我們對ptb資料集進行處理產生對應的詞庫

with open('ptb/ptb.train.txt') as f:
    raw_txt = f.read()
sentences = [line.split() for line in raw_txt.split('\n')]

或者在一些情況下,我們只需要統計出現過的詞彙,使用set結構體進行處理即可
wordSet = set([word for word in line for line in sentence])
2.詞典
在詞典中我們主要做的工作是,統計詞頻,按照頻率進行排序,排序主要是為了讓頻率高的詞有較小的編號,若某些單詞出現的次數低於某個界限值,如10,我們通常將它轉化為特殊詞元如''等,然後對單詞進行token到id的轉化和id到token的轉化。下面的程式碼來自李沐老師的d2l庫,相當完美的實現了字典的功能,可以直接使用vocab[token]來查詢到id,使用len函式查詢長度等。

#構建詞表
class Vocab:
    def __init__(self, tokens=None, min_freq=0, reserved_tokens=None):
        if tokens is None:
            tokens = []
        if reserved_tokens is None:
            reserved_tokens = []
        #將二維token轉化為一維列表
        if(isinstance(tokens[0], list)):
            tokens = [token for line in tokens for token in line]
        counter = collections.Counter(tokens)
        self._token_freqs = sorted(counter.items(), key=lambda x:x[1],reverse = True)#降序
        self.idx_to_token = ['<unk>'] + reserved_tokens
        #先對特定的token進行編號
        self.token_to_idx = {token : idx for idx, token in enumerate(self.idx_to_token)}
        #接著對詞語token進行編號
        for token, freq in self._token_freqs:
            if freq < min_freq:
                break
            if token not in self.token_to_idx:
                self.idx_to_token.append(token)
                self.token_to_idx[token] = len(self.idx_to_token) - 1
    
    def __len__(self):
        return len(self.idx_to_token)

    def __getitem__(self, tokens):
        #如果tokens不是列表或元組,就直接查詢token,若不存在返回unk,此函式可以直接陣列形態訪問獲得id
        if not isinstance(tokens, (list, tuple)):
            return self.token_to_idx.get(tokens, self.unk)
        return [self.__getitem__(token) for token in tokens]
    #裝飾器,使得可以不帶括號的訪問函式
    @property
    def unk(self):
        return 0
    
    @property
    def token_freqs(self):
        return self._token_freqs

3.語料庫corpus
在詞典生成完成後,我們就可以將詞庫中的一個個單詞轉化為對應的標號,比如原文是['I','LIKE', 'YOU']就可以轉化為19, 90, 127,我們使用語料庫來進行訓練。值得注意的是,在生成語料庫之前,由於某些高頻詞或者停用詞的存在(停用詞通常也是高頻詞),提前使用停用詞表(github上有資源)將停用詞刪掉可以有效幫助訓練,因為停用詞沒有意義;或者使用下采樣方法,將高頻率詞按一定概率刪除,頻率越高,則被刪除概率越高,通常使用如下的概率公式:

\[P(w_i) = max(1-\sqrt{\frac{t}{f(w_i)}}, 0) \]

即單詞\(w_i\)被刪除的概率。其中t是一個常數,實驗取1e-4,\(f(w_i)\)

是該單詞詞頻,詞頻大於t時,才有可能被刪除。程式碼:

 # 如果在下采樣期間保留詞元,則返回True
 def keep(token):
     return(random.uniform(0, 1) <
         math.sqrt(1e-4 / counter[token] * num_tokens))

最後正式轉化語料庫就很簡單了
corpus = [vocab[line] for line in sentences]
還是需要通過多次的實踐編寫程式碼才能熟練。
程式碼都是參考李沐老師的DIVE INTO DEEP LEARNING.

石中之火,即使無可燃燒之物,也要盡力發亮