淺談NLP 文本分類/情感分析 任務中的文本預處理工作

淺談NLP 文本分類/情感分析 任務中的文本預處理工作

前言

之所以心血來潮想寫這篇部落格,是因為最近在關注NLP文本分類這類任務中的文本預處理工作,想總結一下自己的所學所想,老規矩,本博文記載僅供備忘與參考,不具備學術價值,本文默認使用python3編程(程式碼能力是屎山級別的,請諒解),默認文本為英文,程式碼主要使用Pytorch(部落客老笨蛋了,之前一直執迷不悟用Keras,現在剛剛開始用torch,怎麼說呢,挺香的 XD)

NLP相關的文本預處理

NLP文本預處理一直是一個很受關注的問題,當下最常用的文本預處理工具當屬nltk,功能統一,api也很簡單,安裝的話直接輸入:

pip install nltk
python#進入python
import nltk
nltk.download()#下載需要的內容

一般來講,最簡單最常見的預處理就是把一整段文本分詞化(Tokenize),對於一段文本(Sentence),可以直接調用nltk庫功能將其分詞化,返回結果為一個詞表(word list)。

import nltk# 為方便,任何import都只在所有程式碼塊中出現一遍,以後的也同理
word_list=nltk.word_tokenize(sentence)

一般來講在預處理數據的時候還會選擇去除標點以及不需要的url等等內容,因此我在自己做實驗的時候選擇使用以下配置來作為基礎的預處理方法。

import string
import re

PUNCT_TO_REMOVE = string.punctuation
url_pattern = re.compile(r'https?://\S+|www\.\S+')
sentence=url_pattern.sub(r'', sentence)
#remove punc
sentence=sentence.translate(str.maketrans('', '', PUNCT_TO_REMOVE))
tmp_word_list=nltk.word_tokenize(sentence)
word_list=[]
for word in tmp_word_list:    
    #lower       
    word=word.lower()
    word_list.append(word)

事實上,文本預處理的方法是非常多樣的,根據下邊程式碼塊中的參考內容鏈接,你可以找到各種各樣數十種有針對性或者泛用的預處理方法,有的是為了處理Twitter中的一些tag,有的是是為了對文本進行詞根化,有的是為了將雙重否定轉換成肯定……總而言之,一切預處理方法都是為了使得NLP任務更好地被執行,使得數據集更容易也更好地被訓練。因此在我們針對NLP任務選擇預處理方法時也應當注意選擇合適的方法。如果我們在一個新聞數據集中使用去除Twitter中tag的預處理方法進行處理的話只會浪費時間。

# 參考鏈接
//medium.com/sciforce/text-preprocessing-for-nlp-and-machine-learning-tasks-3e077aa4946e
//towardsdatascience.com/all-you-need-to-know-about-text-preprocessing-for-nlp-and-machine-learning-bc1c5765ff67
//towardsdatascience.com/nlp-text-preprocessing-a-practical-guide-and-template-d80874676e79
//www.kaggle.com/sudalairajkumar/getting-started-with-text-preprocessing
//www.kaggle.com/theoviel/improve-your-score-with-text-preprocessing-v2
//medium.com/datadriveninvestor/data-cleaning-character-encoding-b4e0e9c65b2a
//github.com/Deffro/text-preprocessing-techniques/blob/master/techniques.py

當然,很多預處理方法在常見的場合併不適用,例如文本中表情處理在Reuters新聞分類以及IMDB情感分析等常用任務上就沒有什麼用處。

為此我總結了5個我認為常用的預處理方法在下面的程式碼中

# 1. stem詞根化
porter = nltk.stem.porter.PorterStemmer()
tmp_word_list=nltk.word_tokenize(sentence)
word_list=[]
for word in tmp_word_list:        
    word=porter.stem(word)
    word_list.append(word)

# 2. spell check拼寫檢查
# pip install pyspellchecker
from spellchecker import SpellChecker
spell=SpellChecker()
tmp_word_list=nltk.word_tokenize(sentence)
word_list=[]
for word in tmp_word_list:    
    #lower             
    misspelled_words = spell.unknown(word.split())
    if word in misspelled_words:
        word_list.append(spell.correction(word))
    else:
        word_list.append(word)

# 3. negation否定詞替換
token=nltk.word_tokenize(token)
word_list=[]  
i, l = 0, len(token)
while i < l:
    word = token[i]
    if word == 'not' and i+1 < l:
        ant = replace(token[i+1])
        if ant:
            word_list.append(ant)
            i += 2
            continue
    word_list.append(word)
    i += 1

def replace(self,word, pos=None):
    """ Creates a set of all antonyms for the word and if there is only one antonym, it returns it """
    antonyms = set()
    for syn in nltk.corpus.wordnet.synsets(word, pos=pos):
        for lemma in syn.lemmas():
            for antonym in lemma.antonyms():
                antonyms.add(antonym.name())
    if len(antonyms) == 1:
        return antonyms.pop()
    else:
        return None   

# 4. stop word 停用詞替換
stops_list = set(nltk.corpus.stopwords.words('english'))
tmp_word_list=nltk.word_tokenize(token)
word_list=[]
for word in tmp_word_list:    
    if word not in stops_list:
        word_list.append(word)

# 5. contraction 連接詞分離
# pip install contractions
import contractions as ctr
tmp_word_list=token.split(' ')
word_list=[]
for word in tmp_word_list:    
    word=ctr.fix(word)
    tmp=nltk.word_tokenize(word)
    for w in tmp:
        word_list.append(w)  

今天暫時更到這裡,後續把自己做實驗遇到的其他一些有趣內容補上