2장 텍스트 전처리

히나·2024년 5월 26일

들어가기에 앞서

해당 글은 "파이썬 텍스트 마이닝 완벽 가이드"를 기반으로 작성되었습니다.

2.1 텍스트 전처리의 개념

자연어 처리(NLP)는 컴퓨터와 인간 언어 간의 상호 작용과 관련된 언어학, 컴퓨터 과학 및 인공 지능의 하위분야로, 특히 대량의 자연어 처리를 처리하고 분석할 수 있도록 컴퓨터를 프로그래밍하는 방법을 말한다. -Wikipedia

위 인용문은 저자가 영문 위키피디아의 NLP에 대한 설명을 구글 번역기로 번역하고 살짝 다듬은 글입니다. 이와 같은 기계번역도 자연어 처리의 한 분야로 볼 수 있습니다.

위의 위키피디아의 정의를 조금 풀어서 설명한다면, 자연어 처리는 자연어로 쓰여진 글을 전처리하는 준비단계와, 전처리된 결과를 컴퓨터가 다루고 이해할 수 있는 형태로 변환하는 단계, 그리고 변환된 형태를 이용해 다양한 분석을 수행하는 단계로 나누어 생각할 수 있습니다. 텍스트의 전처리는 일반적으로 공통적 과정을 거치며, 컴퓨터가 다룰 수 있는 형태로 변환하는 작업은 분석의 목적과 방법론에 따라 달라집니다.

2.1.1 왜 전처리가 필요한가?

그러면 왜 전처리가 필요할까요? 우선 다음의 표를 봅시다

<프로그래밍 언어와 인간이 문서를 이해하는 방식>
기반정의하는 방식이해하는 방식
프로그래맹 언어기호의 순차수열문자단위로 저장되고 이해됨
인간사용된 단어들의 순차수열각 단어를 이해하고, 단어들의 순서에 따라 의미를 이해

위의 표는 프로그래밍 언어와 인간이 문서를 어떻게 정의하고 이해하는 지 나타내고 있습니다. 이를 통해, 컴퓨터에게 어떤 문장을 이해시키고 싶다면 하나의 문자열로 이루어진 문장/문서를 단어단위로 나눈 후, 단어들의 리스트 형태로 변환해주어야 함을 도출할 수 있습니다. 또한 이 과정에서는 쓸모모없다고 생각되는 문자는 제거해야합니다.(노이즈 제거)

2.1.2 전처리의 단계

텍스트 전처리는 '주어진 텍스트에서 1)노이즈와 같이 불필요한 부분을 제거하고, 2)문장을 표준 단어로 분리한 후, 3)각 단어의 품사를 파악하는 것'까지를 의미합니다.

전처리의 단계를 정리하다면 다음과 같습니다.

  1. 정제: 분석에 필요한 노이즈를 제거하는 작업을 뜻합니다. 보통 노이즈의 제거는 토큰화 이전에 이루어지나, 토큰화 이후에도 필요한 경우 정제 작업은 지속적으로 이루어집니다. ex. 불용어 제거는 토큰화 이후에도 틈틈히 필요한 시점에 수행합니다.
  2. 토큰화: 주어진 텍스트를 원하는 단위로 나누는 작업을 뜻합니다. 일반적으로 토큰화를 말하면 단어 토큰화라고 하며, 원하는 단위에 따라 문장 토큰화, 단어 토큰화로 나뉩니다.
  3. 정규화: 같은 의미를 가진 동일한 단어임에도 불구하고 다른 형태로 쓰인 단어들을 통일시켜 표준 단어로 만드는 작업을 뜻합니다. 정규화는 방법에 따라 어간 추출표제어 추출로 나뉩니다.
  4. 품사 태깅: 품사 태깅은 앞서 토큰화한 단어에 대해 품사를 파악해 부착하는 것을 의미합니다. 해당 작업을 필요로 하는 이유는 같은 언어도 문맥에 따라 의미와 품사가 바뀌기 때문입니다. 따라서 정확한 품사를 알기 위해서는 문맥 파악을 필요로 합니다.

2.2 토큰화

NLTK는 교육용으로 개발된 자연어 처리 및 문서 분석용 파이썬 패키지로, WordNet을 비롯해 자연어 처리를 지원하는 다양한 라이브러리 문서(말뭉치) 그리고 에제들을 제공한다고 합니다.

실습 들어가기 전 환경 설정하기

