텍스트 분석을 위한 인코딩

김선재·2021년 11월 14일
0

Deep Learning

목록 보기
12/13
post-thumbnail

텍스트의 수치화

💡 컴퓨터는 텍스트를 인식할 수 없다. 오로지 숫자만 처리가 가능하기 때문에 텍스트를 수치화 시키는 작업을 수행해야 한다.

  1. Integer Encoding( 정수 인코딩 )
  • 단어 토큰화 또는 형태소 분리 후 각 단어에 대해 고유한 정수를 부여
  • 중복이 허용되지 않는 모든 단어들의 집합을 만들어야 한다. 단어 집합( Vocabulary ) 이라고 한다.

Integer Encoding

  • 문장을 단어 토큰화 또는 형태소 분리를 진행하여 각 단어 및 형태소를 얻어낼 수 있다. Integer Encoding은 문장을 구성하는 각 형태소에 정수를 부여
  • 숫자를 부여하는 기준은 ABC( 가나다 )순 또는 등장 빈도가 높은 순으로 순서를 구성할 수도 있다.
  • 일반 적으로 등장 빈도수가 높으면 앞쪽 번호를 부여한다.
import nltk

nltk.download('punkt')

[English] Sentence Tokenization

text = """Isn't she lovely.
Isn't she wonderful.
Isn't she precious.
Less than one minute old.
I never thought through love we'd be.
Making one as lovely as she.
But isn't she lovely made from love.
Isn't she pretty.
Truly the angel's best.
Boy, I'm so happy.
We have been heaven blessed.
I can't believe what God has done.
Through us he's given life to one.
But isn't she lovely made from love.
Isn't she lovely.
Life and love are the same.
Life is Aisha.
The meaning of her name.
Londie, it could have not been done.
Without you who conceived the one.
That's so very lovely made from love."""
from nltk.tokenize import sent_tokenize

sent_tokens = sent_tokenize(text)
print(sent_tokens)

~~>
["Isn't she lovely.", "Isn't she wonderful.", "Isn't she precious.", 'Less than one minute old.', "I never thought through love we'd be.", 'Making one as lovely as she.', "But isn't she lovely made from love.", "Isn't she pretty.", "Truly the angel's best.", "Boy, I'm so happy.", 'We have been heaven blessed.', "I can't believe what God has done.", "Through us he's given life to one.", "But isn't she lovely made from love.", "Isn't she lovely.", 'Life and love are the same.', 'Life is Aisha.', 'The meaning of her name.', 'Londie, it could have not been done.', 'Without you who conceived the one.', "That's so very lovely made from love."]

[English] Word Tokenization

nltk.download('stopwords')
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize

# 단어 토큰화된 전체 문장을 가지고 있을 배열
sentences = []
stop_words = set(stopwords.words('english'))	# 불용어 중복 제거

# 문장을 하나씩 꺼내서 단어 토큰화
for sent in sent_tokens:
	
    word_tokens = word_tokenize(sent)	# 단어 토큰화 수행
    result = []	 # 정제 작업이 완료된 단어를 추가할 배열
    ###### 단어 정제 작업 ######
    for word in word_tokens:	# 단어 토큰에서 단어를 하나씩 추출해 ㅜㅈ기
        # 소문자화
        word = word.lower()	# 모든 단어를 소문자화 하여 정규화
        if word not in stop_words:	# 불용어 처리
        	
            # 단어 길이가 3개 이상인 단어만 사용
            if len(word) > 2:
                result.append(word)
    
    sentences.append(result)
    
print(sentences)

~~>
[["n't", 'lovely'], ["n't", 'wonderful'], ["n't", 'precious'], ['less', 'one', 'minute', 'old'], ['never', 'thought', 'love'], ['making', 'one', 'lovely'], ["n't", 'lovely', 'made', 'love'], ["n't", 'pretty'], ['truly', 'angel', 'best'], ['boy', 'happy'], ['heaven', 'blessed'], ["n't", 'believe', 'god', 'done'], ['given', 'life', 'one'], ["n't", 'lovely', 'made', 'love'], ["n't", 'lovely'], ['life', 'love'], ['life', 'aisha'], ['meaning', 'name'], ['londie', 'could', 'done'], ['without', 'conceived', 'one'], ['lovely', 'made', 'love']]

[English] 단어 집합 만들기( Python )

  • 단어 집합이란 중복을 제거한 단어들의 집합
