자주 등장하지만, 문장 분석에 있어서 큰 도움이 안되는 단어들은 불용어 처리를 통해서 제거할 수 있다.

 

ex) I, my, me....조사, 접미사 등

NLTK에서는 약 100개 정도의 영단어들을 불용어로 사전에 정의했다고 한다.

 

먼저 NLTK를 호출하고 불용어를 확인해보자.

위에서 말했다시피 100개가 넘기 때문에 10개만 확인.

 

 

2. NLTK 이용해서 불용어 제거

위 코드는 "Family is not an important thing. It's everything."라는 임의의 문장에서, NLTK의 word_tokenize를 통해서 단어 토큰화를 수행한 것이다.

그리고 단어 토큰화 결과로부터 NLTK가 정의하고 있는 불용어를 제외한 결과를 출력하고 있다.

결과적으로 'is', 'not', 'an'가 문장에서 제거된 것 확인가능.

 

3. 한국어에서의 불용어 제거

 

한국어에서 불용어를 제거하는 방법으로는 간단하게는 토큰화 후에 조사, 접속사 등을 제거하는 방법이 있다.

하지만 불용어를 제거하려고 하다보면 조사나 접속사와 같은 단어들뿐만 아니라 명사, 형용사와 같은 단어들 중에서 불용어로서 제거하고 싶은 단어들이 생기기도 한다.

 

결국에는 사용자가 직접 불용어 사전을 만들게 되는 경우가 많다.

이번에는 직접 불용어를 정의해보고, 주어진 문장으로부터 사용자가 정의한 불용어 사전으로부터 불용어를 제거해보겠습니다.

아래의 불용어는 임의 선정한 것으로 실제 의미있는 선정 기준이 아니다.

 

이번 장에서는 정규화 기법퍼스에 있는 단어의 개수를 줄일 수 있는 기법표제어 추출(lemmatization)

어간 추출(stemming)의 개념에 대해서 알아보자. 또한 이 둘의 결과가 어떻게 다른지도 확인해보자!.

 

1. 표제어 추출(Lemmatization)

표제어: Lemma라고 부르며, "기본 단어"라는 뜻을 갖고 있다. 따라서 표제어 추출이란, 단어들로부터 표제어를 찾아가는                것이라고 할 수 있다.

핵심은 단어들이 다른 형태를 갖더라도, 뿌리 단어와 비교했을 때 단어의 개수를 줄일 수 있을지 판단한다. 

예를 들어 am, are, is는 서로 다른 스펠링 이지만, be V라는 점에서는 모두 동일하다.

따라서 am, are, is에 대한 표제어 추출결과는 be인 것이다.

 

표제어 추출을 위한 방법으로는 단어를 형태학적으로 파싱(parsing)하는 것이다.

따라서 모든 단어들을 형태소로 만들어야 한다. 

 

그리고 형태소는 크게 두 가지로 이루어져 있다.

1. 어간 (stem) : 단어의 의미를 담고있는 단어의 핵심 부분

2. 접사 (affix)  : 단어에 추가적인 의미를 주는 부분

 

결론적으로, 표제어 추출은 위 두 가지를 분리하는 작업이라고 할 수 있다.

"cats"에 대한 추출값은 cat(어간) + s(접사)

 

코드를 통해서 실습을 진행해보자.

결과를 보면 알겠지만, 표제어 추출은 어간 추출과는 달리 단어의 형태가 적절히 보존되는 양상을 보이는 특징을 가진다.

 

하지만 그럼에도 위의 결과에서는 dy나 ha와 같이 의미를 알 수 없는 적절하지 못한 단어를 출력하고 있다.

이는 표제어 추출기(lemmatizer)가 본래 단어의 품사 정보를 알아야만 정확한 결과를 얻을 수 있기 때문이다.

 

WordNetLemmatizer는 입력으로 단어가 동사 품사라는 사실을 알려줄 수 있습니다.

