728x90

정규화 기법 중에서 코퍼스의 단어의 개수를 줄일수 있는 방법이 어간 추출(stemming)과 표제어 추출(lemmatization)이다.
두 작업의 목적은 의미가 같은 단어를 하나의 단어로 일반화 시켜서 문서 내의 단어의 수를 줄이는 것이다.
자연어 처리에서 전처리의 최종 목표는 원본 코퍼스의 복잡도를 감소시키는 것이다.

표제어 추출(Lemmatization)

표제어(lemma)란 '기본 사전형 단어'이다. 표제어 추출은 단어로부터 표제어를 찾는 과정으로 단어의 형태가 달라도 뿌리가 같은 단어를 찾아서 개수를 줄인다. 예를 들어 am, are, is는 서로 다른 단어이지만 뿌리 단어는 be이다. 이때 단어들의 표제어를 be라고 한다.

표제어 추출을 하는 가장 섬세한 방법은 단어의 형태학적 파싱을 진행하는 것이다. 형태소란 '의미를 가진 가장 작은 단위'로
형태학(morphology)이란 형태소로부터 단어를 만들어가는 학문이다.

형태소의 종류로 어간(stem)과 접사(affix)가 존재하는데 이 둘을 살펴보자

1) 어간(stem)
: 단어의 의미를 가지고 있는 핵심 부분
2) 접사(affix)
: 단어에 추가적인 의미를 주는 부분

형태학적 파싱이란 이 두가지 구성 요소를 분리하는 작업이다. cats란 단어에 형태학적 파싱을 하면 cat(어간)과 s(접사)로 분리된다.
물론 더 이상 분리할 수 없는 경우도 있다.

WordNetLemmatizer 실습

우선 wordnet을 설치한다

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

lemmatizer = WordNetLemmatizer()

words = ['policy', 'doing', 'organization', 'have', 'going', 'love', 'lives', 'fly', 'dies', 'watched', 'has', 'starting']
print("표제어 추출 전 : ", words)
print("표제어 추출 후 : ",[lemmatizer.lemmatize(word) for word in words])

위의 코드를 실행하면 아래와 같은 결과를 얻는다.

표제어 추출 전 :  ['policy', 'doing', 'organization', 'have', 'going', 'love', 'lives', 'fly', 'dies', 'watched', 'has', 'starting']
표제어 추출 후 :  ['policy', 'doing', 'organization', 'have', 'going', 'love', 'life', 'fly', 'dy', 'watched', 'ha', 'starting']

표제어 추출은 단어의 형태가 적절히 유지가 되지만 dy나 ha같이 의미없는 단어로 추출하는 경우도 있다.
이는 표제어 추출기(lemmatizer)가 단어의 품사를 알아야 제대로 추출을 하기 때문이다.
WordNetLemmatizer는 입력으로 단어가 동사 품사라는 사실을 알려줄 수 있다.
즉, dies와 watched, has가 문장에서 동사로 쓰였다는 것을 알려주면 표제어 추출기는 품사의 정보를 보존하면서 정확한 Lemma를 출력하게 된다.

lemmatizer.lemmatize('dies', 'v')

위 코드를 실행하면 제대로 파싱이 된다.

'die'

표제어 추출은 문맥을 고려하며 수행했을 때의 결과는 해당 단어의 품사 정보를 보존하지만 어간 추출을 수행한 결과는 품사 정보가 보존되지 않는다.

어간 추출(stemming)

어간을 추출하는 작업으로 기계적으로 정해진 규칙에 따라 어간을 추출하는 과정이다.
이 작업은 섬세한 작업이 아니기 때문에 어간 추출 후에 나오는 결과 단어는 사전에 존재하지 않는 단어일 수도 있다.
아래에서 어간추출 알고리즘 중에 하나인 포터 알고리즘으로 어간을 추출한다.

PorterStemmer

from nltk.stem import PorterStemmer
from nltk.tokenize import word_tokenize

stemmer = PorterStemmer()

sentence = "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."
tokenized_sentence = word_tokenize(sentence)

print('어간 추출 전 :', tokenized_sentence)
print('어간 추출 후 :',[stemmer.stem(word) for word in tokenized_sentence])

우선 토크나이저로 문장을 토큰화하고 토큰화해서 얻은 단어들을 stemmer에 넣어준다.