# 각 배열에 등장한 횟수가 많을 수록 앞 번호에 배치
# 1. 문장 별로 모여있는 단어들을 하나로 풀어서 합치기
word = sum(sentences, [])	# sentences에 들어있는 모든 배열을 비어있는 배열에 합치는 역할( extends )

print(words)

~~>
["n't", 'lovely', "n't", 'wonderful', "n't", 'precious', 'less', 'one', 'minute', 'old', 'never', 'thought', 'love', 'making', 'one', 'lovely', "n't", 'lovely', 'made', 'love', "n't", 'pretty', 'truly', 'angel', 'best', 'boy', 'happy', 'heaven', 'blessed', "n't", 'believe', 'god', 'done', 'given', 'life', 'one', "n't", 'lovely', 'made', 'love', "n't", 'lovely', 'life', 'love', 'life', 'aisha', 'meaning', 'name', 'londie', 'could', 'done', 'without', 'conceived', 'one', 'lovely', 'made', 'love']
# 2. 빈도수를 센 다음 배치
from collections import Counter	# 횟수 세기 용도

vocab = Counter(words)	# Counter 모듈을 활용하면 단어의 모든 빈도수를 손쉽게 계산 가능

print(vocab)

~~>
Counter({"n't": 8, 'lovely': 6, 'love': 5, 'one': 4, 'made': 3, 'life': 3, 'done': 2, 'wonderful': 1, 'precious': 1, 'less': 1, 'minute': 1, 'old': 1, 'never': 1, 'thought': 1, 'making': 1, 'pretty': 1, 'truly': 1, 'angel': 1, 'best': 1, 'boy': 1, 'happy': 1, 'heaven': 1, 'blessed': 1, 'believe': 1, 'god': 1, 'given': 1, 'aisha': 1, 'meaning': 1, 'name': 1, 'londie': 1, 'could': 1, 'without': 1, 'conceived': 1})

📍 빈도 내림차순으로 정렬

vocab_items = vocab.items()
vocab_items

~~>
dict_items([("n't", 8), ('lovely', 6), ('wonderful', 1), ('precious', 1), ('less', 1), ('one', 4), ('minute', 1), ('old', 1), ('never', 1), ('thought', 1), ('love', 5), ('making', 1), ('made', 3), ('pretty', 1), ('truly', 1), ('angel', 1), ('best', 1), ('boy', 1), ('happy', 1), ('heaven', 1), ('blessed', 1), ('believe', 1), ('god', 1), ('done', 2), ('given', 1), ('life', 3), ('aisha', 1), ('meaning', 1), ('name', 1), ('londie', 1), ('could', 1), ('without', 1), ('conceived', 1)])

📍 빈도수가 높은 순서대로 정렬

vocab_sorted = sorted(vocab_items, key = lambda x : x[1], reverse=True)
print(vocab_sorted)

~~>
[("n't", 8), ('lovely', 6), ('love', 5), ('one', 4), ('made', 3), ('life', 3), ('done', 2), ('wonderful', 1), ('precious', 1), ('less', 1), ('minute', 1), ('old', 1), ('never', 1), ('thought', 1), ('making', 1), ('pretty', 1), ('truly', 1), ('angel', 1), ('best', 1), ('boy', 1), ('happy', 1), ('heaven', 1), ('blessed', 1), ('believe', 1), ('god', 1), ('given', 1), ('aisha', 1), ('meaning', 1), ('name', 1), ('londie', 1), ('could', 1), ('without', 1), ('conceived', 1)]

📍 높은 빈도수를 가진 단어일 수록 낮은 정수 인덱스를 부여( 앞쪽에 배치 )

word2idx = {}	# 비어있는 딕셔너리
i = 0

for word, frequency in vocab_sorted:
	
    if frequency > 1:	# 정제 작업, 빈도수가 너무 작은 단어는 제외
    	i += 1
        word2idx[word] = i	# 딕셔너리에 단어와 정수( 단어의 인덱스 ) 추가

print(word2idx)

~~>
{"n't": 1, 'lovely': 2, 'love': 3, 'one': 4, 'made': 5, 'life': 6, 'done': 7}

📍 빈도수가 가장 높은 상위 n개만 선택해서 단어집합으로 사용하기

# 단어 집합 상위 5개의 단어만 사용하겠다.( 사용할 단어집합의 크기 )
# 딥러닝 수행시 사용할 단어의 개수!!!
vocab_size = 5