즉, dies와 watched, has가 문장에서 동사로 쓰였다는 것을 알려준다면 표제어 추출기는 품사의 정보를 보존하면서 정확한 Lemma를 출력할 수 있다.

 

2. 어간 추출 (Stemming)

어간 추출은 형태학적 분석을 단순화한 버전이라고 볼 수도 있고, 정해진 규칙만 보고 단어의 어미를 자르는 어림짐작의 작업이라고 볼 수도 있다. 따라서 추출 값이 사전에 존재하지 않는 단어일 수도 있다! 

" 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." 라는 문장을 어간 추출을 돌려보자.

추출 값을 보면 thi, wa, copi 등 사전에 없는 단어가 추출된 것을 확인할 수 있다.

stemmer = PorterStemmer()를 사용한것을 확인할 수 가 있는데,

포터 알고리즘의 규칙 중 대표적으로 아래의 규칙들을 가진다.

 

ALIZE → AL    (realize -> real)
ANCE → 제거 (allowance -> allow)
ICAL → IC       (electricical -> electic)

 

보통 어간 추출은 표제어 추출보다 더 빠르게 작동한다.

또한 어간 추출기 중 포터 어간 추출기 (PorterStemmer())이 가장 준수한 성능을 자랑한다고 한다.

 

 

2. 한국어 어간 추출 (Stemming)

한국어의 어간을 먼저 살펴보면, 5언 9품사의 구조를 갖고 있다.

이 중에서, 용언(동사 및 형용사)은 어간+어미로 구성되어 있다.

 

 

1) 활용(conjugation)

활용이란 용언의 어간(stem)어미(ending)를 가지는 일을 말한다.

활용(conjugation)은 한국을 포함한 인도유럽어(indo-european language)에서도 주로 볼 수 있는 언어적 특징 중 하나를 말하는 통칭적인 개념이다. 

 

어간(stem) : 용언(동사, 형용사)을 활용할 때, 원칙적으로 모양이 변하지 않는 부분.

활용에서 어미에 선행하는 부분. 때론 어간의 모양도 바뀔 수 있음(예: 긋다, 긋고, 그어서, 그어라).

 

어미(ending): 용언의 어간 뒤에 붙어서 활용하면서 변하는 부분이며, 여러 문법적 기능을 수행

어간이 어미를 취할 때, 어간의 모습이 일정하다면 규칙 활용, 어간이나 어미의 모습이 변하는 불규칙 활용으로 나뉨.

 

(2) 규칙 활용

규칙 활용은 어간이 어미를 취할 때, 어간의 모습이 일정합니다. 아래의 예제는 어간과 어미가 합쳐질 때, 어간의 형태가 바뀌지 않음을 보여줍니다.

잡/어간 + 다/어미

이 경우에는 어간이 어미가 붙기전의 모습과 어미가 붙은 후의 모습이 같으므로, 규칙 기반으로 어미를 단순히 분리해주면 어간 추출이 됩니다.

(3) 불규칙 활용

불규칙 활용은 어간이 어미를 취할 때 어간의 모습이 바뀌거나 취하는 어미가 특수한 어미일 경우를 말한다.

예를 들어 ‘듣-, 돕-, 곱-, 잇-, 오르-, 노랗-’ 등이 ‘듣/들-, 돕/도우-, 곱/고우-, 잇/이-, 올/올-, 노랗/노라-’와 같이 어간의 형식이 달라지는 일이 있거나 ‘오르+ 아/어→올라, 하+아/어→하여, 이르+아/어→이르러, 푸르+아/어→푸르러’와 같이 일반적인 어미가 아닌 특수한 어미를 취하는 경우 불규칙활용을 하는 예에 속한다.

 

이 경우에는 어간이 어미가 붙는 과정에서 어간의 모습이 바뀌었으므로 단순한 분리만으로 어간 추출이 되지 않고 좀 더 복잡한 규칙을 필요로 합니다. 아래의 링크는 다양한 불규칙 활용의 예를 보여준다.

 

