자연어처리(텍스트 이진 분류)

2 minute read

텍스트 이진 분류

  • acllmdb_v1_small 폴더의 훈련 데이터는 긍부정 각 30개씩, 테스트 데이터는 긍부정 각 10개씩만 가지고 있다.
  • 자료가 너무 적어 정상적인 정확도는 나오지 않고 연습용으로만 사용

Train Data Loading

imdb_dir = '/content/gdrive/My Drive/pytest/aclImdb_v1_small/aclImdb/'
import os
train_dir = os.path.join(imdb_dir, 'train') # aclimdb 폴더의 훈련 데이터 내용을 가져온다
labels = [] ; texts = [] # labels와 texts 라는 두 개의 빈 리스트를 만든다
for label_type in ['neg', 'pos']: # train 폴더에 있는 pos 12,500 + neg 12,500 개의 데이터를 읽는다
    dir_name = os.path.join(train_dir, label_type) # neg와 pos 폴더 각각에 접근한다
    for fname in os.listdir(dir_name):
        if fname[-4:] == '.txt': # 마지막 4 글자가 .txt 로 끝나는지를 확인한다
            f = open(os.path.join(dir_name, fname), encoding='utf8')
            texts.append(f.read()) # 텍스트를 읽어서 texts 리스트에 연결한다
            f.close()
            if label_type == 'neg': # 만약 현재 폴더가 neg 폴더라면
                labels.append(0) # texts와 같은 순서의 labels 리스트에 0을 저장한다
            else:
                labels.append(1) # pos 폴더라면 같은 순서의 labels 리스트에 1을 저장

Data Tokenizing

텍스트에 사용된 단어의 종류를 빈도 순으로 정렬하는 작업이다.

%tensorflow_version 2.x
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
import numpy as np
import math
validation_ratio = math.floor(len(texts) * 0.3) # 최적 모델 판정을 위한 검증 샘플은 전체의 30%로 한다
max_words = 10000 # 데이터셋에서 가장 빈도 높은 9,999 개의 단어만 사용한다
maxlen = 200 # 항상 각 문장의 길이가 200 단어가 되도록 고정한다
tokenizer = Tokenizer(num_words=max_words) # 상위빈도 max_words 개의 단어를 추려내는 Tokenizer 객체 생성
tokenizer.fit_on_texts(texts) # texts 내용에 대한 단어 인덱스를 구축한다. 사용할 단어가 결정된다
word_index = tokenizer.word_index # 단어와 인덱스의 쌍을 가져온다
#print(word_index) : {'the' : 1,'and' : 2 ,'a' :3 ...}

Tokenizer 예시

Tokenizing을 할 때는 그 대상들이 별개의 원소로 있어야 한다.

  1. 자료가 중첩 리스트로 있을 때의 경우이다. 중첩 리스트일때 원소가 분리가 안되있을 때 별개의 원소로 분리 해주어야 한다.
         sample1=[['사과 감자 옥수수'],['딸기 감자 옥수수'],['양파 부추 옥수수']]
         # 출력 : ['사과 감자 옥수수':1,'딸기 감자 옥수수':2,'양파 부추 옥수수' :3]
         sample2 = [['사과', '감자', '옥수수'], ['너희', '감자', '옥수수'], ['그들', '감자', '옥수수'], ['양파', '부추', '옥수수']]
         # 출력 : ['옥수수':1,'감자':2,'사과':3,'그들':5,'양파':6,'부추':7]
    
    
  2. 단일리스트일 경우 별개의 원소로 분리되지 않아도 가능하다

     sample3 = ['사과 감자 옥수수 너희 그들 양파 부추']
     # 출력 : ['사과':1,'감자':2,'옥수수':3,'너희':4,'그들':5,'양파':6,'부추':7]
     sample4 = ['사과', '감자', '옥수수', '너희', '그들', '양파', '부추’]
     # 출력 : ['사과':1,'감자':2,'옥수수':3,'너희':4,'그들':5,'양파':6,'부추':7]
    

Data Sequencing

문자를 숫자로 변환하는 작업을 수행한다.

    data = tokenizer.texts_to_sequences(texts) # 위에서 설정한 빈도 10,000의 결과가 여기서 반영된다.

GitHub Logo

Data Padding

  • Padding은 데이터의 길이를 고정시켜준다. -> 행렬 연산을 쉽게하기 위함
  • 지정된 길이에서 모자라는 것은 0으로 채우고, 넘치는 것은 잘라낸다.
  • 길이를 고정해야 텐서의 크기가 맞춰진다,
  • 기본값으로 단어의 선택은 뒤에서부터 한다.
  • nested list를 2D 텐서(2차원 넘파이 배열)로 만든다.
   from keras.preprocessing.sequence import pad_sequences
   sequences=[[1,2,3,4,5],[1,2,3,4],[1]] # nested list
   padded = pad_sequences(sequences,maxlen=3)
   print(padded)
    # 출력 : [[3 4 5]
    #         [2 3 4]
    #         [0 0 1]]

One-Hot Encoding

one-hot encoding은 모든 숫자를 0과 1로만 만든다.

    def to_one_hot(sequences,dimension):
        #zeros는 전달받은 x,y값으로 x*y행렬을 만들어 모두 0으로 채워준다.
        results = np.zeros((len(sequences),dimension)
        for i,sequence in enumerate(sequences):
            results[i,sequence]=1
        return results
        )
    data = to_one_hot(data,dimension=max_words)
    #다중분류에서는 labels도 원-핫 인코딩을 한다
    labels = np.asarray(labels).astype('float32')

Leave a comment