# 단어 집합의 인덱스를 구해오기
word_frequency = [w for w, c in word2idx.items() if c >= vocab_size + 1]

print(word_frequency)	# 단어 집합에서 제외할 단어들

~~>
['life', 'done']
# 단어 사전에서 버릴 단어들 제거
for w in word_frequency:
    del word2idx[w]

print(word2idx)

~~>
{"n't": 1, 'lovely': 2, 'love': 3, 'one': 4, 'made': 5}

[English] 인코딩 수행하기

  • 텍스트로 이루어진 단어를 정수로 표현하는 것을 인코딩이라고 한다.
  • 정수를 텍스트로 이루어진 단어로 표현하는 것을 디코딩이라고 한다.

💡 Transformer, Seq2Seq, Attention( 바다나우 어텐션 ), BERT 등을 배우면 인코딩과 디코딩 작업용해서 텍스트를 분류할 수도 있고, 생성할 수도 있다.

📍 UNK(OOV) 토큰 만들기

word2idx['<oox>'] = 6
print(word2idx)

~~>
{"n't": 1, 'lovely': 2, 'love': 3, 'one': 4, 'made': 5, '<oov>': 6}
encoded = [] 	# 인코딩된 데이터를 저장하기 위한 배열

for s in sentences:
	
    # 임시로 인코딩된 내용을 저장할 배열
    temp = []
    # 문장에서 단어 토큰을 하나씩 꺼내기
    for w in s:
    	if w in word2idx:	# 단어가 사전에 있으면
        	temp.append(word2idx[w])	# 단어에 해당하는 정수를 temp에 추가
       	else:
        	temp.append(word2idx['<oov>'])	# 단어 집합에 없는 단어라면 oov에 해당하는 정수를 찾아서 추가
    encoded.append(temp)
    
print('변환 전 : ', sentences[:5])
print('변환 후 : ', encoded[:5])

~~>
변환 전 :  [["n't", 'lovely'], ["n't", 'wonderful'], ["n't", 'precious'], ['less', 'one', 'minute', 'old'], ['never', 'thought', 'love']]
변환 후 :  [[1, 2], [1, 6], [1, 6], [6, 4, 6, 6], [6, 6, 3]]

[English] Vocab & Integer Encoding ( Tensorflow )

📍 단어 집합 만들기

from tensorflow.keras.preprocessing.text import Tokenizer

t = Tokenizer()

# fit_on_texts() 함수에 코퍼스( sentences )를 집어 넣으면 바로 빈도수를 기준으로 단어 집합을 만들어 준다.
t.fit_on_texts(sentences)	# 형태소 분리의 결과가 들어간다. 이 때 형태소 분리의 결과는 항상 2차원 배열이어야만 한다.

# 생성된 단어 집합 확인
print(t.word_index)

~~>
{"n't": 1, 'lovely': 2, 'love': 3, 'one': 4, 'made': 5, 'life': 6, 'done': 7, 'wonderful': 8, 'precious': 9, 'less': 10, 'minute': 11, 'old': 12, 'never': 13, 'thought': 14, 'making': 15, 'pretty': 16, 'truly': 17, 'angel': 18, 'best': 19, 'boy': 20, 'happy': 21, 'heaven': 22, 'blessed': 23, 'believe': 24, 'god': 25, 'given': 26, 'aisha': 27, 'meaning': 28, 'name': 29, 'londie': 30, 'could': 31, 'without': 32, 'conceived': 33}

📍 단어의 빈도수 확인하기

print(t.word_counts)

~~>
OrderedDict([("n't", 8), ('lovely', 6), ('wonderful', 1), ('precious', 1), ('less', 1), ('one', 4), ('minute', 1), ('old', 1), ('never', 1), ('thought', 1), ('love', 5), ('making', 1), ('made', 3), ('pretty', 1), ('truly', 1), ('angel', 1), ('best', 1), ('boy', 1), ('happy', 1), ('heaven', 1), ('blessed', 1), ('believe', 1), ('god', 1), ('done', 2), ('given', 1), ('life', 3), ('aisha', 1), ('meaning', 1), ('name', 1), ('londie', 1), ('could', 1), ('without', 1), ('conceived', 1)])

📍 인코딩 수행하기( text_to sequences )

print(t.text_to_sequences(sentences))