출처:https://wikidocs.net/21707

앞서 배운 단어 데이터(코퍼스)에서 용도에 맞게 토큰으로 분류하는 토큰화(tokenization)에 대해서 배웠다.

이번에는 토큰화의 작업 전,후에서 사용하는 정제(cleaning) & 정규화(normalization)에 대해서 배워보자.

 

먼저 정제와 정규화의 목적은 아래와 같다.

정제(cleaning) : 갖고 있는 코퍼스로부터 노이즈를 제거

정규화(normalization) : 표현 방법이 다른 단어를 통합시켜서 같은 단어로 만들어줆

1. 규칙에 기반한 표기가 다른 단어들의 통합

필요에 따라 같은 의미를 갖고 있음에도, 표기가 다를 수 있다. 이를 하나의 단어로 정규화 할 수 있다.

ex) USA와 US

위 두개는 같은 의미를 가지므로 같게 정규화 해보자.

 

먼저, 대/소문자 통합이다.

통상 영어의 첫 글자는 대문자로 표기한다. He is ~~~ 에서 He 는 he와 같다.

따라서 He/he의 정규화는 대/소문자 통합으로 해결할 수 있다.

 

주의할 점은 대문자와 소문자가 다른의미를 가지는 경우이다.

위 예시에서 미국인 US와 우리를 뜻하는 us가 다른 것처럼!

 

또한 고유명사로써 회사 이름, 사람 이름의 경우 또한 마찬가지이다.

 

그 밖에도, 아래와 같은 방식 등으로 텍스트 전처리를 수행할 수 있다.

2. 불용어 제거 

3. 등장 빈도가 적은 단어

4. 길이가 짧은 단어

 

위 방법들에 대해서는 다음 포스트에서 자세히 다뤄 보도록 하자.

 

어간 추출(Stemming)과 표제어 추출(Lemmatization)

어간추출과 표제어추출 모두 단어의 개수를 줄이는 방식이다.

먼저 어간 추출이란  형태학적 분석을 단순화한 버전이라고 볼 수도 있고, 정해진 규칙만 보고 단어의 어미를 자르는 어림짐작의 작업이라고 볼 수도 있다고 한다.

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.

위의 예시 문장에 대해서 어간추출을 진행해보도록 하자.

 

규칙 기반의 접근을 하고 있으므로 어간 추출 후의 결과에는 사전에 없는 단어들도 포함되어 있다.

가령, 포터 알고리즘의 어간 추출은 이러한 규칙들을 가진다.

ALIZE → AL
ANCE → 제거
ICAL → IC

 

위의 규칙에 따르면 좌측의 단어는 우측의 단어와 같은 결과를 얻게된다.

 

formalize → formal
allowance → allow
electricical → electric

 

실제 코드를 통해 확인해보자.

words = ['formalize', 'allowance', 'electricical']

print('어간 추출 전 :',words)
print('어간 추출 후 :',[stemmer.stem(word) for word in words])
어간 추출 전 : ['formalize', 'allowance', 'electricical']
어간 추출 후 : ['formal', 'allow', 'electric']

어간 추출 속도는 표제어 추출보다 일반적으로 빠른데, 포터 어간 추출기는 정밀하게 설계되어 정확도가 높으므로 영어 자연어 처리에서 어간 추출을 하고자 한다면 가장 준수한 선택이다. NLTK에서는 포터 알고리즘 외에도 랭커스터 스태머(Lancaster Stemmer) 알고리즘을 지원한다. 이번에는 포터 알고리즘과 랭커스터 스태머 알고리즘으로 각각 어간 추출을 진행했을 때, 이 둘의 결과를 비교해보자.

from nltk.stem import PorterStemmer
from nltk.stem import LancasterStemmer

porter_stemmer = PorterStemmer()
lancaster_stemmer = LancasterStemmer()

