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,我們通常將它轉化為特殊詞元如'
#構建詞表 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上有資源)將停用詞刪掉可以有效幫助訓練,因為停用詞沒有意義;或者使用下采樣方法,將高頻率詞按一定概率刪除,頻率越高,則被刪除概率越高,通常使用如下的概率公式:
即單詞\(w_i\)被刪除的概率。其中t是一個常數,實驗取1e-4,\(f(w_i)\)
# 如果在下采樣期間保留詞元,則返回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.