Development/AI

자연어 처리(NLP) 개념 잡기 (2) - 표제어, 어간

고고마코드 2022. 1. 8. 20:03
반응형

자연어 처리(NLP)를 학습할 때 필요한 용어들을 기초적인 지식 수준에서 이해하기 쉽게 정리합니다.
예제 코드는 Google Colab 을 기반으로 작성했습니다.


자연어 처리(NLP) 개념 잡기의 다른 포스팅도 참고하세요.

자연어 처리(NLP) 개념 잡기 (1) - 말뭉치, 토큰화

자연어 처리(NLP) 개념 잡기 (3) - 정제, 정규화, 불용어


표제어(Lemmatization)

표제어는 단어의 기본형이다. 보통 사전에 대표로 실린 단어를 뜻한다.

예를 들어 '사과들' 을 뜻하는 단어는 'apples' 이지만

이 단어의 표제어는 본래의 뜻이 '사과'인 'apple' 이다.

또한 'apples' 단어로 어간과 접사를 나누어 보면

  • 어간: 단어의 의미를 담고 있는 단어의 핵심 부분 - 'apple'

  • 접사: 단어에 추가적인 의미를 주는 부분 - 's'

이렇게 표제어 추출을 하는 이유는 자연어 처리에서는 전처리 과정의 복잡성을 줄이는 것이 중요하기 때문에 단어를 표제어로 바꾸어 벡터 표현의 차원을 줄이는 방법이 도움이 된다.

예제 1

import spacy
nlp = spacy.load('en')

words = nlp("i ate an apples")
for word in words:
  print('{} -> {}'.format(word, word.lemma_))
i -> i
ate -> eat
an -> an
apples -> apple

spacy는 사전에 정의된 WordNet 사전을 사용해 표제어를 추출한다.

위 예제 코드를 보면 2개의 단어가 변형된 것을 알 수 있다.

'ate' -> 'eat' / 'apples' -> 'apple'

ate(먹었다)는 eat(먹다)의 과거형이므로 표제어인 'eat' 으로 변형하여 추출했다.

apples(사과들)는 apple(사과)의 복수형이므로 표제어인 'apple'으로 변형하여 추출했다.


어간(Stemming)

앞에서 설명했지만 어간은 단어의 의미를 담고 있는 단어의 핵심 부분이다.

어간 추출은 표제어 추출 대신 사용하는 축소 기법이다. (표제어 추출이 어간 추출보다 더 오래 걸리지만 성능이 좋다)

수동으로 만든 규칙을 사용해 단어의 끝을 잘라 어간이라는 공통 형태로 축소한다.

어간 추출 예제 - Porter 알고리즘

import nltk
nltk.download('wordnet')
from nltk.stem.snowball import SnowballStemmer

snow_stemmer = SnowballStemmer(language='english')

words = ['cared','university','fairly','easily','singing',
       'sings','sung','singer','sportingly']

stem_words = []
for w in words:
    x = snow_stemmer.stem(w)
    stem_words.append(x)

for e1,e2 in zip(words,stem_words):
    print(e1+' --> '+e2)
cared --> care
university --> univers
fairly --> fair
easily --> easili
singing --> sing
sings --> sing
sung --> sung
singer --> singer
sportingly --> sport

어간 추출 예제 - Snowball 알고리즘

import nltk
nltk.download('wordnet')
from nltk.stem import PorterStemmer

porter_stemmer = PorterStemmer()

words = ['cared','university','fairly','easily','singing',
       'sings','sung','singer','sportingly']

porter_words = []
for w in words:
    x = porter_stemmer.stem(w)
    porter_words.append(x)

for e1,e2 in zip(words,porter_words):
    print(e1+' --> '+e2)
cared --> care
university --> univers
fairly --> fairli
easily --> easili
singing --> sing
sings --> sing
sung --> sung
singer --> singer
sportingly --> sportingli

두 예제를 보면 알겠지만 어간 추출은 단어를 보고 어림짐작해서 어간을 추출하기 때문에 잘못 추출한 부분이 보이기도 한다.

'easily' 를 보고 우리가 원하고자 하는 어간은 'easy'일 것이지만 엉뚱한 단어가 나왔다.

또한 알고리즘마다 추출하는 어간이 다르며 성능 차이를 보인다.

그렇기 때문에 알고리즘을 사용할 때는, 사용하고자 하는 말뭉치에 적용해보고 어떤 알고리즘이 적합한지 판단한 후에 사용해야 한다.


참고자료

  1. 파이토치로 배우는 자연어 처리

  2. 딥러닝을 이용한 자연어 처리 입문 (지은이: 유원준 외1)


반응형