words = ['policy', 'doing', 'organization', 'have', 'going', 'love', 'lives', 'fly', 'dies', 'watched', 'has', 'starting']
print('어간 추출 전 :', words)
print('포터 스테머의 어간 추출 후:',[porter_stemmer.stem(w) for w in words])
print('랭커스터 스테머의 어간 추출 후:',[lancaster_stemmer.stem(w) for w in words])
어간 추출 전 : ['policy', 'doing', 'organization', 'have', 'going', 'love', 'lives', 'fly', 'dies', 'watched', 'has', 'starting']
포터 스테머의 어간 추출 후: ['polici', 'do', 'organ', 'have', 'go', 'love', 'live', 'fli', 'die', 'watch', 'ha', 'start']
랭커스터 스테머의 어간 추출 후: ['policy', 'doing', 'org', 'hav', 'going', 'lov', 'liv', 'fly', 'die', 'watch', 'has', 'start']

동일한 단어들의 나열에 대해서 두 스태머는 전혀 다른 결과를 보여준다. 두 스태머 알고리즘은 서로 다른 알고리즘을 사용하기 때문이다. 그렇기 때문에 이미 알려진 알고리즘을 사용할 때는, 사용하고자 하는 코퍼스에 스태머를 적용해보고 어떤 스태머가 해당 코퍼스에 적합한지를 판단한 후에 사용하여야 한다.

이런 규칙에 기반한 알고리즘은 종종 제대로 된 일반화를 수행하지 못 할 수 있다. 어간 추출을 하고나서 일반화가 지나치게 되거나, 또는 덜 되거나 하는 경우다. 예를 들어 포터 알고리즘에서 organization을 어간 추출했을 때의 결과를 보자.

organization → organ

organization과 organ은 완전히 다른 단어 임에도 organization에 대해서 어간 추출을 했더니 organ이라는 단어가 나왔다. organ에 대해서 어간 추출을 한다고 하더라도 결과는 역시 organ이 되기 때문에, 두 단어에 대해서 어간 추출을 한다면 동일한 어간을 갖게 될 수 있다. 이는 의미가 동일한 경우에만 같은 단어를 얻기를 원하는 정규화의 목적에는 맞지 않다.

마지막으로 동일한 단어에 대해서 표제어 추출과 어간 추출을 각각 수행했을 때, 결과에서 어떤 차이가 있는지 간단한 예를 통해서 알아 보도록 하자.

 

Stemming

am → am
the going → the go
having → hav

 

Lemmatization
am → be
the going → the going
having → have

 

 

출처: 위키독스

         (https://wikidocs.net/21707)

00 자연어 처리 (natural language processing)

자연어란 우리가 일상생활에서 말하는 말을 의미한다.

자연어처리는 우리의 말을 컴퓨터에게 전달하여 처리시키는 작업이라고 할 수 있다.

 

이를 위해서 자연어를 컴퓨터가 알아들을 수 있는 말로 바꿔 주어야 한다,

텍스트 전처리 작업에는 크게 토큰화 / 정제 / 정규화가 있다고한다.

 

01-01 토큰화(Tokenization)

자연어처리 모델은 "코퍼스"라는 데이터셋을 바탕으로 만들어지는데, 이 코퍼스에서 "토큰"이라고 불리는 단위로 

나누는 작업을 "토큰화"라고 한다.

일반적으로 토큰은 '의미있는 단위"로 정의한다고 생각하면 된다.

 

영어로 예를 들어 Don't be shy. Mr.San is  expecting a lot from you.라는 문장을 토큰화 한다면,

XXXXX, be , shy , Mr , San , is , expecting , a , lot , from , you 이렇게 될 수 있다.

영어권 언어는 한국과 달리 띄어쓰기만으로 쉽게 토큰화 작업을 수행할 수 있다.

 

하지만 소유격을 나타내는 ' (apostrophe)는 어떻게 토큰화 해야할까?

위에 Don't을 예시로 든다면 다양한 방식이 있다.
Dont

Do, n't 

Don, 't 

word_tokenize 모듈을 통해서 어퍼스트로피를 어떻게 처리하는지 보자.

 

Don't라는 코퍼스를 "Do" 와 "n't"로 구분한 것을 볼 수 있다. 구두점과 공백과 달리 단순 제거하게 되면 올바른 토큰화 작업이 힘들어 질 수 있다.

 

그렇다면 점과 공백은 어떤가?

마찬가지로 고려할 사항들이 있다.

Ph.D 처럼 점 자체가 토큰이 될 수도 있고, 문장에서의 마침표로써의 점은 문장의 경계를 파악하는데 도움이 되기 때문에 

점을 제거하지 않을 수 있다.

 

공백의 경우도 마찬가지이다.

공백이 포함된 단어가 존재할 수 있기 때문이다.New York, rock n roll..)

 

