通過前面一系列的文本前處理,我們成功將雜亂無章的文本整理完畢,讓電腦可以好好地處理每一個單詞。
不過在一個完整的句子中,每一個單詞被賦予的含意並不是只有它本身被哪些字母組合起來而已,舉一個簡單的例子來說:
Let's go to the park. ( 我們去公園吧 )
I need to park the car. ( 我需要停車 )
對於電腦來說,斷詞完之後的結果都是 park,並沒有差別,但我們一眼就能看出這兩個代表的意思不一樣,原因就在於我們可以從上下文、詞性等其他地方判斷出來。
就好像你有兩個同學都叫 Tom,但你可以從他們的外表、衣著、性格等特徵分辨出兩人的不同,語言的世界也是如此,比方說 park 作為名詞的時候是公園,作為動詞的時候則有停車的意思。
所以,通過對句子做出完整的詞性標註和語法分析,我們就可以更完整地展示每個單詞的基本資訊,用在其他的 NLP 任務上。
那麼就進入正題吧。
詞性標註 ( parts-of-speech tagging, POS ) 對於翻譯任務或是提取語意都有很大的幫助。詞性的話大家在學習語言的時候應該都有學過,像是動詞、名詞、形容詞等等。
過去的做法是基於規則 ( rule-based ) 或是使用統計和機率的方式預測單詞的詞性,而隨著萬能的深度學習出現,也出現了使用模型去預測詞性的方式。
接下來就進入程式實作的部分吧,我們以下面這個句子為例:
Yesterday, Tom traveled to New York City and enjoyed a fantastic Broadway show.
NLTK 用來標註詞性的工具其實昨天已經借來用過一次了,今天來看一下它完整顯示出來長怎樣:
from nltk.tag import pos_tag
from nltk.tokenize import word_tokenize
sentence = "Yesterday, Tom traveled to New York City and enjoyed a fantastic Broadway show."
tokens = word_tokenize(sentence)
print(pos_tag(tokens))
[('Yesterday', 'NN'), (',', ','), ('Tom', 'NNP'), ('traveled', 'VBD'), ('to', 'TO'), ('New', 'NNP'), ('York', 'NNP'), ('City', 'NNP'), ('and', 'CC'), ('enjoyed', 'VBD'), ('a', 'DT'), ('fantastic', 'JJ'), ('Broadway', 'NNP'), ('show', 'NN'), ('.', '.')]
首先對句子做斷詞,然後再標註詞性就完成了,不過我在練習的時候發現,之前學英文的詞性是像 Verb、Adjective 這種的,但電腦所標註的詞性簡稱和我認識的有些不同,而且更複雜一些。
後來上網查一下對照表才知道,這些標註的簡寫有更詳細的含意,比方說 NNP 是單數專有名詞,CC 是連接詞,VBD 是動詞過去式 …… 等等。
大家如果想要了解的更詳細的話可以參考這個連結。
此外,Spacy 也有 POS 的工具,作法也一併附上來好了:
import spacy
sentence = "Yesterday, Tom traveled to New York City and enjoyed a fantastic Broadway show."
nlp = spacy.load("en_core_web_sm")
text = nlp(sentence)
print([(token.text, token.tag_) for token in sentence])
[('Yesterday', 'NN'), (',', ','), ('Tom', 'NNP'), ('traveled', 'VBD'), ('to', 'IN'), ('New', 'NNP'), ('York', 'NNP'), ('City', 'NNP'), ('and', 'CC'), ('enjoyed', 'VBD'), ('a', 'DT'), ('fantastic', 'JJ'), ('Broadway', 'NNP'), ('show', 'NN'), ('.', '.')]
我們把兩邊的輸出比對一下會發現,Spacy 詞性標註的結果幾乎和 NLTK 相同。
此外,使用 .pos_
可以獲得另一種詞性標註的表達方式,這個就比較貼近我認識的那種,連標點符號都用 PUNCT
標起來了:
print([(token.text, token.pos_) for token in sentence])
[('Yesterday', 'NOUN'), (',', 'PUNCT'), ('Tom', 'PROPN'), ('traveled', 'VERB'), ('to', 'ADP'), ('New', 'PROPN'), ('York', 'PROPN'), ('City', 'PROPN'), ('and', 'CCONJ'), ('enjoyed', 'VERB'), ('a', 'DET'), ('fantastic', 'ADJ'), ('Broadway', 'PROPN'), ('show', 'NOUN'), ('.', 'PUNCT')]
接下來,讓我們看看如何使用 jieba 進行中文的詞性標註:
import jieba
sentence = '湯姆今天上課遲到而且沒有繳交作業'
words = jieba.posseg.cut(sentence)
print([(word, flag) for word, flag in words])
[('湯姆', 'N'), ('今天', 'N'), ('上課', 'Vi'), ('遲到', 'Vi'), ('而且', 'C'), ('沒有', 'Vt'), ('繳交', 'Vt'), ('作業', 'N')]
jieba 的詞性標註結果就和 NLTK 還有 Spacy 不太一樣了,雖然從縮寫來看可以辨認的出來,不過如果要了解每一個詞性代號的意思,還是要上網去查。
推薦文章
https://www.nltk.org/api/nltk.tag.pos_tag.html
https://spacy.io/usage/linguistic-features/
https://www.cnblogs.com/bytesfly/p/part-of-speech.html