표제어 추출(Lemmatization)은 어간 추출과 같이 텍스트 정규화에 사용되는 방법입니다. 어간 추출이 규칙을 기반으로 접사들을 잘라냈다고 하면, 표제어 추출은 사전을 이용하여 단어의 원형을 찾는 작업이라 볼 수 있습니다.
NLTK에서는 WordNetLemmatizer를 통해 표제어 추출을 진행할 수 있습니다.
import nltk
from nltk.stem import WordNetLemmatizer
nltk.download('wordnet') # 표제어 추출에 사용할 사전을 다운받습니다.
lemmatizer = WordNetLemmatizer()
print(lemmatizer.lemmatize("lives"))
# 결과
# life
표제어 추출은 어간 추출과 달리 사전에서 검색하여 표제어를 반환합니다. 때문에 규칙 기반의 어간 추출보다 속도가 더 느립니다.
하지만, 'studi'같은 온전하지 않은 단어를 반환하는 어간 추출과 달리 사전을 기반으로 하기 때문에 비교적 온전한 형태의 단어를 반환해줍니다.
표제어 추출 역시 어간 추출과 마찬가지로 단어의 형태가 적절치 못하거나 단어의 원형을 얻지 못하는 경우가 생기기도 합니다.
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
print(lemmatizer.lemmatize("dies")) # 결과: dy
print(lemmatizer.lemmatize("went")) # 결과: went
때문에, 표제어 추출을 진행할 때는 단어와 단어의 품사를 같이 입력하여 정확한 표제어를 얻습니다.
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
# lemmatize 메소드에서 품사의 기본값은 'n', 명사로 되어 있습니다.
print(lemmatizer.lemmatize("dies", 'v')) # 결과: die
print(lemmatizer.lemmatize("went", 'v')) # 결과: go
표제어 추출은 형태소에 품사를 지정해주는 품사 태깅과 함께 사용할 수 있습니다.
from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag
from nltk.stem import WordNetLemmatizer
txt = "We cannot direct the wind but we can adjust the sails."
tokens = word_tokenize(txt)
tags = pos_tag(tokens)
lemmatizer = WordNetLemmatizer()
result = []
for token, tag in tags:
lemma = lemmatizer.lemmatize(token, pos=tag)
result.append(lemma)
print(result)
# 결과
# KeyError: 'PRP'
하지만 품사 태깅의 결과를 그대로 표제어 추출에 인자로 넘겨주면 오류가 발생하게 됩니다. 이는 WordNetLemmatizer
의 품사 태그가 pos_tag
에서 사용하는 태그보다 적기 때문에 품사 태그를 인지하지 못하는 오류가 발생하게 되는 것입니다.
WordNetLemmatizer
의 lemmatize
메소드에서 사용하는 품사 태그는 다음과 같습니다.
품사 태그 | 설명 |
---|---|
n | noun |
v | verb |
a | adjective |
r | adverb |
s | adjective satellite |
때문에 pos_tag
의 품사 태그를 WordNetLemmatizer
내에서 유효한 품사 태그로 변환해줄 필요가 있습니다.
for token, tag in tags:
if tag.startswith('N'):
lemma = lemmatizer.lemmatize(token, pos='n')
elif tag.startswith('V'):
lemma = lemmatizer.lemmatize(token, pos='v')
elif tag.startswith('J'):
lemma = lemmatizer.lemmatize(token, pos='a')
elif tag.startswith('R'):
lemma = lemmatizer.lemmatize(token, pos='r')
else:
lemma = lemmatizer.lemmatize(token)
result.append(lemma)