해당 실습은 윈도우의 wsl에서 진행하였다. wsl 설치 및 재설치 방법은 다음을 참고하자.

  1. pip3 설치하기
sudo apt-get install python3
sudo apt-get install python3-pip

두 명령어가 작동하지 않을 경우 다음을 참고하자

  1. NLTK 라이브러리 설치하기
pip3 install nltk
  1. vscode에 jupyter notebook 설정하기
    vscode에서 jupyter extention 추가
    확장프로그램에서 jupyter만 쳐도 관련 확장프로그램이 나온다. 해당 확장 프로그램을 설치하도록 하자.

간단한 파이썬 코드
위와 같이 간단한 파이썬 코드를 작성하고 실행 코어를 kernel->python3만 설정해도 알아서 관련 커널과 패키지를 설치하고 업데이트 해준다.

  1. 필요한 nltk 라이브러리 설치하기
    필요한 nltk 라이브러리 다운로드

2.2.1 문장 토큰화

토큰화는 주어진 텍스트를 원하는 단위(토큰)로 나누는 작업을 말합니다. 먼저 나누려는 단위가 문장인 경우에 사용하는 문장 토큰화를 알아봅시다.

문장 토큰화는 여러 문장으로 이루어진 텍스트를 각 문장으로 나누는 것으로 nltk의 sent_tokenize를 사용합니다.

실행 예제는 다음과 같습니다.

para = "Hello everyone. It's good to see you. Let's start our text mining class!"

from nltk.tokenize import sent_tokenize

print(sent_tokenize(para))

실행 결과

['Hello everyone.', "It's good to see you.", "Let's start our text mining class!"]

sent_tokenize()에 para를 인수로 주고 실행한 결과를 출력했습니다. 출력된 결과를 보면 각 문장을 문자열로 갖는 리스트임을 알 수 있습니다.

내부적으로 sent_tokenize는 영어 학습 데이터에 대해 사전학습된 모델을 사용해 토큰화 합니다. 다른 언어에 대해 문장 토큰화를 하기 위해서는 다음과 같이 사전학습된 모델을 지정해 불러올 수 있습니다.

다음은 프랑스어를 학습한 모델을 사용하는 예시입니다.

paragraph_french = """3e t'ai demand si tu m'aimais bien, Tu m'a r pondu non.
Je t'ai demand si j' tais jolie, Tu m'a r pondu non.
Je t'ai demand si j' tai dans ton coeur, T니 m'a r pondu non."""

import nltk.data
tokenizer = nltk.data.load('tokenizers/punkt/french.pickle')
print(tokenizer.tokenize(paragraph_french))

실행 결과

["3e t'ai demand si tu m'aimais bien, Tu m'a r pondu non.", "Je t'ai demand si j' tais jolie, Tu m'a r pondu non.", "Je t'ai demand si j' tai dans ton coeur, T니 m'a r pondu non."]

NLTK에는 한글에 대해 사전학습된 모델이 아직 없다고 합니다. 그러나 문장 토큰화는 각 문장의 끝에 있는 마침표 등을 기준으로 분리하도록 학습되어 있으므로, 영어로 학습된 모델도 잘 분리할 수 있음을 에측할 수 있습니다.

한글에 대한 작동 여부를 알아봅시다.

para_kor = "안녕하세요, 여러분. 만나서 반갑습니다. 이제 텍스트마이닝 클래스를 시작해봅시다!"
# 한국어에 대해서도 sentence tokenizer는 잘 작동함
print(sent_tokenize(para_kor))

실행 결과

['안녕하세요, 여러분.', '만나서 반갑습니다.', '이제 텍스트마이닝 클래스를 시작해봅시다!']

잘 작동하는 것을 알 수 있습니다.

2.2.2 단어 토큰화

앞에서 서술했듯, 일반적으로 토큰화라고 하면 단어 토큰화를 의미합니다. NLTK에서는 word_tokenize()로 단어 토큰화를 할 수 있습니다. 단어 토큰화를 하기 위해 문장 토큰화가 우선 진행되어야할 것 같지만 아닙니다. 바로 단어 토큰화를 진행하면 됩니다.

from nltk.tokenize import word_tokenize
# 주어진 text를 word 단위로 tokenize함
print(word_tokenize(para))

실행 결과

['Hello', 'everyone', '.', 'It', "'s", 'good', 'to', 'see', 'you', '.', 'Let', "'s", 'start', 'our', 'text', 'mining', 'class', '!']

