표제어 추출
표제어(Lemma)란 단어의 사전적 어원을 뜻합니다. 서로 다른 단어도 표제어는 같은 경우가 있기 때문에, 표제어를 기준으로 통합하면 단어가 정규화됩니다.
예를 들어 am, are, is는 서로 다른 단어이지만 표제어는 동일하게 be입니다. 영어 코퍼스에 특히 많은 be 동사들을 모두 표제어로 통합시킨다면 전체 단어의 수가 많이 줄어들겠죠?
표제어 추출을 하기 위해서는 먼저 토큰화된 단어에 품사 태깅을 해야 하는데요. 실습할 문장에 품사 태깅을 먼저 해 볼게요.
text = 'You are the happiest person.'
tokenized_words = word_tokenize(text)
# 품사 태그
tagged_words = pos_tag(tokenized_words)
pos_tag()는 Penn Treebank POS Tag를 사용한다고 했었죠? 하지만 표제어 추출에 사용되는 함수는 WordNet POS Tag를 사용합니다. 그래서 pos_tag()로 태깅한 품사를 WordNet POS Tag에 맞게 변환해야 합니다.
WordNet POS Tag란, WordNet이란 거대한 영어 어휘 데이터베이스에 적용되어 있는 품사 태그인데요. 다음과 같은 품사 태그가 있습니다.
품사태그 | 품사 |
n (wn.NOUN) | 명사 |
a (wn.ADJ) | 형용사 |
r (wn.ADV) | 부사 |
v (wn.VERB) | 동사 |
PennTreebank POS Tag는 앞에서 봤던 대로 다음과 같은 품사 태그들이 있었습니다.
품사태그 | 품사 | 품사태그 | 품사 |
CC | Coordinating conj. | TO | infinitival to |
CD | Cardinal number | UH | Interjection |
DT | Determiner | VB | Verb, base form |
EX | Existential there | VBD | Verb, past tense |
FW | Foreign word | VBG | Verb, gerund/present pple |
IN | Preposition | VBN | Verb, past participle |
JJ | Adjective | VBP | Verb, non-3rd ps. sg. present |
JJR | Adjective, comparative | VBZ | Verb, 3rd ps. sg. present |
JJS | Adjective, superlative | WDT | Wh-determiner |
LS | List item marker | WP | Wh-pronoun |
MD | Modal | WP$ | Possessive wh-pronoun |
NN | Noun, singular or mass | WRB | Wh-adverb |
NNS | Noun, pluarl | # | Pound sign |
NNP | Proper noun, singular | $ | Dollar sign |
NNPS | Proper noun, plural | . | Sentence-final punctuation |
PDT | Predeterminer | , | Comma |
POS | Possesive ending | : | Colon, semi-colon |
PRP | Personal pronoun | ( | Left bracket character |
PP$ | Possessive pronoun | ) | Right bracket character |
RB | Adverb | " | Straight double quote |
RBR | Adverb, comparative | ‘ | Left open single quote |
RBS | Adverb, superlative | “ | Left open double quote |
RP | Particle | ’ | Right close single quote |
SYM | Symbol | ” | Right close double quote |
Penn Treebank POS Tag를 보면 약간의 규칙성이 보입니다. NN, NNp, NNPS처럼 N으로 시작하는 태그는 모두 명사(Noun)를 의미합니다. JJ, JJR, JJS와 같이 J로 시작하는 태그는 모두 형용사(Adjective)를 의미하죠. 이 규칙성을 이용하여 Penn Treebank POS Tag를 WordNet POS Tag의 4가지 태그로 손쉽게 바꿀 수 있습니다.
from nltk.corpus import wordnet as wn
def penn_to_wn(tag):
if tag.startswith('J'):
return wn.ADJ
elif tag.startswith('N'):
return wn.NOUN
elif tag.startswith('R'):
return wn.ADV
elif tag.startswith('V'):
return wn.VERB
else:
return
그러면, penn_to_wn()을 이용해서 품사를 WordNet POS Tag로 바꾸고 표제어 추출까지 해 보겠습니다. 표제어 추출에는 NLTK의 WordNetLemmatizer 클래스에 있는 lemmatize() 함수를 사용합니다. 단어와 품사 태그를 (단어, 품사 태그) 형태로 lemmatize() 함수에 넣으면 표제어가 반환됩니다. 코드로 살펴볼게요.
from nltk.stem import WordNetLemmatizer
nltk.download('wordnet')
nltk.download('omw-1.4')
lemmatizer = WordNetLemmatizer()
lemmatized_words = []
for word, tag in tagged_words:
# WordNet Pos Tag로 변환
wn_tag = penn_to_wn(tag)
# 품사를 기준으로 표제어 추출
if wn_tag in (wn.NOUN, wn.ADJ, wn.ADV, wn.VERB):
lemmatized_words.append(lemmatizer.lemmatize(word, wn_tag))
else:
lemmatized_words.append(word)
Penn Treebank POS Tag는 WordNet POS Tag보다 더 많은 품사를 가지고 있습니다. 때문에, wn_tag에는 WordNet POS Tag로 바뀌지 않은 일부 품사들도 있는데요. 그럴 경우에 어떤 식으로 표제어 추출을 할지가 이슈가 됩니다.
WordNet POS Tag에 포함되지 않는 품사를 가진 단어들을 그냥 제거할 수도 있고, 품사 정보 추가 없이 lemmatizer.lemmatize(word)를 바로 해주는 경우도 있습니다. 그리고, 표제어 추출을 하지 않고 원형의 단어를 그대로 사용하는 것도 방법인데요.
세 가지 방법 중 무엇을 사용해도 괜찮습니다. 다만, 분석하려는 목적과 코퍼스의 특징에 따라 더 좋은 결과가 나올 방식을 선택해서 전처리하면 됩니다. 저희는 WordNet POS Tag에 포함되지 않는 품사를 가진 단어들은 원형 그대로 사용하겠습니다.
# 품사를 기준으로 표제어 추출
if wn_tag in (wn.NOUN, wn.ADJ, wn.ADV, wn.VERB):
lemmatized_words.append(lemmatizer.lemmatize(word, wn_tag))
else:
lemmatized_words.append(word)
결과를 실행해보면 다음과 같습니다.
# 표제어 추출 확인
print('표제어 추출 전 :', tokenized_words)
print('표제어 추출 후 :', lemmatized_words)
are이 be로, happiest가 happy로 변경됐네요. 표제어 추출이 잘 됐습니다.
표제어 추출 과정도 이후에 쉽게 불러서 쓸 수 있도록 하나의 함수로 만들어 두겠습니다. 함수 words_lemmatizer()는 (단어, 품사) 형태로 품사 태깅된 리스트를 파라미터로 받고, 표제어 추출이 된 결과를 반환합니다.
import nltk
from nltk.stem import WordNetLemmatizer
from nltk.corpus import wordnet as wn
nltk.download('wordnet')
nltk.download('omw-1.4')
def penn_to_wn(tag):
if tag.startswith('J'):
return wn.ADJ
elif tag.startswith('N'):
return wn.NOUN
elif tag.startswith('R'):
return wn.ADV
elif tag.startswith('V'):
return wn.VERB
def words_lemmatizer(pos_tagged_words):
lemmatizer = WordNetLemmatizer()
lemmatized_words = []
for word, tag in pos_tagged_words:
wn_tag = penn_to_wn(tag)
if wn_tag in (wn.NOUN, wn.ADJ, wn.ADV, wn.VERB):
lemmatized_words.append(lemmatizer.lemmatize(word, wn_tag))
else:
lemmatized_words.append(word)
return lemmatized_words
words_lemmatizer() 함수는 preprocess.py 파일에 추가해 두고 이후 포스팅에서 필요할 때 불러와서 사용하겠습니다.
'Data Analysis > Natural Language Processing(NLP)' 카테고리의 다른 글
자연어 전처리 적용 II (0) | 2023.06.14 |
---|---|
표제어 추출 실습 (0) | 2023.06.10 |
품사 태깅 실습 (0) | 2023.06.10 |
품사 태깅(POS; Part of Speech Tagging) (0) | 2023.06.10 |
문장 토큰화 실습 (0) | 2023.06.09 |