어간 추출 전 : ['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', '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('어간 추출 전 :',words)
print('어간 추출 후 :',[stemmer.stem(word) for word in words])
어간 추출 전 : ['formalize', 'allowance', 'electricical']
어간 추출 후 : ['formal', 'allow', 'electric']

어간 추출은 기계화된 작업이기 때문에 표제어 추출보다 빠르게 진행된다. 포터 알고리즘은 나름 세밀하게 설계되어 영어 자연어 처리에서
어간 추출을 수행 시 1번 옵션이다. NLTK에서는 포터 알고리즘 외에도 랭커스터 스태머(Lancaster Stemmer) 알고리즘을 지원한다.

이번에는 포터 알고리즘과 랭커스터 스태머 알고리즘으로 각각 어간 추출을 진행했을 때, 이 둘의 결과를 비교해보자.

porter vs lancaster

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']

동일한 단어에 대해서 두 스태머는 서로 다른 결과를 출력한다. 따라서 목적에 맞게 적절한 어간 추출기를 사용하면 된다.

한국어의 어간 추출

한국어는 5언 9품사의 구조를 가지고 있다.

체언 명사, 대명사, 수사
수식언 관형사, 부사
관계언 조사
독립언 감탄사
용언 동사, 형용사

이 중에서 용언에 해당하는 동사와 형용사는 어간(stem)과 어미(ending)의 결합으로 구성된다.

 

728x90

코퍼스의 용도에 맞게 토큰을 분류하는 작업을 토큰화(tokenization)이라 하고, 토큰화 작업 전,후에는 텍스트 데이터를 용도에 맞게 정제(cleaning) 및 정규화(normalization)하는 일이 항상 함께한다.

  • 정제(cleaning) : 갖고 있는 코퍼스로부터 노이즈 데이터를 제거한다
  • 정규화(normalization) : 표현 방법이 다른 단어들을 통합시켜서 같은 단어로 만들어준다.

정제 작업은 토큰화 작업에 방해가 되는 부분들을 제거함. 따라서 토큰화보다 먼저 진행되기도 하지만 중간중간 남은 노이즈를 제거하기 위해서
지속적으로 필요하다. 완벽하게 정제하는건 사실상 불가능해서 타협점을 찾는것도 방법이다

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

표기가 다르지만 의미가 같은 단어들을 하나의 단어로 정규화하는 방법이 있다.
USA와 US는 동일한 의미이므로 한 단어로 정규화할 수 있다. 이러한 정규화를 거치면 US를 찾아도 USA도 함께 찾을 수 있다.

2. 대, 소문자 통합

영어권에서는 대소문자를 통합하는게 정규화 방법 중에 하나임. 영어권에서는 문장 맨 앞글자가 대문자인데 사실 이는 특별한 의미가 있는것은 아니기 때문에
소문자로 변환하는 과정을 거친다. 소문자로 정규화하는 방법의 장점은 검색의 확장이다.
예를 들어서, 사용자가 Cup을 검색했을때 소문자로 변환하면 cup으로 된 정보들도 검색이 가능해진다.
물론, 대문자가 유지되어야하는 경우도 존재한다. 예를 들어, 미국을 의미하는 US와 우리를 뜻하는 us는 뜻이 다르고, 회사 이름이나 사람 이름등이 대문자로 유지되야하는 것은 사실이다.
이러한 문제는 언제 소문자 변환을 사용할지 결정하는 ML 시퀀스 모델을 통해 좀 더 정확하게 수행 가능하지만, 예외 사항을 고려하지 않고
그냥 전부 소문자로 변환하는 것도 하나의 방법이긴 하다

3. 불필요한 단어 제거

정제 작업에서 삭제하는 노이즈 데이터는 자연어가 아니면서 의미 없는 글자들(특수문자 등)일수도 있지만, 분석하려는 목적에 맞지 않는 불필요한 데이터도
노이즈 데이터라고 한다. 불필요한 단어들을 제거하는 방법으로는 불용어 제거와 등장 빈도가 적은 단어 제거, 길이가 짧은 단어 제거등이 있다.

(1) 등장 빈도가 적은 단어

등장 빈도가 현저히 적은 단어는 자연어 처리에 도움이 되지 않는 경우도 있다. 스팸 메일 분류기를 설계할때 등장하는 단어 위주로 스팸 메일을 구분할 수 있는데 100,000개의 메일 데이터중에서 5번 밖에 등장하지 않은 단어가 있으면 이 단어는 분류에 거의 도움이 되지 않을 것이다.

(3) 짧은 단어

한국어에서는 별로 효용이 없지만 영어권 언어에서는 짧은 단어 제거만으로도 유의미한 정제 효과를 거둘수 있다.
사실 길이를 조건으로 단어를 제거하면 구두점도 함께 제거하는 효과도 있다.
아무튼, 영어 단어의 경우 평균 길이가 6

7 정도이고 한국어 단어의 경우 2

3 정도인데 한국어의 단어는 한자어가 많고 한 글자로도
의미를 가진 단어들이 많기 때문에 이러한 방식이 위험함. 예를 들어, dragon은 한국어로 용 한글자로 표현이 된다.

이런 특성 때문에 영어는 길이가 2~3 이하인 단어를 제거하는 걸로도 의미없는 단어 제거 효과를 누릴 수 있다.
길이가 1인 단어를 제거하면 의미 없는 관사 'a'나 주어 'I'를 제거할 수 있다.

import re
text = "I was wondering if anyone out there could enlighten me on this car."

# 길이가 1~2인 단어들을 정규 표현식을 이용하여 삭제
shortword = re.compile(r'\W*\b\w{1,2}\b')
print(shortword.sub('', text))

4. 정규 표현식

언어낸 코퍼스에서 노이즈 데이터의 특징을 파악했다면 정규 표현식으로 이를 제거할 수 있다. 예를 들어, HTML 문서로부터 가져온 코퍼스는
문서 곳곳에 HTML 태그가 있다. 따라서, 문서 내에 반복적으로 등장하는 글자를 규칙기반으로 제거할 수 있다.

 

728x90

단어 토큰화

토큰을 만드는 기준에 따라서 명칭이 조금씩 다른데 기준이 단어면 word tokenization이라고 한다.
여기서 단어의 범위는 단어구, 의미를 갖는 문자열까지 확장될 수 있다.

구두점 : 마침표(.), 콤마(,), 물음표(?), 느낌표(!) 등과 같은 기호이다.

토큰화 작업은 단순히 구두점이나 특수문자를 제거하는 정제(cleaning) 과정으로는 해결되지 않는다.
구두점이나 특수문자를 제거하면 토큰의 의미를 잃어버리는 경우도 존재한다.

  • 영어의 경우 띄어쓰기(whitespace) 단위로 자르면 단어단위 구분이 되지만 한국어는 그렇지 안다

토큰화의 기준

토큰화를 하다보면, 예상하지 못하는 경우가 있어서 애매한 경우가 발생한다. 이럴때는 데이터 활용 목적을 고려해서
목적에 방해가 되지 않는 기준을 선택하면 된다. 예를 들어, Jone's와 Don't에서 어포스트로피(')를 처리하는 경우가 있다.
그 중 word_tokenize와 WordPunctTokenizer를 사용해서 아포스트로피를 어떻게 처리하는지 확인하자.

word_tokenize 실습

우선 punkt를 다운로드 받는다

import nltk
nltk.download("punkt")

필요한 라이브러리 import

from nltk.tokenize import word_tokenize
from nltk.tokenize import WordPunctTokenizer
from tensorflow.keras.preprocessing.text import text_to_word_sequence
print('단어 토큰화1 :',word_tokenize("on't be fooled by the dark sounding name, Mr. Jone's Orphanage is as cheery as cheery goes for a pastry shop."))

위 코드를 실행하면 결과는 아래와 같이 나온다.

단어 토큰화1 : ['Do', "n't", 'be', 'fooled', 'by', 'the', 'dark', 'sounding', 'name', ',', 'Mr.', 'Jone', "'s", 'Orphanage', 'is', 'as', 'cheery', 'as', 'cheery', 'goes', 'for', 'a', 'pastry', 'shop', '.']

Don't를 Do와 n't로, jone's를 jone과 's로 구분한걸 확인할 수 있다.

WordPunctTokenizer 실습

print('단어 토큰화2 :',WordPunctTokenizer().tokenize("Don't be fooled by the dark sounding name, Mr. Jone's Orphanage is as cheery as cheery goes for a pastry shop."))
단어 토큰화2 : ['Don', "'", 't', 'be', 'fooled', 'by', 'the', 'dark', 'sounding', 'name', ',', 'Mr', '.', 'Jone', "'", 's', 'Orphanage', 'is', 'as', 'cheery', 'as', 'cheery', 'goes', 'for', 'a', 'pastry', 'shop', '.']

WordPunctTokenizer는 구두점을 별도로 분류하는 특징을 갖고 있기 때문에, 앞서 확인했던 word_tokenize와는 달리 Don't를 Don과 '와 t로 분리하였으며, 이와 마찬가지로 Jone's를 Jone과 '와 s로 분리.

text_to_word_sequence

keras도 토큰화 도구 text_to_word_sequence를 지원합니다.

print('단어 토큰화3 :',text_to_word_sequence("Don't be fooled by the dark sounding name, Mr. Jone's Orphanage is as cheery as cheery goes for a pastry shop."))
단어 토큰화3: ["don't", 'be', 'fooled', 'by', 'the', 'dark', 'sounding', 'name', 'mr', "jone's", 'orphanage', 'is', 'as', 'cheery', 'as', 'cheery', 'goes', 'for', 'a', 'pastry', 'shop']

결과는 다음과 같다. 결과를 소문자로 전환하고 마침표, 콤마, 구두점을 제거한다. 하지만 어포스트로피(')는 유지한다.

토큰화에서 고려할 사항

무식하게 corpus에서 구두점 지우고 공백 기준으로 토큰화하고 하면 안된다.

1) 구두점, 특수문자 단순 제거 X

  • 마침표(.)의 경우는 문장의 끝을 의미하기 때문에 문장의 경계를 아는데 도움이 된다. 따라서, 제외하면 안된다.
  • 단어 자체에 구두점이 포함된 경우가 있다. 예를 들어 Ph.d나 AT&T의 경우. 또, 특수문자 $와 /의 경우 각각
    $40.55에서는 돈의 의미, 23/02/23에서는 날짜의 의미를 가진다. 이 경우에는 23/02/23을 하나의 단위로 봐야하기 때문에 분류하는 것이
    불필요하다.

2) 줄임말, 단어내 띄어쓰기

  • 영어권 언어에서는 (')가 단어를 압축하는 역할을 가진다. 예를 들어 don't는 do not을 압축한 것이다.
    여기서 t를 접어(clitic)이라고 한다. 즉, 단어가 줄임말로 쓰일때 생기는 형태이다.
  • New York의 경우 단어 중간에 띄어쓰기가 포함된다. 이 단어는 하나의 토큰으로 보는것이 타당하므로 이런 단어를 하나로 보는 능력도 필요하다

3) 표준 토큰화 예제 (Penn Treebank Tokenization)

표준으로 쓰이고 있는 토큰화 방법중 하나인 Penn Treebank Tokenization은
규칙 1. 하이픈으로 구성된 단어는 하나로 유지한다
규칙 2. doesn't와 같이 어포스트로피로 접어가 함께하는 단어는 분리한다

from nltk.tokenize import TreebankWordTokenizer

tokenizer = TreebankWordTokenizer()

text = "Starting a home-based restaurant may be an ideal. it doesn't have a food chain or restaurant of their own."
print("트리뱅크 워드 토크나이저 : ", tokenizer.tokenize(text))

결과는 아래와 같다.

트리뱅크 워드 토크나이저 :  ['Starting', 'a', 'home-based', 'restaurant', 'may', 'be', 'an', 'ideal.', 'it', 'does', "n't", 'have', 'a', 'food', 'chain', 'or', 'restaurant', 'of', 'their', 'own', '.']

결과를 보면, 각각 규칙1과 규칙2에 따라서 home-based는 하나의 토큰으로 취급하고 있으며, dosen't의 경우 does와 n't는 분리.

문장 토큰화(Sentence Tokenization)

문장 토큰화는 토큰의 단위가 문장인 경우 즉, 코퍼스 내에서 문장 단위로 구분하는 작업으로 문장 분류(sentence segmentation)라고도 부른다.
문장 단위로 분류할때 마침표(.), 느낌표(!), 물음표(?)로 하면 될거같지만 !나 ?는 문장의 구분을 위한 구분자 역할을 하지만 마침표는 문장의 끝이 아니더라고 등장할 수 있다.

아래의 두 예시 문장을 살펴보자.
EX1) IP 192.168.56.31 서버에 들어가서 로그 파일 저장해서 aaa@gmail.com로 결과 좀 보내줘. 그 후 점심 먹으러 가자.
EX2) Since I'm actively looking for Ph.D. students, I get the same question a dozen times every year.