~~>
[[1, 2], [1, 8], [1, 9], [10, 4, 11, 12], [13, 14, 3], [15, 4, 2], [1, 2, 5, 3], [1, 16], [17, 18, 19], [20, 21], [22, 23], [1, 24, 25, 7], [26, 6, 4], [1, 2, 5, 3], [1, 2], [6, 3], [6, 27], [28, 29], [30, 31, 7], [32, 33, 4], [2, 5, 3]]

📍 디코딩 수행하기( sequences_to_texts )

print(t.sequences_to_texts([[1, 12],
			    [1, 17, 22]]))
                
~~>
["n't old", "n't truly heaven"]

[Korean] 토큰화 및 정수 인코딩을 Tensorflow로 구현

# 설치 코드
!pip install konlpy
import pandas as pd
import numpy as np
import urllib.request
from tensorflow.keras.preprocessing.text import Tokenizer
urllib.request.urlretrieve("https://raw.githubusercontent.com/e9t/nsmc/master/ratings_test.txt", filename="ratings_test.txt")

~~>
('ratings_test.txt', <http.client.HTTPMessage at 0x7f6723ad7b50>)
train_data = pd.read_table('ratings_text.txt', encoding='utf-8')
train_data.info()

~~>
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 50000 entries, 0 to 49999
Data columns (total 3 columns):
 #   Column    Non-Null Count  Dtype 
---  ------    --------------  ----- 
 0   id        50000 non-null  int64 
 1   document  49997 non-null  object
 2   label     50000 non-null  int64 
dtypes: int64(2), object(1)
memory usage: 1.1+ MB
train_data.head()

~~>

📍 1. nan값 제거

# 중복되지 않은 데이터의 개수 확인
train_data['document'].nunique()

~~>
49157

📍 2. 중복 문장 제거

# 중복 데이터 제거, nan값 제거
train_data.drop_duplicates(subset=['document'], inplace=True)
train_data = train_data.dropna(how='any')	# nan값이 존재하는 행을 제거

📍 3. 특수문자 및 영어 제거

# 정규식을 활용해서 한글만 추출( 영문, 특수문자 제거 )
train_data['document'] = train_data['document'].str.replace('[^ㄱ-ㅎㅏ-ㅣ가-힣]', '')	# 한글 및 공백이 아닌 문자는 모두, 마지막에 공백( space )

train_data.head()

~~>


📍 비어있는 문자열 정제

# 비어있는 문자열을 강제로 nan값으로 만들고, nan을 제거
train_data['document'].replace('', np.nan, inplace=True)
train_data.isnull().sum()	# nan값이 몇개 인지 개수 세기

~~>
id            0
document    162
label         0
dtype: int64
train_data = train_data.dropna(how='any')
train_data.head()

~~>


📍 Stemming 작업

from konlpy.tag import Okt

okt = Okt()
# okt 테스트 하기
sample_text = "뭐야 이 평점들은 나쁘진 않지만 점 짜리는 더더욱 아니잖아"
print(okt.morphs(sample_text, stem=True))

~~>
['뭐', '야', '이', '평점', '들', '은', '나쁘다', '않다', '점', '짜다', '리', '는', '더', '더욱', '아니다']

📍 불용어( stopwords ) 선정

stop_words = ['의','가','이','은','들','는','좀','잘','걍','과','도','를','으로','자','에','와','한','하다', '것', '게']
x_train = []

for sentence iin train_data['document']:
	
    temp_x = []
    temp_x = okt.morphs(sentence, stem=True)	# 토큰화
    temp_x = [word for word in temp_x if not word in stop_words]	# 불용어 제거
    
    x_train.append(temp_x)
    
x_train[:3]

~~>
[['굳다', 'ㅋ'],
 ['뭐', '야', '평점', '나쁘다', '않다', '점', '짜다', '리', '더', '더욱', '아니다'],
 ['지루하다', '않다', '완전', '막장', '임', '돈', '주다', '보기', '에는']]

📍 토큰화

t = Tokenizer()
t.fit_on_texts(x_train)
t.texts_to_sequences(x_train)[:3]

~~>
[[611, 89],
 [62, 165, 23, 392, 19, 20, 277, 773, 42, 858, 17],
 [64, 19, 87, 377, 107, 109, 58, 148, 243]]
profile
data science!!, data analyst!! ///// hello world

0개의 댓글