'Tokenization'에 해당하는 글 2건

토큰화, 정제 및 정규화 등의 전처리 작업을 마친 후에, 컴퓨터가 데이터 처리를 더 빠르게 하도록 텍스트를 수치화 하는 것을 정수 인코딩(Integer Encoding) 이라 한다.


결론 : keras 의 Tokenizer 를 사용하면 쉽게 해결



정수 인코딩 과정

  1. 문장 토큰화, 정제 및 일반화, 단어 토큰화.
  2. 빈도수를 기록하여 빈도수가 높은 순서대로 정렬 
  3. 자연어 처리에서 빈도수가 낮은 단어는 의미를 가지지 않을 가능성이 높으므로 제외
  4. 빈도수 순서로 정렬된 단어에 순차적으로 인덱스 부여
  5. 각 단어를 부여된 인덱스로 맵핑.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
from nltk.tokenize import sent_tokenize
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
 
text = "A barber is a person. a barber is good person. a barber is huge person. he Knew A Secret! The Secret He Kept is huge secret. Huge secret. His barber kept his word. a barber kept his word. His barber kept his secret. But keeping and keeping such a huge secret to himself was driving the barber crazy. the barber went up a huge mountain."
text = sent_tokenize(text)  # 문장 토큰화
 
vocab = {}
sentences = []
stop_words = set(stopwords.words('english'))
 
for i in text:
    sentence = word_tokenize(i)  # 단어 토큰화
    result = []
 
    for word in sentence:
        word = word.lower()  # 단어 중복제거를 위해 소문자화
        if word not in stop_words:
            if len(word) > 2:  # 3자 이상의 단어만 수집
                result.append(word)
                if word not in vocab:  # 단어 중복 제거
                    vocab[word] = 0
                vocab[word] += 1  # 빈도수 계산
 
    sentences.append(result)  # 문장별 정제된 단어 리스트
 
vocab_sorted = sorted(vocab.items(), key=lambda x: x[1], reverse=True)  # 빈도수 높은 순으로 단어 정렬
word_to_index = {}
= 0
for (word, frequency) in vocab_sorted:
    if frequency > 1:  # 빈도수 높은 순으로 정렬된 단어에 1부터 인덱스 부여
        i = i + 1
        word_to_index[word] = i
 
vocab_size = 5
words_frequency = [w for w, c in word_to_index.items() if c >= vocab_size + 1]
for w in words_frequency:  # 빈도수 상위 5개를 제외한 단어 제거
    del word_to_index[w]
 
