본문 바로가기
자연어(LLM)

[AI활용 자연어처리 챗봇프로젝트] 토큰화 및 문장처리

by 바다의 공간 2024. 12. 3.

토큰화 및 문장처리

■ 자연어 처리를 위한 설치 패키지는 아래와 같습니다!

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import tensorflow as tf
from tensorflow import keras
import os
import re

  토큰화

- 주어진 코퍼스에서 토큰이라 불리는 단위로 나누는 작업을 토큰화 라고 합니다!

토큰의 단위는 상황에 따라서 다르지만 보통 의미가 있는 단위로 토큰을 정의합니다.

 

단어 토큰화(word Tokenization)

- 주어진 코퍼스(corpus)에서 토큰(token)이라 불리는 단위로 나누는 작업을 토큰화(tokenization)라고 합니다
- 토큰의 단위는 상황에 따라 다르나, 보통 의미가 있는 단위로 토큰을 정의합니다.

-토큰의 기준을 단어(word)로 하는 경우, 단어 토큰화(word tokenization)라고 합니다.

다만, 여기서 단어(word)는 단어 단위 외에도 단어구, 의미를 갖는 문자열로도 간주되기도 합니다.


예를 들어보겠습니다. 아래의 입력으로부터 구두점(punctuation)과 같은 문자는 제외시키는 간단한 단어 토큰화 작업을 해봅시다. 구두점이란 마침표(.), 컴마(,), 물음표(?), 세미콜론(;), 느낌표(!) 등과 같은 기호를 말합니다.


입력: **Time is an illusion. Lunchtime double so!**


이러한 입력으로부터 구두점을 제외시킨 토큰화 작업의 결과는 다음과 같습니다.


출력 : "Time", "is", "an", "illustion", "Lunchtime", "double", "so"
sentence =  "Don't be fooled by the dark sounding name, Mr. Jone's Orphanage is as cheery as cheery goes for a pastry shop."
sentence

영어에서는 ' 어퍼스트로피가 있다는 점!

#  Don't
# Jone's

# Don't
# Don t
# Dont
# Do n't
# Jone's
# Jone s
# Jone
# Jones

# 원하는 결과가 나올수 있는 토큰화 도구 사용해야 한다.

# NLTK 영어 토큰화 도구

 

꼭 어떻게 해야하는 기준이나 답이 있는것은 아니지만 토큰화 라이브러리를 사용하고 내가 원하는

결과값이 나오게끔 사용하면 됩니다. 

 

한번 예시를 볼까용

 

[NLTK 영어 토큰화 도구]

 

 

import nltk
nltk.download('punkt_tab') # 사전다운자료
from nltk.tokenize import word_tokenize
from nltk.tokenize import WordPunctTokenizer

 

이렇게 nltk를 사용하면 토큰화가 됩니다.

 

 

■ word_tokenize 토큰화

word_tokenize(sentence)

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

 

 

 

■ WordPunctTokenizer().tokenize()

WordPunctTokenizer().tokenize(sentence)

['Don',
 "'",
 't',
 'be',
 'fooled',
 'by',
 'the',
 'dark',
 'sounding',
 'name',
 ',',
 'Mr',
 '.',
 'Jone',
 "'",
 's',
 'Orphanage',
 'is',
 'as',
 'cheery',
 'as',
 'cheery',
 'goes',
 'for',
 'a',
 'pastry',
 'shop',
 '.']

 

구두점을 별도로 분리하는 특징이 있습니다.

 

■ 케라스

케라스에서도 기본적으로 제공되는 토큰화가있습니다!

#keras
from tensorflow.keras.preprocessing.text import text_to_word_sequence

print(text_to_word_sequence(sentence))

#["don't", 'be', 'fooled', 'by', 'the', 'dark', 'sounding', 'name', 'mr', "jone's", 'orphanage', 'is', 'as', 'cheery', 'as', 'cheery', 'goes', 'for', 'a', 'pastry', 'shop']

케라스는 마침표, 컴마, 구두점 정도를 제거합니다.

어퍼스트로피는 보존하는것을 확인할 수 있습니다.

 