위 결과를 보면 마침표나 느낌표 등의 기호가 별도의 단어로 분리 되어 있으며, It'sIt's로 두 토큰으로 분리하는 것을 알 수 있습니다. NLTK의 WordPunctTokenizer를 사용할 때 결과가 바뀌는지를 보기 위해 다음을 실행해봅시다.

from nltk.tokenize import WordPunctTokenizer
print(WordPunctTokenizer().tokenize(para))

실행 결과

['Hello', 'everyone', '.', 'It', "'", 's', 'good', 'to', 'see', 'you', '.', 'Let', "'", 's', 'start', 'our', 'text', 'mining', 'class', '!']

word_tokenize와는 달리 WordPuncTokenizerIt'sit, ', s로 구분함을 알 수 있습니다. 이는 두 토크나이저가 서로 다른 알고리즘에 기반하기 때문입니다.

그렇다면 word_tokenize를 한글에서도 적용할 수 있을까요? 한 번 코드를 실행해봅시다.

print(word_tokenize(para_kor))

실행 결과

['안녕하세요', ',', '여러분', '.', '만나서', '반갑습니다', '.', '이제', '텍스트마이닝', '클래스를', '시작해봅시다', '!']

영어와는 달리 단어 단위로 분리한다고 느껴지지 않습니다. 이는 영어와는 다른 문법 구조에 달려있습니다. 한국어는 모든 단어를 공백으로 구분하는 영어와는 달리, 의미를 이루는 최소 단위가 공백 없이 붙어있는 경우가 많습니다. 따라서 공백을 이용하는 분리만으로는 부족하게 느껴집니다.

따라서 한국어 텍스트를 전확하게 토큰화하기 위해서는 영어와는 다른 방법을 필요로 합니다. 공백과 같은 단어를 구분해 주는 것들을 단어 경계(word boundary)라고 합니다. 공백만으로 토큰화가 부족하다면 새로운 방법을 적용하여 단어를 분리해야하며 이를 단어 분할이라고 칭합니다.

2.2.3 정규표현식을 이용한 토큰화

NLTK가 제공하는 함수를 이용해 토큰화를 하면 간편하다는 장점이 있으나, 세밀하게 토큰화하기 어렵다는 단점이 있습니다. 이때 정규표현식을 이용하여 진행한다면 NLTK를 사용하지 않고도 다양한 조건에 따라 토큰화 할 수 있습니다.

파이썬에서 정규표션식을 지원하는 라이브러리는 re입니다.

관련 함수

함수인수예시
findallregex, contextre.findall("abc", "How are you boy?")

정규 표현식 예시

표현식의미
[abc]기본 정규 표현식. 안에 들어가는 것들을 검색할 수 있다.
[0-9]순서가 있는 경우 -를 사용하여 줄여쓸 수 있다.
[\w]\w를 사용하여 대소문자 및 숫자를 모두 포함할 수 있다.
[abc]+특정 문자가 한 번 이상 반복될 경우에 사용한다.
[abc]{n,m}특정 문자가 n~m회 반복된 문자열을 찾아내기 위해 사용한다.

NLTK에서는 정규표현식을 사용하는 토크나이저를 RegexpTokenizer로 제공한다.

from nltk.tokenize import RegexpTokenizer
# regular expression(정규식)을 이용한 tokenizer
# 단어 단위로 tokeniz은 \w:문자나 숫자를 의미. 즉 문자나 숫자 혹은 |가 반복되는 것을 찾아냄
tokenizer = RegexpTokenizer("[\w']+")
# can,t를 하나의 단어로 인식
print(tokenizer.tokenize("Sorry, I can't go there."))

실행 결과

['Sorry', 'I', "can't", 'go', 'there']