word_to_index['OOV'= len(word_to_index) + 1  # OOV(Out-Of-Vocabulary) : 단어 집합에 없는 단어
encoded = []
for s in sentences:
    temp = []
    for w in s:
        try:
            temp.append(word_to_index[w])  # 단어를 인덱스로 치환
        except:
            temp.append(word_to_index['OOV'])
    encoded.append(temp)
 
print(word_to_index)
print(sentences)
print(encoded)
 

''' 출력 
{'barber'1'secret'2'huge'3'kept'4'person'5'OOV'6}
[['barber''person'], ['barber''good''person'], ['barber''huge''person'], ['knew''secret'], ['secret''kept''huge''secret'], ['huge''secret'], ['barber''kept''word'], ['barber''kept''word'], ['barber''kept''secret'], ['keeping''keeping''huge''secret''driving''barber''crazy'], ['barber''went''huge''mountain']]
[[15], [165], [135], [62], [2432], [32], [146], [146], [142], [6632616], [1636]]
'''
cs


뭔가 상당히 복잡해 보이는데 25줄까지는 전처리, 그 뒤로는 빈도수 계산하고 인덱스 부여한 뒤 단어 위치에 인덱스로 치환하는 과정이다.



27~38줄의 과정에 collection.Counter 를 사용할 수도 있다.


from collections import Counter
words = sum(sentences, [])  # 리스트 요소들을 하나의 리스트로 합치기
vocab = Counter(words)  # 중복 요소 제거 및 빈도수 계산하여 정렬
vocab = vocab.most_common(vocab_size)  # 빈도수 상위 개수만큼 추출
cs


마찬가지로 nltk.FreqDist 도 사용할 수 있다.


from nltk import FreqDist
import numpy as np
words = np.hstack(sentences)  # 리스트 요소들을 하나의 리스트로 합치기
vocab = FreqDist(words)   # 중복 요소 제거 및 빈도수 계산하여 정렬
cs


이 모든 것들을 한번에 해결하는 keras...


from tensorflow.keras.preprocessing.text import Tokenizer
tokenizer = Tokenizer(6)  # 빈도수 상위 5개
tokenizer.fit_on_texts(sentences)  # 빈도수를 기준으로 단어 집합 생성
encode = tokenizer.texts_to_sequences(sentences)  # 정수 인코딩
cs


생성된 tokenizer 로 인덱스 부여 확인(word_index), 빈도수 확인(word_counts) 도 가능하다. 기본적으로 OOV 는 제거되므로 OOV 를 보존하려면 Tokenizer 에 oov_token 인자를 사용한다. 이 경우 OOV 의 default 인덱스 값은 1이며, 나머지 상위 5개 단어의 인덱스는 2부터 시작된다.


tokenizer = Tokenizer(num_words = vocab_size + 2, oov_token = 'OOV')
cs




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,

토큰화 : 코퍼스를 의미 있는 단위로 쪼갬 (단어/어절/문장/...)

- ['아버지', '가', '방', '에', '들어가', '신다']


코퍼스를 수집하고 가장 먼저 해야할 것은, 데이터들을 의미 있는 작은 단위(Token)로 쪼개는 토큰화(tokenization) 작업을 해야 한다. 띄어쓰기 별로 나눈다던지, 어절별로 나눈다던지, 형태소별로 나누던지, 이러한 토큰화 작업을 하면 토큰들에 대한 분석이 가능해 진다.



언어별 토큰화의 어려움


의미있는 단어들을 추출하기 위한 첫번째 단계인 토큰화는 언어별로 섬세한 알고리즘을 필요로 한다. 예로 들면, 영어권 언어들은 띄어쓰기 단위의 어절 토큰화가 단어 토큰화와 같아 합성어(New York)나 줄임말(I'm) 정도의 예외처리만 잘하면 단어(word) 토큰화가 가능하다. 한국어의 경우 띄어쓰기를 규칙적으로 사용하지도 않을 뿐더러, 교착어이기 때문에 대부분의 단어에 조사 등이 붙어 어절 토큰화가 아닌 형태소 토큰화가 필요하다. 형태소는 그 자체로 뜻이 있는 자립 형태소와, 다른 형태소와 결합해야지만 사용할 수 있는 의존 형태소가 있는데 이 형태소들을 각각 분리하는 것이 형태소(morpheme) 토큰화이다. 또한 여러 뜻을 포함하는 단어의 의미를 파악하기 위해 품사 태깅(part-of-speech tagging)도 필요하다. 문장(sentence) 토큰화를 먼저 수행할 수도 있는데 이 경우 구두점이 단어의 일부분이 아닌 문장의 끝임을 어떻게 판단할 것인지, 이러한 규칙들이 필요하다.


이런 것들을 어떻게 만들어야 하나... 걱정할 필요 없다. 이미 공개된 자연어 처리 패키지들을 잘 활용하기만 하면 된다.


◈ 영문 자연어 처리: NLTK(Natural Language Toolkit)


◈ 한글 자연어 처리: KoNLPy

- 한글 형태소 분석기: Mecab, Komoran, Hannanum, Kkma, Okt(Open Korean Text, 예전이름 Twitter),... 


◈ 한글 문장 분리기: kss(Korean Sentence Splitter)



NLTK 를 사용한 영어권 언어 토큰화


import nltk
from nltk.tokenize import word_tokenize
from nltk.tokenize import sent_tokenize
from nltk.tag import pos_tag
 
# corpus download
nltk.download('punkt')
nltk.download('averaged_perceptron_tagger')
 
text = "At eight o'clock on Thursday morning. Arthur didn't feel very good."
tokens = word_tokenize(text)
 
print(tokens) # 단어 토큰화
print(pos_tag(tokens)) # 품사 태깅
print(sent_tokenize(text)) # 문장 토큰화
 

""" 결과
['At', 'eight', "o'clock", 'on', 'Thursday', 'morning', '.', 'Arthur', 'did', "n't", 'feel', 'very', 'good', '.']
[('At', 'IN'), ('eight', 'CD'), ("o'clock", 'NN'), ('on', 'IN'), ('Thursday', 'NNP'), ('morning', 'NN'), ('.', '.'), ('Arthur', 'NNP'), ('did', 'VBD'), ("n't", 'RB'), ('feel', 'VB'), ('very', 'RB'), ('good', 'JJ'), ('.', '.')]
["At eight o'clock on Thursday morning.", "Arthur didn't feel very good."]
"""
cs


NLTK 를 사용하여 단어/문장 토큰화 및 토큰화 데이터에 품사를 태깅하였다. NLTK 는 Penn Treebank Tokenization 의 규칙에 따라 토큰화 하고, Penn Treebank POS Tags 라는 품사 태깅 기준을 사용한다.(패키지마다 기준이나 규칙은 다를 수 있다.)



KoNLPy 를 사용한 한글 토큰화


KoNLPy 을 사용하기 위해서는 JDK 1.7 이상이 설치되어 있어야 한다. 그리고 pip 로 konlpy 를 설치하고, JAVA 와 Python 을 연결해 주는 JPype 를 본인의 버전에 맞게 다운로드 하여 설치한다. (JPype 다운로드 - https://www.lfd.uci.edu/~gohlke/pythonlibs/#jpype)


> pip install konlpy
> pip install JPype1-1.1.2-cp38-cp38-win_amd64.whl
cs


from konlpy.tag import *
 
okt = Okt()
hannanum = Hannanum()
kkma = Kkma()
komoran = Komoran()
mecab = Mecab()
 
text = "아버지가방에들어가신다"
 
print(okt.morphs(text))
print(okt.pos(text))
print('-----')
print(mecab.morphs(text))
print(mecab.pos(text))
 
 
""" 결과
['아버지', '가방', '에', '들어가신다']
[('아버지', 'Noun'), ('가방', 'Noun'), ('에', 'Josa'), ('들어가신다', 'Verb')]
-----
['아버지', '가', '방', '에', '들어가', '신다']
[('아버지', 'NNG'), ('가', 'JKS'), ('방', 'NNG'), ('에', 'JKB'), ('들어가', 'VV'), ('신다', 'EP+EC')]
"""
cs


한글 토큰화 방법도 형태소를 분석하고 품사를 태깅하는 순서로 토큰화 과정은 대부분 비슷하다. 형태소 분석기에 따라 토큰화된 결과가 조금씩 다르며, 상황별 문장에 따라 각각의 장단점이 있다. 저중에는 아버지가 제대로 방에 들어가는 분석기도 mecab 뿐이고 성능도 가장 낫다고는 하지만... 윈도우 플랫폼은 지원하지 않아 추가 설치 및 설정 등이 필요하다.




WRITTEN BY
손가락귀신
정신 못차리면, 벌 받는다.

,