두 문장 모두 마침표 기준을 토큰화하면 제대로 이뤄지지 않는다.
영어 문장의 토큰화를 수행하는 sent_tokenize로 문장 토큰화를 실습해보자

sent_tokenize 실습

from nltk.tokenize import sent_tokenize

text = "His barber kept his word. But keeping such a huge secret to himself was driving him crazy. Finally, the barber went up a mountain and almost to the edge of a cliff. He dug a hole in the midst of some reeds. He looked about, to make sure no one was near."
print('문장 토큰화1 :',sent_tokenize(text))

결과는 아래와 같다

문장 토큰화1 : ['His barber kept his word.', 'But keeping such a huge secret to himself was driving him crazy.', 'Finally, the barber went up a mountain and almost to the edge of a cliff.', 'He dug a hole in the midst of some reeds.', 'He looked about, to make sure no one was near.']

문장 중간에 마침표가 여러개 등장하는 경우에는 어떨까?

text = "I am actively looking for Ph.D. students. and you are a Ph.D student."
print('문장 토큰화2 :',sent_tokenize(text))

결과를 보면 아주 잘 분리되고 있다.

문장 토큰화2 : ['I am actively looking for Ph.D. students.', 'and you are a Ph.D student.']

kss

한국어에 대한 문장 토큰화 도구도 존재한다.
우선 kss 라이브러리를 설치하자. 생각보다 kss를 설치하는데 오래 결린다.