이렇게 내가 원하는 결과값을 위한 라이브러리를 사용하면 됩니다!

좀 더 연구하고 생각할게 많아진다는점!


 토큰화에서 고려할 사항들

 

구두점과 특수문자 : 구두점과 특수문제를 무조건 제외하는것은 답이 아니다!!

# 예]
#   단어 자체에 구두점 : m.p.h 나 Ph.D 나 AT&T
#   $, / 같은 특수문자 : $45.55 나 01/02/06
#   숫자 사이의 컴마: 123,456,789

  띄어쓰기

줄임말과 단어 내에 띄어쓰기가 있는 경우?

# 예]
#  what're는 what are의 줄임말, we're는 we are의 줄임말
#  New York 이나 rock 'n' roll는 한 단어

New York는 토큰화하면 안되고(띄어있어도 하나의 토큰으로 해야함)

we're는 토큰화를 해서 we are로 해도된다.


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

text = "Starting a home-based restaurant may be an ideal. it doesn't have a food chain or restaurant of their own."
text

from nltk.tokenize import TreebankWordTokenizer

print(TreebankWordTokenizer().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. doesn't 와 같이 어퍼스트로피로 '접어'가 함께 하는 단어는 분리해준다.

위에보면 home-based와 does, n't같은경우를 확인할 수 있습니다.

 


  문장 토큰화(Sentence Tokenization)

- 토큰의 단위가 문장(sentence)일 경우!!

말뭉치가 정제되지않은 상태는 문장 토큰화가 먼저 필요하다!

즉 코퍼스가 되지않은상태는 문장을 쪼개야한다는 말입니다

 

일반적으로 맞지만 꼭! 그렇지많은 않다는것을 알아야합니다. <--!, ?같은경우는 문장구분을 위한 명확한 구분자(boundary)역할을 하지만! 마침표(.)는 그렇지 않기때문입니다.

 

예시

# 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.

만약 1번같은경우는 마침표로해서 토큰화를 하게되면 IP에서도 계속 토큰화가 되고 말이 좀 안되는 형태로 예상됩니다.

2번째같은경우는 마침표기준으로 한다는 가정하에 ph.d.그리고 마지막으로해서 한 문장으로 나오게 됩니다.


  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."
text

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

만약 아래와 같은 문장이라면?

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

sent_tokenize(text)

['I am actively looking for Ph.D. students.', 'and you are a Ph.D student.']
여기서 보면 단순히 그냥 냅다 자르진않은걸 확인할 수 있습니다.조금 더 깊어진?  느낌이 듭니다.

 

 

 

 한국어도 가능합니다!!

 

한국어에 대한 문장 토큰화 도구는 kss(Korea sentence Splitter)을 추천합니다.

코랩에는 없으므로 !pip install kss를 통해서 설치해주어야합니다.

설치는 1~5분 사이? 걸리는거같아요.

import kss

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


kss.split_sentences(text)
WARNING:root:Oh! You have mecab in your environment. Kss will take this as a backend! :D

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

우리나라는 교착어이기떄문에 토큰화하기가 굉장히 어려워요..

한국어는 어절로(띄어쓰기)로 토큰화 하기 힘든이유..!

 

영어는 대체로 한국어보다는 조금 낫습니다.

 

■ 품사태깅(Park-of-speech tagging)

한국어 형태소 분류하는 패키지가있습니다. 

!pip install konlpy

분류기도 여러개를 제공합니다.

from konlpy.tag import Okt #Opne Korea Text
from konlpy.tag import Kkma #꼬꼬마
한글 형태소 분석기 KoNLPy는 다음과 같은 다양한 형태소 분석, 태깅 라이브러리를 파이썬에서 쉽게 사용할 수 있도록 모아놓았다.

Hannanum: 한나눔. KAIST Semantic Web Research Center 개발.
http://semanticweb.kaist.ac.kr/hannanum/

Kkma: 꼬꼬마. 서울대학교 IDS(Intelligent Data Systems) 연구실 개발.
http://kkma.snu.ac.kr/

Komoran: 코모란. Shineware에서 개발.
https://github.com/shin285/KOMORAN

Mecab: 메카브. 일본어용 형태소 분석기를 한국어를 사용할 수 있도록 수정.
https://bitbucket.org/eunjeon/mecab-ko

Open Korean Text: 오픈 소스 한국어 분석기. 과거 트위터 형태소 분석기.
https://github.com/open-korean-text/open-korean-text

 

사용해보자면

okt = Okt()
kkma = Kkma()

sentece ='열심히 코딩한 당신, 연휴에는 여행을 가봐요'

okt.morphs(sentece) #형태소 분석
결과
['열심히', '코딩', '한', '당신', ',', '연휴', '에는', '여행', '을', '가봐요']

okt.pos(sentece) #품사 태깅

결과
[('열심히', 'Adverb'),
 ('코딩', 'Noun'),
 ('한', 'Josa'),
 ('당신', 'Noun'),
 (',', 'Punctuation'),
 ('연휴', 'Noun'),
 ('에는', 'Josa'),
 ('여행', 'Noun'),
 ('을', 'Josa'),
 ('가봐요', 'Verb')]
 
 #명사만 추출하고 싶으면?
okt.nouns(sentece)

결과
['코딩', '당신', '연휴', '여행']

이렇게 okt로 해볼 수 있습니다.


이번에는 꼬꼬마로 해보겠습니다!

kkma.morphs(sentence)

결과
['열심히', '코딩', '하', 'ㄴ', '당신', ',', '연휴', '에', '는', '여행', '을', '가보', '아요']

kkma.pos(sentence)
결과
[('열심히', 'MAG'),
 ('코딩', 'NNG'),
 ('하', 'XSV'),
 ('ㄴ', 'ETD'),
 ('당신', 'NP'),
 (',', 'SP'),
 ('연휴', 'NNG'),
 ('에', 'JKM'),
 ('는', 'JX'),
 ('여행', 'NNG'),
 ('을', 'JKO'),
 ('가보', 'VV'),
 ('아요', 'EFN')]
 
 kkma.nouns(sentence)
 결과
 ['코딩', '당신', '연휴', '여행']

분석기마다 성능이 다르니까 어떤게 적절할지 꼭 확인해봐야합니다.


okt vs kkm

 

첫번째 문장 test

sentence = '아버지가방에들어가신다'

print(okt.pos(sentence))
print(kkma.pos(sentence))

결과
[('아버지', 'Noun'), ('가방', 'Noun'), ('에', 'Josa'), ('들어가신다', 'Verb')]
[('아버지', 'NNG'), ('가방', 'NNG'), ('에', 'JKM'), ('들어가', 'VV'), ('시', 'EPH'), ('ㄴ다', 'EFN')]

 

둘다 제대로 잡지못하는..모습을 보여줍니다 가방을 명사로 잡아버렸네요~


두번째 문장 test

sentence = '그래욬ㅋㅋ'

print(okt.pos(sentence))
print(kkma.pos(sentence))

[('그래욬', 'Noun'), ('ㅋㅋ', 'KoreanParticle')]
[('그리하', 'VV'), ('여', 'ECD'), ('욬', 'UN'), ('ㅋㅋ', 'EMO')]
okt.pos(sentence, norm=True, stem=True
[('그렇다', 'Adjective'), ('ㅋㅋ', 'KoreanParticle')]

okt.pos(sentence, norm=True,)
[('그래요', 'Adjective'), ('ㅋㅋ', 'KoreanParticle')]

norm기능과 stem기능에 따라서 또 그렇다, 그래요 등의 어원이 나옵니다!


이렇게 OKT와 KKM를 활용해서 토큰 추출을 해보았는데 

한국어로 토큰화를 할 수 있다는 사실에 일단 먼저 놀랐고 두번째로는 생각보다 굉장히 많은 곳에서 쓰이고 있다는것도 느꼈다. 사실 우리가 사용하고 있는 모든것들에 조금씩은 녹아있는 기술이라고 생각을 하고 

내가 스스로 사용하면서 답답했던 부분이나 좀더 용이하거나 편하게 사용할 수 있는 아이디어들도 꾸준히 생각해보려고한다.