정규화 기법중 코퍼스에 있는 단어의 개수를 줄일 수 있는 기법인 제어 추출(lemmatization)과 어간 추출(stemming)의 개념을 알아본다.
이 두 작업이 갖고 있는 의미는 눈으로 봤을 때는 서로 다른 단어들이지만, 하나의 단어로 일반화 시킬 수 있다면 하나의 단어로 일반화 시켜서 문서 내의 단어 수를 줄이겠다는 것이다.
이 방법들은 단어의 빈도수를 기반으로 문제를 풀고자 하는 BoW(Bag of Words)표현을 사용하는 자연어 처리 문제에 주로 사용된다.
1. 표제어 추출(Lemmatization)
표제어(Lemma)는 한글로는 '표제어' 또는 '기본 사전형 단어' 정도의 의미를 갖는다.
표제어 추출은 단어들로부터 표제어를 찾아가는 과정이다.
즉, 단어들이 다른 형태를 가지더라도, 그 뿌리 단어를 찾아가서 단어의 개수를 줄일 수 있는지를 판단한다.
예를 들어, am, are, is는 서로 다른 스펠링이지만 그 뿌리 단어는 be라고 볼 수 있다. 이때, 이 단어들의 표제어는 be이다.
표제어 추출을 하는 가장 섬세한 방법은 parsing를 먼저 진행하는 것이다.
형태소란 '의미를 가진 가장 작은 단위'를 뜻한다..
형태학(morphology)이란, 형태소로부터 단어들을 만들어가는 학문을 뜻한다.
형태소는 두가지 종류가 있다.
- 어간(stem) : 단어의 의미를 담고 있는 단어의 핵심 부분
- 접사(affix) : 단어에 추가적인 의미를 주는 부분
형태학적 파싱은 이 두가지 요소로 분리하는 작업을 말한다.
예를들어 cats라는 단어에 대한 형태학적 파싱을 수행한다면, cat(어간)와 -s(접사)를 분리할 수 있다.
이 때 fox 같이 독립적인 형태소는 파싱을 한다고 하더라도 분리할 수 없다.
NLTK에서는 표제어 추출을 위한 도구인 WordNetLemmatizer를 지원한다. 이를 통해 표제어 추출을 해본다.
from nltk.stem import WordNetLemmatizer
n=WordNetLemmatizer()
words=['policy', 'doing', 'organization', 'have', 'going', 'love', 'lives', 'fly', 'dies', 'watched', 'has', 'starting']
print([n.lemmatize(w) for w in words])
['policy', 'doing', 'organization', 'have', 'going', 'love', 'life', 'fly', 'dy', 'watched', 'ha', 'starting']
표제어 추출은 어간 추출과는 달리 단어의 형태가 적절히 보존되는 양상을 보이는 특징이 있다.
하지만 위의 결과에서 보듯 dy, ha와 같이 의미를 알 수 없는 적절하지 못한 단어를 출력하고 있다.
이는 표제어 추출기(lammatizer)가 본래 단어의 품사 정보를 알아야만 정확한 결과를 얻을 수 있다.
WordNetLemmatizer는 입력으로 단어가 동사 품사라는 사실을 알려줄 수 있다.
즉, dies와 watched, has가 문장에서 동사로 쓰였다는 것을 알려준다면 표제어 추출기는 품사의 정보를 보존하면서 정확한 Lemma를 출력하게 된다.
n.lemmatize('dies', 'v')
'die'
n.lemmatize('watched', 'v')
'watch'
n.lemmatize('has', 'v')
'have'
어간 추출에 대해서 언급하기에 앞서, 표제어 추출과 어간 추출의 차이에 대해 미리 언급하자면
표제어 추출은 문맥을 고려하며, 수행했을 때의 결과는 해당 단어의 품사 정보를 보존한다.
(POS 태그를 보존한다고도 말할 수 있다.)
하지만, 어간 추출을 수행한 결과는 품사 정보가 보존되지 않는다.
(POS 태그를 고려하지 않습니다.)
더 정확히는, 어간 추출을 한 결과는 사전에 존재하지 않는 단어일 경우가 많다.
2. 어간 추출(Stemming)
어간(Stem)을 추출하는 작업을 어간 추출(Stemming)이라고 한다.
어간 추출은 형태학적 분석을 단순화한 버전이라고 볼 수도 있고, 정해진 규칙만 보고 단어의 어미를 자르는 어림짐작의 작업이라고 볼 수도 있다.
이 작업은 섬세한 작업이 아니기 때문에 어간 추출 후에 나오는 결과 단어는 사전에 존재하지 않는 단어일 수 있다.
예제를 보면 쉽게 이해가 가능하다.
다음 은 어간 추출 중 하나인 포터 알고리즘(Porter Algorithm)에 아래의 Text를 입력으로 넣는 예제를 들어보겠다.
input : This was not the map we found in Billy Bones's chest, but an accurate copy, complete in all things--names and heights and soundings--with the single exception of the red crosses and the written notes.
from nltk.stem import PorterStemmer
from nltk.tokenize import word_tokenize
s = PorterStemmer()
text="This was not the map we found in Billy Bones's chest, but an accurate copy, complete in all things--names and heights and soundings--with the single exception of the red crosses and the written notes."
words=word_tokenize(text)
print(words)
['This', 'was', 'not', 'the', 'map', 'we', 'found', 'in', 'Billy', 'Bones', "'s", 'chest', ',', 'but', 'an',
'accurate', 'copy', ',', 'complete', 'in', 'all', 'things', '--', 'names', 'and', 'heights','and',
'soundings', '--', 'with', 'the', 'single', 'exception', 'of', 'the', 'red', 'crosses', 'and', 'the', 'written', 'notes', '.']
print([s.stem(w) for w in words])
['thi', 'wa', 'not', 'the', 'map', 'we', 'found', 'in', 'billi', 'bone', "'s", 'chest', ',', 'but', 'an',
'accur', 'copi', ',', 'complet', 'in', 'all', 'thing', '--', 'name', 'and', 'height', 'and', 'sound', '--',
'with', 'the', 'singl', 'except', 'of', 'the', 'red', 'cross', 'and', 'the', 'written', 'note', '.']
위의 알고리즘의 결과에는 사전에 없는 단어들도 포함되어 있다.
어간 추출은 단순 규칙에 기반하여 이루어 지기 때문이다.
* 포터 알고리즘의 어간 추출 규칙
ALIZE → AL
ANCE → 제거
ICAL → IC
words=['formalize', 'allowance', 'electricical']
print([s.stem(w) for w in words])
['formal', 'allow', 'electric']
위의 규칙에 따라서 다음과 같은 결과가 나온다.
formalize → formal
allowance → allow
electricical → electric
포터 어간 추출기는 정밀하게 설계되어 정확도가 높으므로 영어 자연어 처리에서 어간 추출을 하고자 한다면 가장 준수한 선택이다.
NLTK에서는 포터 알고리즘 외에도 랭커스터 스태머(Lancaster Stemmer)알고리즘을 지원한다.
이 둘을 비교 해보록 한다.
from nltk.stem import PorterStemmer
s=PorterStemmer()
words=['policy', 'doing', 'organization', 'have', 'going', 'love', 'lives', 'fly', 'dies', 'watched', 'has', 'starting']
print([s.stem(w) for w in words])
['polici', 'do', 'organ', 'have', 'go', 'love', 'live', 'fli', 'die', 'watch', 'ha', 'start']
from nltk.stem import LancasterStemmer
l=LancasterStemmer()
words=['policy', 'doing', 'organization', 'have', 'going', 'love', 'lives', 'fly', 'dies', 'watched', 'has', 'starting']
print([l.stem(w) for w in words])
['policy', 'doing', 'org', 'hav', 'going', 'lov', 'liv', 'fly', 'die', 'watch', 'has', 'start']
동일한 단어들의 나열에 대해서 두 스태머는 전혀 다른 결과를 보여준다. 두 스태머 알고리즘은 서로 다른 알고리즘을 사용하기 때문이다. 그렇기 때문에 이미 알려진 알고리즘을 사용할 때는, 사용하고자 하는 코퍼스에 스태머를 적용해보고 어떤 스태머가 해당 코퍼스에 적합한지를 판단한 후에 사용하여야 한다.
이런 규칙에 기반한 알고리즘은 종종 제대로 된 일반화를 수행하지 못 할 수 있다.
어간 추출을 하고나서 일반화가 지나치게 되거나, 또는 덜 되거나 하는 경우를 예로 들수 있다.
마지막으로, 같은 단어에 대해서 표제어 추출과 어간 추출을 각각 수행했을 때, 결과에서 어떤 차이가 있는지 예를 보면 다음과 같다.
Stemming
am → am
the going → the go
having → hav
Lemmatization
am → be
the going → the going
having → have
3. 한국어에서의 어간 추출
한국어는 아래의 표와 같이 5언 9품사의 구조를 가지고 있습다.
언 | 품사 |
체언 | 명사, 대명사, 수사 |
수식언 | 관형사, 부사 |
관계언 | 조사 |
독립언 | 감탄사 |
용언 | 동사, 형용사 |
이 중 용언에 해당되는 '동사'와 '형용사'는 어간(stem)과 어미(ending)의 결합으로 구성된다..
3-1) 활용(conjugation)
활용이란 용언의 어간(stem)이 어미(ending)를 가지는 일을 말한다.
- 어간(stem) : 용언(동사, 형용사)을 활용할 때, 원칙적으로 모양이 변하지 않는 부분. 활용에서 어미에 선행하는 부분. 때론 어간의 모양도 바뀔 수 있음. (예: 긋다, 긋고, 그어서, 그어라).
- 어미(ending): 용언의 어간 뒤에 붙어서 활용하면서 변하는 부분이며, 여러 문법적 기능을 수행
활용은 어간이 어미를 취할 때, 어간의 모습이 일정하다면 규칙 활용, 어간이나 어미의 모습이 변하는 불규칙 활용으로 나뉜다.
3-2) 규칙 활용
규칙 활용은 어간이 어미를 취할 때, 어간의 모습이 일정하다.
아래의 예제는 어간과 어미가 합쳐질 때, 어간의 형태가 바뀌지 않음을 보여준다.
잡/어간 + 다/어미
이 경우에는 어간이 어미가 붙기전의 모습과 어미가 붙은 후의 모습이 같으므로, 규칙 기반으로 어미를 단순히 분리해주면 어간 추출이 된다.
3-3) 불규칙 활용
불규칙 활용은 어간이 어미를 취할 때 어간의 모습이 바뀌거나 취하는 어미가 특수한 어미일 경우를 말한다.
예를 들어 ‘듣-, 돕-, 곱-, 잇-, 오르-, 노랗-’ 등이 ‘듣/들-, 돕/도우-, 곱/고우-, 잇/이-, 올/올-, 노랗/노라-’와 같이 어간의 형식이 달라지는 일이 있거나 ‘오르+ 아/어→올라, 하+아/어→하여, 이르+아/어→이르러, 푸르+아/어→푸르러’와 같이 일반적인 어미가 아닌 특수한 어미를 취하는 경우 불규칙활용을 하는 예에 속한다.
이 경우에는 어간이 어미가 붙는 과정에서 어간의 모습이 바뀌었으므로 단순한 분리만으로 어간 추출이 되지 않고 좀 더 복잡한 규칙을 필요로 한다.
'Deep learning > NLP(자연어처리)' 카테고리의 다른 글
카운트 기반의 단어 표현(Count based word Representation) (0) | 2020.03.02 |
---|---|
정규 표현식(Regular Expression) (0) | 2020.03.01 |
정제(Cleaning) and 정규화(Normalization) (0) | 2020.03.01 |
토큰화 (0) | 2020.03.01 |
펄플렉서티(Perplexity) (0) | 2020.02.27 |