슬기로운 연구생활

3-1. BoW + NB 본문

프로젝트 : 영화리뷰 분류

3-1. BoW + NB

vhrehfdl 2019. 7. 24. 11:50

[1] Data Set

( Train Data )

- 긍정 리뷰 : 93,042 / 부정 리뷰 : 275,270

( Test Data )

- 긍정 리뷰 : 10,338 / 부정 리뷰 : 30,586

평점이 1점 ~ 3점인 영화리뷰를 부정 리뷰로 분류했고 10점인 리뷰를 긍정 리뷰로 라벨링했다.

 

[2] Text To Vector

텍스트 데이터를 NB에 그대로 넣을 수 없으니 Vector로 변환하는 과정을 거쳤다.

BoW을 사용해 Text를 Vector로 변형하였다.

Vector의 차원수 : 602,884

( 형태소 분석기를 사용해 전처리를 하면 차원수가 감소할까? 조사와 같은 불필요한 품사들을 제외하고 명사, 형용사, 동사 등 중요한 품사만 사용하면 차원수를 줄일 수 있을 것 같다. 실험해봐야겠다. )

Sklearn의 CountVector를 사용하면 ( 그림1 )과 같이 표현이 된다.

 

( 그림1 ) BoW 적용 결과

 

[3] Naive Bayes

Sklearn에 MultinomialNB를 적용하여 분류기를 만들었다.

( 그림2 ) MultinomialNB 계산 공식

Sklearn에서는 다양한 NB 모델을 지원한다.

MultinomialNB : feature가 이산형일 때 유용.

Bernoulli : feature가 이진형일 때 유용.

Gaussian : feature가 정규분포를 따를 때 유용.

[3-1] 코드

from sklearn import preprocessing, naive_bayes, metrics
from sklearn.feature_extraction.text import CountVectorizer
import pandas
import csv
from sklearn.metrics import classification_report


def Load_Data(train_file_dir, validation_file_dir):
    train_file = open(train_file_dir, 'r', encoding='utf-8')            # 학습 데이터 파일 읽기
    csv_reader_train = csv.reader(train_file)

    valid_file = open(validation_file_dir, 'r', encoding='utf-8')       # 검증 데이터 파일 읽기
    csv_reader_valid = csv.reader(valid_file)

    all_texts = []
    train_texts, train_labels = [], []
    valid_texts, valid_labels = [], []

    for row in csv_reader_train:
        all_texts.append(row[0])
        train_texts.append(row[0])
        train_labels.append(row[1])

    train_file.close()

    for row in csv_reader_valid:
        all_texts.append(row[0])
        valid_texts.append(row[0])
        valid_labels.append(row[1])

    valid_file.close()

    # 전체, 학습, 검증 데이터 프레임 미리 만들어둔다.
    dfAll, dfTrain, dfValid = pandas.DataFrame(), pandas.DataFrame(), pandas.DataFrame()
    dfAll['text'] = all_texts
    dfTrain['text'], dfTrain['label'] = train_texts, train_labels
    dfValid['text'], dfValid['label'] = valid_texts, valid_labels

    # 라벨링을 해준다.
    encoder = preprocessing.LabelEncoder()
    train_y, valid_y = encoder.fit_transform(dfTrain['label']), encoder.fit_transform(dfValid['label'])

    DataSet = {'train_text': dfTrain['text'], 'valid_text': dfValid['text'], 'train_label': train_y, 'valid_label': valid_y, 'all_text_data': dfAll['text']}

    return DataSet


def Convert_Text_To_Vector(DataSet):

    AllTextData = DataSet['all_text_data']
    train_text = DataSet['train_text']
    valid_text = DataSet['valid_text']

    word_index, embedding_matrix = None, None           # Word Embedding 일 사용 할 경우에만 사용한다.


    # 문장을 단어로 잘라준다.
    count_vect = CountVectorizer(analyzer='word', token_pattern=r'\w{1,}')
    count_vect.fit(AllTextData)

    train_count = count_vect.transform(train_text)
    print(train_count.shape)

    valid_count = count_vect.transform(valid_text)
    print(valid_count.shape)

    TextToVec_DataSet = {'train_count': train_count, 'valid_count': valid_count, 'word_index': word_index, 'embedding_matrix': embedding_matrix }

    return TextToVec_DataSet


def Train_Model(classifier, data_set, text_to_vector_data_set, target_names=['0', '1']):

    train_count, train_label = text_to_vector_data_set['train_count'], data_set['train_label']
    valid_count, valid_label = text_to_vector_data_set['valid_count'], data_set['valid_label']

    # train_count와 train_label로 학습해서 모델 생성.
    classifier.fit(train_count, train_label)

    # 학습된 모델에 valid_count를 넣어 정답 예측하기.
    predictions = classifier.predict(valid_count)

    print("-" * 33)
    print(classification_report(valid_label, predictions, target_names=target_names))

    return metrics.accuracy_score(predictions, valid_label)


if __name__ == "__main__":
    DataSet = Load_Data("../data/train.csv", "../data/validation.csv")          # 1. 학습데이터와 검증데이터를 불러온다.
    TextToVec_DataSet = Convert_Text_To_Vector(DataSet)                         # 2. 불러온 Text 데이터를 Vector로 변환해준다.

    classifier = naive_bayes.MultinomialNB()                                    # 3. 사용할 알고리즘 정의
    # classifier = naive_bayes.BaseNB()
    # classifier = naive_bayes.GaussianNB()
    # classifier = naive_bayes.BernoulliNB()

    accuracy = Train_Model(classifier, DataSet, TextToVec_DataSet)              # 4. model을 만들고 정확도를 측정한다.

    print("모델 정확도: ", accuracy)
    print("-" * 33)

https://github.com/vhrehfdl/Blog/blob/master/movie_review_classification/model/BoW%2BNB.py

 

[3-2] 결과

( 그림2 ) NB 결과

대체 왜 이렇게 결과가 높게 나오는지 모르겠다.

어떠한 전처리도 하지 않았고 그냥 BoW로 Vector 만들고 NB 사용했을 뿐인데 지나치게 높게 나왔다.

그 이유를 추측해본다면, 애초에 DataSet을 구성할 때 1~3점은 부정리뷰, 10점은 긍정리뷰로 한게 문제일수도 있다고 생각했다.

왜냐하면 너무 극단적이기 때문이다.

텍스트에도 그러한 특성들이 반영되어 있을 수 있기 때문에 결과가 너무 좋게 나온 것 같기도 하다.

만약, 애매모호한 문장을 Test Set으로 구성해 해당 Model에 테스트 해보면 정확률이 낮게 나올 수도 있을 것 같다. ( 추가적으로 실험해봐야겠다. )

[4] 추후 계획

- 일단은 Konlpy를 사용해 전처리 했을 때 성능이 올라가는지 확인해봐야 한다. ( 불필요 품사 제외, Stemming )

- Test Set을 바꿔서 accuracy를 측정해봐야 할 것 같다.

- NB 다양한 모델 사용 ( 가우시안, 베르누이 )

'프로젝트 : 영화리뷰 분류' 카테고리의 다른 글

3-4. BoW + Random Forest Classifier  (0) 2019.07.25
3-3. BoW + SVM  (0) 2019.07.25
3-2. BoW + NB + Komoran  (0) 2019.07.25
2. 데이터 가공  (0) 2019.07.24
1. 소개  (0) 2019.07.24
Comments