- 문장 토큰화

-> 한 문장씩 구분해야함.

-> 어떠한 기준으로 구분할 것인가?

명확한 기준은 ?나 ! 같은 비교적 명확한 구분자(boundary)가 존재한다.

구두점의 경우는 명확하지 않을 수 있다.

위에서 언급한 Ph.D나 Mr.San.. 등 문장의 끝에서만 등장하지 않을 수 있기 때문이다.

 

- 한국어 토큰화의 어려움

영어는 보편적으로 New York과 같은 합성어나 he's와 같은 예외처리만 한다면 띄어쓰기만 해도 토큰화가 쉽다.

이에 반해 한국어는 띄어쓰기만으로는 토큰화가 힘들다.

 

한국어에서 띄어쓰기 단위가 되는 단위를 "어절"이라고 하는데, 어절 토큰화는 NLP에서 지양하고 있다고 한다.

(어절 토큰화 != 단어 토큰화  때문)

 

이 이유는 근본적으로 한국어가 영어와 다른 형태를 가지는 교착어이기 때문이다. (조사, 어미 등을 붙여서 말을 만드는 것)

교착어는 첨가어라고도 하며, "첨가"라는 말 그대로 어근에 접사가 붙어서 의미가 변화하는 형태의 언어를 말한다.

 

예시로 "그"라는 어근에 다양한 조사가 붙어서 그는, 그가, 그에게, 그또한 등등 다양한 의미로 바뀌기 때문에 토큰화가 어렵다. 영어의 경우는 "그" "에게" 처럼 분리가 되기 때문에 한국어가 어렵다고 하는 것이다.

 

한국어 토큰화의 핵심은 "형태소" ( Morpheme) 이다.

형태소는 "뜻을 가진 가장 작은 말의 단위"이며, 두 가지 형태소로 이루어져 있다. "자립 형태소"와 "의존 형태소"이다.

 

Ex) 에디가 책을 읽었다.

자립 형태소: 에디, 책  (어떠한 접사, 어미, 조사와 관계없이 자립하여 쓸 수 있는 형태소)

의존 향태소: -가, -을, 읽, -었, -다.  (다른 형태소와 결합하여 사용되는 형태소)

 

따라서 한국어의 올바른 토큰화를 하기 위해서는 어절 토큰화가 아닌 위의 분리와 같은 형태소 토큰화를 진행해야 한다.!!

 

- 품사 태깅

단어는 품사에 따라 의미가 달리지기도 한다.

fly -> 동사 : 날다, 명사: 파리

못 -> 명사: 얇고 긴거, 부사 : 부정의 의미

따라서 단어를 올바르게 파악하기 위해서는 단어가 어떠한 품사로 쓰였는지에 따라 구분해놓아야 하는데, 

이를 품사 태깅이라고 한다.

 

NLTK에서는 pos_tag라는 기준을 사용하여 품사를 태깅한다.

VBP - 동사

RB - 부사

.......

 

한국어처리는 대표적으로 KoNLPy(코엔엘파이) 패키지에서, 형태소 분석기로 Okt(Open Korea text)를 이용한다.

 

+ Recent posts