pip install kss
import kss

text = '딥 러닝 자연어 처리가 재미있기는 합니다. 그런데 문제는 영어보다 한국어로 할 때 너무 어렵습니다. 이제 해보면 알걸요?'
print('한국어 문장 토큰화 :',kss.split_sentences(text))

결과는 아주 훌륭하다. 근데 어떤 이유에서인지 시간이 오래결렸고 interrupt하니까 완료되었다(?)

한국어 문장 토큰화 : ['딥 러닝 자연어 처리가 재미있기는 합니다.', '그런데 문제는 영어보다 한국어로 할 때 너무 어렵습니다.', '이제 해보면 알걸요?']

한국어 토큰화의 어려움

한국어는 조사, 어미등을 붙여서 언어를 만드는 교착어라 토큰화가 어렵다. 영어는 그냥 whitespace 기준으로 해도 얼추 잘 먹힌다.
띄어쓰기의 단위를 어절이라고하는데 한국어는 어절 토큰화와 단어 토큰화가 다르다.

1) 교착어의 특성

한국어에서는 조사가 띄어쓰기 없이 붙는다. 예를 들어서 그가, 그는에서 '그'라는 단어에 '가'와 '는'이 띄어쓰기 없이 붙는다.
따라서, 한국어 nlp에서는 조사를 분리할 필요가 있다.
한국어 토큰화에서는 형태소(morpheme)의 개념이 중요한데 가장 작은 말의 단위를 뜻한다. 형태소에는 자립 형태소와 의존 형태소가 있다.

  • 자립 형태소 : 접사, 어미, 조사와 상관없이 자립하여 사용할 수 있는 형태소. 그 자체로 단어가 된다. 체언(명사, 대명사, 수사), 수식언(관형사, 부사), 감탄사 등이 있다.
  • 의존 형태소 : 다른 형태소와 결합하여 사용되는 형태소. 접사, 어미, 조사, 어간을 말한다.