위에서는 정규표현식으로 [\w']+를 사용했습니다. 이는 문자, 숫자, 공백 문자 외에 '까지 포함해 단어를 구분합니다. 즉 그 외의 문자는 단어를 구분하는 단어 경계로 사용됩니다.
결과를 보면 can't가 포함되어 있는데 '를 단어 경계에 포함하고, 3글자 이상의 단어들만 추출하려면 어떻게 해야할까요? 방법은 꽤 단순합니다. [abc]{n,m}의 방식에서 뒤의 숫자를 그냥 비워주면 됩니다.

text1 = "Sorry, I can't go there."
tokenizer = RegexpTokenizer("[\w]{3,}")
print(tokenizer.tokenize(text1.lower()))

실습 결과

['sorry', 'can', 'there']

2.2.4 노이즈와 불용어 제거

정규표현식을 이용한 토큰화 과정을 보면, 그 과정에서 특수문자와 같은 불필요한 문자들, 혹은 노이즈가 삭제된 것을 볼 수 있습니다. 토큰화 과정과 별도로 정규표현식을 이용한 치환을 통해 원하는 패턴의 노이즈를 제거할 수도 있습니다

불용어는 의미 없는 특수문자 등과는 별도로, 실제 사용되는 단어이지만 분석에는 별 필요가 없는 단어들을 말합니다. 보통 불용어는 빈도가 너무 적거나 혹은 반대로 빈도가 너무 많아 별 필요가 없는 단어들 입니다. 그 외에 분석의 목표 관점에서 볼 때 필요 없는 단어들도 존재합니다.

길이가 짧은 단어들(ex. a, I, it...)은 정규표현식을 이용하여 제거할 수 있습니다. 그 외에 특정 단어를 지정하여 불용어 사전을 만들고, 해당 사전을 참조하여 불용어를 삭제할 수 있습니다. NLTK에서는 stopwords라는 라이브러리를 이용하여 언어별 불용어 사전을 제공합니다.

from unittest import result
from nltk.corpus import stopwords
english_stops = set(stopwords.words('english'))

text1 = "Sorry, I couldn't go to movie yesterday."

tokenizer = RegexpTokenizer(r"[\w']+")
tokens = tokenizer.tokenize(text1.lower())

# stopwords를 제외한 단어들만드로 list를 생성
result = [word for word in tokens if word not in english_stops] 

print(result)

실행 결과

['sorry', 'go', 'movie', 'yesterday']

위 결과를 보면 I, couldn't, to가 없어져있음을 알 수 있습니다. 따라서 이 세 단어가 NLTK가 제공하는 영어 불용어 사전에 포함되어있다는 사실이 도출됩니다.

한 번 불용어 사전을 출력해볼까요?

print(english_stopwords)

실행 결과

{'how', 'their', 'why', 'i', (중간 생략) 'he', 'at', 'her', 'wouldn'}

불용어 사전을 이용한 불용어 제거 방법을 이해했으니 자신만의 불용어 사전을 만들어 제거해봅시다.

책에는 불용어 사전에 'go'가 포함되어있으나, 실습 중에는 뺐습니다.

my_stopword = ['i', 'to' ]

result = [word for word in tokens if word not in english_stops] 
print(result)

실행 결과

['sorry', 'go', 'movie', 'yesterday']

2.3 정규화

정규화같은 의미를 가진 동일한 단어이지만, 다른 형태로 쓰여진 단어들을 통일해 표준 단어로 만드는 작업을 의미합니다. 정규화는 방법에 따라 어간 추출표제어 추출로 나뉩니다.

2.3.1 어간 추출

어간 추출어형이 변환된 단어로부터 접사 등을 제거하고, 그 단어의 어간을 분리해내는 작업을 말합니다.

잠시 단어의 뜻을 파악하고 지나갑시다.

단어
어형단어의 형태
어간어형 변화에서 변화하지 않는 부분
어형 변화어떤 단어가 동일한 어간을 가지고 동일한 품사를 유지하며,어미를 변화시켜 문법적 기능도 변화하는 현상
통시적 어형 변화시간의 경과에 따라 단어의 형태가 변화
공시적 어형 변화음소적 배합관계나 활용을 비롯한 분법적 현상에 따른 변화

영어와 한국어는 원리와 구조가 다르므로 어간 추출도 달라질 수 밖에 없습니다. 영어에 대한 어간 추출 알고리즘에는 포터 스테머(Porter Stemmer), 랭카스터 스테머(Lancaster Stemmer) 등이 있습니다.

포터 스테머: 영어분야에서는 사실상의 표준이 된 스테밍 알고리즘입니다. 다음의 코드는 NLTK의 포터 스테머를 사용해 어간 추출을 하는 예시 입니다.

from nltk.stem import PorterStemmer
stemmer = PorterStemmer()
print(stemmer.stem('cooking'), stemmer.stem('cookery'), stemmer.stem('cookbooks') )

실행 결과

cook cookeri cookbook

cookerycookeri가 된 것처럼 스테머 알고리즘은 단어가 편형되는 규칙을 사용하여 원형을 찾으므로, 그 결과가 항상 올바른 단어가 되지는 않습니다. 그러나 변환된 단어가 동일한 형태로 변환되었으므로 분석의 의도를 충족시킬 수 있습니다.

다음은 토큰화와 결합하여 어간 추출을 하는 예시입니다.

from nltk.tokenize import word_tokenize

para = "Hello everyone. It's good to see you. Let's start our text mining class!"
tokens = word_tokenize(para)
print(tokens)
result = [stemmer.stem(token) for token in tokens]
print(result)

실행 결과

['Hello', 'everyone', '.', 'It', "'s", 'good', 'to', 'see', 'you', '.', 'Let', "'s", 'start', 'our', 'text', 'mining', 'class', '!']
['hello', 'everyon', '.', 'it', "'s", 'good', 'to', 'see', 'you', '.', 'let', "'s", 'start', 'our', 'text', 'mine', 'class', '!']

랭카스터 스테머: 포터 스테머와는 다른 알고리즘을 사용합니다.

위와 같은 예시로 스테밍을 진행해봅시다.

from nltk.stem import LancasterStemmer
stemmer = LancasterStemmer()
print(stemmer.stem('cooking'), stemmer.stem('cookery'), stemmer.stem('cookbooks') )

실행 결과

cook cookery cookbook

cookery에 대한 결과물이 달라짐을 알 수 있습니다.

2.3.2 표제어 추출

표제어 추출은 의미적 관점에서 단어의 기본형을 찾는 작업이라고 할 수 있습니다. 따라서 사전을 이용하여 사전에 정의된 기본형으로 변환합니다.

영어에 대한 표제어 추출기로, WordNet을 이용한 WordNetLemmatizer가 잘 알려져 있다고 합니다.

from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
print(lemmatizer.lemmatize('cooking'))
print(lemmatizer.lemmatize('cooking', pos='v'))
print(lemmatizer.lemmatize('cookery'))
print(lemmatizer.lemmatize('cookbook'))

실행 결과

cooking
cook
cookery
cookbook

스태머와는 다른 결과를 볼 수 있습니다. WordNetLemmatizer는 품사를 따로 지정하지 않으면 cooking에 대한 기본형으로 동일한 cooking을 반환합니다. 이는 사전에 요리라는 뜻으로 cooking이라는 명사가 존재하기 때문입니다. 그러나 품사를 나타내는 매개변수 pos에 동사를 의미하는 인수 'v'를 넘겨주면 cook을 반환했음을 볼 수 있습니다.

위의 결과를 볼 때, 표제어 추출은 사전에 있는 단어의 기본형을 반환하며, 이를 위해 품사가 필요할 수도 있다는 사실을 알 수 있습니다. 따라서 정확한 기본형을 알기 위해서는 품사를 알아야 하는데, 품사는 문장의 문맥을 파악해야만 알 수 있습니다.

from nltk.stem import PorterStemmer

stemmer = PorterStemmer()
print('stemming result:', stemmer.stem('believes'))
print('lemmatizing result:', lemmatizer.lemmatize('believes'))
print('lemmatizing result:', lemmatizer.lemmatize('believes', pos='v'))

실행 결과

stemming result: believ
lemmatizing result: belief
lemmatizing result: believe

2.4 품사 태깅

토큰화와 정규화 과정을 거쳐서 나온 각 결과를 보통은 형태소라고 합니다. 토큰화와 정규화 과정을 통해서 이렇게 형태소까지 분리할 것인지는 전적으로 분석을 수행하는 사람의 판단에 달려있습니다. 형태소까지 분리하지 않아도 좋은 결과를 얻을 수 있따면 굳이 하지 않아도 됩니다.

2.4.1 품사의 이해

우리가 주어진 텍스트를 분리할 때, 낱말까지 하는 것이 좋은지 아니면 형태소까지 하는 것이 좋은지는 전적으로 최종적으로 분석하고자 하는 내용과 성능에 달려있습니다.

품사 태깅은 형태소에 대해 품사를 파악해 부착하는 작업을 말합니다.

공용 품사 태그 집합

품사 태그는 언어나 학자에 따라 다르게 정의되는 경우가 많습니다. 다음 표는 다양한 언어에서 공통 되는 품사 태그를 나타낸 것으로, NLTK에서 사용하는 간소화된 태그 세트입니다. 내용을 보면 한국어의 품사와는 차이가 있습니다.

아래의 표는 영어를 비롯한 외국어를 다룰 때 참고하면 되며, 공용 품사 태그 집합도 연구하는 주체에 따라 다르게 정의되므로 반드시 표준이라고 생각할 필요는 없습니다.

태그
ADJadjectivenew, good, high
ADPadpositonon, of, at, with
ADVadverbreally, already
CONJconjunctionand, or, if
DETdeterminer, articlea, some, most
NOUNnounyear, home, costs
NUMnumeral1991, fourth
PRTparticleat, on, out, over, per
PRONpronounhe, its, her, I, us
VERBverbis, say
.punctuation marks. , ; !
Xothersersatz, esprit, dunno

펜 트리뱅크 태그 집합

NLTK는 간소화된 태그 집합 외에 펜 트리뱅크 태그 집합을 제공합니다. 이 태그 집합은 훨씬 세분화된 품사 분류를 사용합니다.

TagDescription
CCCoordinating conjunction
CDCardinal number
DTDeterminer
EXExistential there
FWForeign word
INPreposition or subordinating conjunction
JJAdjective
JJRAdjective, comparative
JJSAdjective, superlative
LSList item marker
MDModal
NNNoun, singular or mass
NNSNoun, plural
NNPProper noun, singular
NNPSProper noun, plural
PDTPredeterminer
POSPossessive ending
PRPPersonal pronoun
PRP$Possessive pronoun
RBAdverb
RBRAdverb, comparative
RBSAdverb, superlative
RPParticle
SYMSymbol
TOto
UHInterjection
VBVerb, base form
VBDVerb, past tense
VBGVerb, gerund or present participle
VBNVerb, past participle
VBPVerb, non-3rd person singular present
VBZVerb, 3rd person singular present
WDTWh-determiner
WPWh-pronoun
WP$Possessive wh-pronoun
WRBWh-adverb

2.4.2 NLTK를 활용한 품사 태깅

실제 품사 태깅을 하는 것은 매우 쉽습니다. 영어로 된 텍스트에 대해 품사 태깅을 하고자 한다면 지금까지와 마찬가지로 NLTK를 쓰는 것이 가장 편합니다.

nltk.pos_tag()는 토큰화된 결과에 대해 품사를 태깅해 (단어, 품사)로 구성된 튜플의 리스트로 품사 태깅 결과를 반환해줍니다.

import nltk
from nltk.tokenize import word_tokenize

tokens = word_tokenize("Hello everyone. It's good to see you. Let's start our text mining class!")
print(nltk.pos_tag(tokens))

실행 결과

[('Hello', 'NNP'), ('everyone', 'NN'), ('.', '.'), ('It', 'PRP'), ("'s", 'VBZ'), ('good', 'JJ'), ('to', 'TO'), ('see', 'VB'), ('you', 'PRP'), ('.', '.'), ('Let', 'VB'), ("'s", 'POS'), ('start', 'VB'), ('our', 'PRP$'), ('text', 'NN'), ('mining', 'NN'), ('class', 'NN'), ('!', '.')]

NLTK는 펜 트리뱅크 태그 집합을 사용합니다. 약어를 확인하기 위해서는 nltk.help.upenn_target()를 사용하면 됩니다.

import nltk

nltk.download('tagsets')
nltk.download('universal_tagset')

nltk.help.upenn_tagset('CC')

실행 결과

# 생략
CC: conjunction, coordinating
    & 'n and both but either et for less minus neither nor or plus so
    therefore times v. versus vs. whether yet

원하는 품사의 단어들만 추출
자연어 분석을 할 때에는 상황에 따라 명사만 필요하거나, 특정 품사들만 사용할 때가 있습니다. 특정 품사들의 단어를 추출해봅시다.

my_tag_set = ['NN', 'VB', 'JJ']
my_words = [word for word, tag in nltk.pos_tag(tokens) if tag in my_tag_set]
print(my_words)

실행 결과

['everyone', 'good', 'see', 'Let', 'start', 'text', 'mining', 'class']

2.4.3 한글 형태소 분석과 품사 태깅

형태소 분석
영어에서는 우리말의 형태소에 해당하는 것이 공백으로 분리된 단어와 거의 일치해서 토큰화 과정이 비교적 쉬웠지만, 여러 형태소가 합쳐져 하나의 어절의 되는 경우가 많아 공백을 기준으로 분리할 수 없다는 문제가 있다.

토큰화를 할 때 음절이나, 단어 단위가 아닌 형태소 단위로 하는 이유는 무엇일까요? 결국 우리가 알고 싶은 것은 문장의 의미입니다. 따라서 토큰화는 의미 단위로 이루어져야 하는 것이 맞기 때문입니다.

품사 태깅
한국어의 품사 체계는 당연히 영어와는 차이가 있습니다. 그러나 공통되는 부분도 많습니다.

한글 형태소 분석과 품사 태깅
그렇다면 NLTK로 한국어 문서에 대해서도 품사 태깅이 가능할까요?

sentence = '''
이 헌법시행 당시의 대법원장과 대법원판사가 아닌 법관은 제1항 단서의 규정에 불구하고 이 헌법에 의하여 임명된 것으로 본다.
'''

tokens = word_tokenize(sentence)
print(tokens)
print(nltk.pos_tag(tokens))
'''

tokens = word_tokenize(sentence)
print(tokens)
print(nltk.pos_tag(tokens))

실행 결과

['이', '헌법시행', '당시의', '대법원장과', '대법원판사가', '아닌', '법관은', '제1항', '단서의', '규정에', '불구하고', '이', '헌법에', '의하여', '임명된', '것으로', '본다', '.']
[('이', 'JJ'), ('헌법시행', 'NNP'), ('당시의', 'NNP'), ('대법원장과', 'NNP'), ('대법원판사가', 'NNP'), ('아닌', 'NNP'), ('법관은', 'NNP'), ('제1항', 'NNP'), ('단서의', 'NNP'), ('규정에', 'NNP'), ('불구하고', 'NNP'), ('이', 'NNP'), ('헌법에', 'NNP'), ('의하여', 'NNP'), ('임명된', 'NNP'), ('것으로', 'NNP'), ('본다', 'NNP'), ('.', '.')]

위 결과를 보면 당시의'를 하나의 토큰으로 분리하였으나, 당시의당시로 분리되어야 합니다. 또한 헌법시행을 고유명사로 분리하였는디, 당연히 옳지 않습니다. 따라서 다른 라이브러리를 사용해야 합니다.

파이썬에서 쓸 수 있는 대표적인 형태소 분석 및 품사 태깅 라이브러리는 KoNLPy입니다. KoNLPyHannanum, Kkma, Komoran, Mecab, Twitter 이렇게 다섯 개의 형태소 분석기를 제공합니다.

[참고]성능 평가 그래프
성능 평가 그래프

KoNLPy 설치하기
wsl에서 설치하는 방법은 다음을 참조하자. 맥으로 하다가 오류가 발생해서 다시 wsl로 옮긴 건 비밀이다.
https://blog.naver.com/PostView.naver?blogId=phoenixqq&logNo=222539167484

KoNLPy의 형태소 분석 및 품사 태깅 기능 사용법
제대로 설치되었다면 형채소 분석과 품사 태깅을 수행해봅시다. 아래는 5개의 형태소 분석기 클래스에서 공통으로 지원하는 세 함수를 간략히 설명한 것입니다.

함수설명반환 값
morphs(phrase)주어진 텍스트를 형태소 단위로 분리합니다.형태소의 리스트
nouns(phrase)주어진 텍스트를 형태소 단위로 분리하여 명사만을 반환합니다.텍스트에 있는 명사의 리스트
pos(phrase)주어진 텍스트를 형태소 단위로 분리하고, 품사를 부착해 반환합니다. 토큰화도 같이 진행하여 반환합니다.(단어, 품사)로 된 튜플 리스트

다음은 분석기 twitter를 활용한 실습 코드입니다.

import konlpy
from konlpy.tag import Okt
t = Okt()

print('형태소: ', t.morphs(sentence))
print()
print('명사: ', t.nouns(sentence))

실행 결과

형태소:  ['\n', '이', '헌법', '시행', '당시', '의', '대법원', '장', '과', '대법원판사', '가', '아닌', '법관', '은', '제', '1', '항', '단서', '의', '규정', '에', '불구', '하고', '이', '헌법', '에', '의하여', '임명', '된', '것', '으로', '본다', '.', '\n']

명사:  ['이', '헌법', '시행', '당시', '대법원', '대법원판사', '법관', '제', '항', '단서', '규정', '불구', '이', '헌법', '임명', '것']
profile
git블로그와 티스토리를 떠돌다 벨로그에 정착하다.

0개의 댓글