예를 들어, 아버지가 방에 들어가신다. 라는 문장을 토큰화하면 단어 토큰화를 진행하면 '아버지가', '방에', '들어가신다' 로 토큰화가 된다.
형태소 단위로 분해하면 다음과 같다

  • 자립 형태소 : 에디, 책
  • 의존 형태소 : -가, -을, 읽-,-었,-다
    여기서 살펴볼 수 있는 점은 영어와 같이 단어 토큰화를 진행하려면 어절 토큰화가 아니라 형태소 토큰화를 수행해야한다는 점이다.

2) 한국어는 띄어쓰기가 잘 지켜지지 않는다

한국어의 경우 띄어쓰기를 안해도 말을 이해하는게 크게 어렵지 않다. 이는 한국어(모아쓰기 방식)와 영어(풀어쓰기 방식)의 언어적 특성의 차이에 기인한다. 그렇게 때문에 코퍼스에 잘못된 띄어쓰기로 저장된 텍스트가 많다. 이 때문에 자연어 처리가 어려워졌다.

품사 태깅

단어의 표기는 같지만 품사에 따라서 의미가 바뀌는 경우가 있다. 예를 들어, 감은 명사로 감나무의 열매이지만, 접사로는 느낌이라는 뜻이다.
즉, 단어의 의미를 제대로 파악하려면 품사를 파악해야하고 단어가 어떤 품사로 쓰였는지 보는 것이 주요 지표가 될 수 있다.
단어 토큰화 과정에서 각 단어가 어떤 품사로 쓰였는지 구분하는 작업을 품사 태깅(part-of-speeech tagging)이라 한다.

품사 태깅 실습 NLTK, KoNLPy

nltk에서는 penn Treebank POS Tags 라는 기준으로 품사를 태깅한다.

from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag

text = "I am actively looking for Ph.D. students. and you are a Ph.D. student."
tokenized_sentence = word_tokenize(text)

print('단어 토큰화 :',tokenized_sentence)
print('품사 태깅 :',pos_tag(tokenized_sentence))
단어 토큰화 : ['I', 'am', 'actively', 'looking', 'for', 'Ph.D.', 'students', '.', 'and', 'you', 'are', 'a', 'Ph.D.', 'student', '.']
품사 태깅 : [('I', 'PRP'), ('am', 'VBP'), ('actively', 'RB'), ('looking', 'VBG'), ('for', 'IN'), ('Ph.D.', 'NNP'), ('students', 'NNS'), ('.', '.'), ('and', 'CC'), ('you', 'PRP'), ('are', 'VBP'), ('a', 'DT'), ('Ph.D.', 'NNP'), ('student', 'NN'), ('.', '.')]

여기서 영어 문장에 대해서 토큰화를 수행한 결과를 입력으로 품사 태깅을 수행함.
Penn Treebank POG Tags에서 PRP는 인칭 대명사, VBP는 동사, RB는 부사, VBG는 현재부사, IN은 전치사, NNP는 고유 명사, NNS는 복수형 명사, CC는 접속사, DT는 관사를 의미함.

한국어 자연어 처리를 위해서는 KoNLPy라는 파이썬 패키지를 사용할 수 있다.
코엔엘파이를 통해서 사용할 수 있는 형태소 분석기로 Okt(Open Korea Text), 메캅(Mecab), 코모란(Komoran), 한나눔(Hannanum), 꼬꼬마(Kkma)가 있다.

Okt 실습

from konlpy.tag import Okt
from konlpy.tag import Kkma

okt = Okt()
kkma = Kkma()

print('OKT 형태소 분석 :',okt.morphs("열심히 코딩한 당신, 연휴에는 여행을 가봐요"))
print('OKT 품사 태깅 :',okt.pos("열심히 코딩한 당신, 연휴에는 여행을 가봐요"))
print('OKT 명사 추출 :',okt.nouns("열심히 코딩한 당신, 연휴에는 여행을 가봐요")) 

morphs는 형태소 추출, pos는 품사 태깅, nouns는 명사 추출을 수행한다.

OKT 형태소 분석 : ['열심히', '코딩', '한', '당신', ',', '연휴', '에는', '여행', '을', '가봐요']
OKT 품사 태깅 : [('열심히', 'Adverb'), ('코딩', 'Noun'), ('한', 'Josa'), ('당신', 'Noun'), (',', 'Punctuation'), ('연휴', 'Noun'), ('에는', 'Josa'), ('여행', 'Noun'), ('을', 'Josa'), ('가봐요', 'Verb')]
OKT 명사 추출 : ['코딩', '당신', '연휴', '여행']

결과를 살펴보면 기본적으로 조사를 분리하고 있다.

Kkma 실습

print('꼬꼬마 형태소 분석 :',kkma.morphs("열심히 코딩한 당신, 연휴에는 여행을 가봐요"))
print('꼬꼬마 품사 태깅 :',kkma.pos("열심히 코딩한 당신, 연휴에는 여행을 가봐요"))
print('꼬꼬마 명사 추출 :',kkma.nouns("열심히 코딩한 당신, 연휴에는 여행을 가봐요"))  

결과는 아래와 같다.

꼬꼬마 형태소 분석 : ['열심히', '코딩', '하', 'ㄴ', '당신', ',', '연휴', '에', '는', '여행', '을', '가보', '아요']
꼬꼬마 품사 태깅 : [('열심히', 'MAG'), ('코딩', 'NNG'), ('하', 'XSV'), ('ㄴ', 'ETD'), ('당신', 'NP'), (',', 'SP'), ('연휴', 'NNG'), ('에', 'JKM'), ('는', 'JX'), ('여행', 'NNG'), ('을', 'JKO'), ('가보', 'VV'), ('아요', 'EFN')]
꼬꼬마 명사 추출 : ['코딩', '당신', '연휴', '여행']

결과의 형태소 분석 결과가 okt와 다른데 용도에 맞게 형태소 분석기를 골라 사용하면 된다.
속도를 중시하면 mecab을 사용할 수 있다.

Reference

https://wikidocs.net/21698

+ Recent posts