KT 에이블스쿨 46일차(1)

박기범·2023년 4월 5일
0

에이블스쿨

목록 보기
52/95

자연어처리 NLP의 3일차 프로젝트를 진행했습니다.



실습 내용

1-2일차에는 데이터 분석 위주로 진행했고 오늘은 이제 분석을 토대로 어떻게 tokenizer를 진행할 것이고 모델링을 할 것인지에 대해 진행했습니다.



실습에 사용한 코드

오늘은 전체적인 코드를 한번 작성하겠습니다. 어제 포스팅과 중복된 코드가 있는데 어제 코드에서 문제점이 있어서 수정했습니다.

▶특수문자 제거

    train_x = train_x.str.replace('[^ㄱ-ㅎㅏ-ㅣ가-힣A-Za-z0-9]', ' ', regex=True)
    val_x = val_x.str.replace('[^ㄱ-ㅎㅏ-ㅣ가-힣A-Za-z0-9]', ' ', regex=True)

특수문자를 제거하고 공백으로 대체하는 코드입니다. [ ]안에 있는 코드는 ^ㄱ-ㅎㅏ-ㅣ가-힣A-Za-z0-9인데 앞에 ^있으면 해당을 제외한 나머지 문자들을 선택해주는 것을 의미합니다.

▶tokenizer & sequences

    from konlpy.tag import Mecab

    mecab = Mecab()

    def get_nouns(text):
        nouns = mecab.nouns(text)
        return nouns

명사를 추출하고 띄어쓰기로 해당 명사를 구분 지어줍니다.

    from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer

    count_vectorize = CountVectorizer()
    count_mecab_vectorizer = CountVectorizer(tokenizer=get_nouns)
    
    train_x_counts = count_vectorize.fit_transform(train_x)
    val_x_counts = count_vectorize.transform(val_x)

    train_x_mecap_counts = count_mecab_vectorizer.fit_transform(train_x)
    val_x_mecp_counts = count_mecab_vectorizer.transform(val_x)

위에 생성한 mecab으로 tokenizer을 진행합니다.

    import tensorflow as tf
    import numpy as np
    from tensorflow.keras.preprocessing import sequence, text

    TOP_K = 5000
    MAX_SEQUENCE_LENGTH = 500

    x_mor_train_str = train_x.apply(lambda x:' '.join(get_nouns(x)))
    x_mor_val_str = val_x.apply(lambda x:' '.join(get_nouns(x)))
    x_mor_train = train_x.apply(lambda x:get_nouns(x))
    x_mor_val = val_x.apply(lambda x:get_nouns(x))
    tokenizer_str = text.Tokenizer(num_words = TOP_K, char_level=False)
    tokenizer_str.fit_on_texts(x_mor_train_str)
    x_mor_train_seq_str = tokenizer_str.texts_to_sequences(x_mor_train_str)
    x_mor_val_seq_str = tokenizer_str.texts_to_sequences(x_mor_val_str)

    max_length = len(max(x_mor_train_seq_str, key=len))

    if max_length > MAX_SEQUENCE_LENGTH:
        max_length = MAX_SEQUENCE_LENGTH
    print(max_length)

    x_mor_train_seq_str = sequence.pad_sequences(x_mor_train_seq_str, maxlen=max_length)
    x_mor_val_seq_str = sequence.pad_sequences(x_mor_val_seq_str, maxlen=max_length)
    
    
    tokenizer = text.Tokenizer(num_words = TOP_K, char_level=False)
    tokenizer.fit_on_texts(x_mor_train)
    x_mor_train_seq = tokenizer.texts_to_sequences(x_mor_train)
    x_mor_val_seq = tokenizer.texts_to_sequences(x_mor_val)

    max_length = len(max(x_mor_train_seq_str, key = len))

    if max_length > MAX_SEQUENCE_LENGTH:
        max_length = MAX_SEQUENCE_LENGTH
    print(max_length)

    x_mor_train_seq = sequence.pad_sequences(x_mor_train_seq, maxlen=max_length)
    x_mor_val_seq = sequence.pad_sequences(x_mor_val_seq, maxlen=max_length)

sequence를 마저 진행해줍니다.

▶w2v (word 2 vector)

해당 코드는 아직 이해를 하지 못해서 코드만 붙여놓고 나중에 수정해두겠습니다.

    import gdown
    url = 'https://drive.google.com/file/d/0B0ZXk88koS2KbDhXdWg1Q2RydlU/view?resourcekey=0-Dq9yyzwZxAqT3J02qvnFwg'
    output = os.path.join(PATH, 'ko.zip')
    gdown.download(url, output, fuzzy=True, quiet=False)

    import zipfile
    with zipfile.ZipFile(os.path.join(PATH, "ko.zip"), 'r') as zip_ref:
        zip_ref.extractall(PATH)
	!pip install gensim
    from gensim.models import Word2Vec, FastText, KeyedVectors
    import logging

    logging.basicConfig(format = '%(asctime)s : %(levelname)s : %(message)s', level = logging.INFO)

    SIZE = 128
    WINDOW = 3
    MIN_COUNT = 1
    w2v_model = Word2Vec(sentences=x_mor_train, vector_size=SIZE, window=WINDOW, max_vocab_size=None, min_count=MIN_COUNT, workers=4, negative=5, sg=0)
    # 아래 함수는 제공합니다.
    def get_sent_embeddings(model, embedding_size, tokenized_words):

        # 단어 임베딩 및 n_words의 크기가 0인 feature_vec 배열을 0으로 초기화합니다. 
        # 또한 model.wv.index2word를 사용하여 Word2Vec 모델의 어휘에 단어 세트를 생성합니다.
        feature_vec = np.zeros((embedding_size,), dtype='float32')
        n_words = 0
        index2word_set = set(model.wv.index_to_key)

        # 토큰화된 문장의 각 단어를 반복하고 Word2Vec 모델의 어휘에 존재하는지 확인합니다. 
        # 그렇다면 n_words가 증가하고 단어의 임베딩이 feature_vec에 추가됩니다.
        for word in tokenized_words:
            if word in index2word_set:
                n_words += 1
                feature_vec = np.add(feature_vec, model.wv[word])

        # Word2Vec 모델의 어휘에 있는 입력 문장에 단어가 있는지 확인합니다. 
        # 있다면 feature_vec를 n_words로 나누어 입력 문장의 평균 임베딩을 구합니다.
        if (n_words > 0):
            feature_vec = np.divide(feature_vec, n_words)

        return feature_vec
    def get_dataset(sentences, model, num_features):

        # 각 문장에 대한 임베딩을 보유할 dataset이라는 빈 목록을 초기화합니다.
        dataset = list()

        # 문장의 각 문장을 반복하고 앞에서 설명한 get_sent_embeddings() 함수를 사용하여 문장에 대한 평균 임베딩을 생성합니다. 
        # 결과 문장 임베딩이 데이터 세트 목록에 추가됩니다.
        for sent in sentences:
            dataset.append(get_sent_embeddings(model, num_features, sent))

        # 루프에서 생성된 문장 임베딩을 sent_embedding_vectors라는 2차원 배열에 쌓습니다. 
        sent_embedding_vectors = np.stack(dataset)

        return sent_embedding_vectors
	pre_trained = Word2Vec.load(os.path.join(PATH, 'ko_updated.bin'))
	x_pr_train = get_dataset(train_x.apply(lambda x: mecab.morphs(x)), pre_trained, 128)
    x_pr_val = get_dataset(val_x.apply(lambda x: mecab.morphs(x)), pre_trained, 128)

w2v가 진행됐으면 어떤 단어들이 학습됐는지 확인가능합니다. 아래 코드는 결과를 확인하는 코드입니다.

    keys = list(w2v_model.wv.key_to_index)
    print(keys[:100])

학습된 명사들중 상위 100개만 보여줍니다.

	w2v_model.wv['문제']

'문제'라는 단어에 대한 학습 가중치를 확인할 수 있습니다.

▶모델링 시작

모델링을 진행했는데 너무 낮은 결과 값이 나왔습니다.

    from sklearn.metrics import accuracy_score

    # 모델링 시작 
    from lightgbm import LGBMClassifier

    model = LGBMClassifier()

    model.fit(x_pr_train, train_y)

    y_pred = model.predict(x_pr_val)

    accuracy_score(val_y, y_pred)

아직 튜닝이 부족한지 전처리를 잘못했는지 0.4점대라는 점수를 기록해서 너무 기대 이하의 결과값을 보여줬습니다! 내일은 모델링 튜닝을 좀 더 해보면서 좋은 값이 나오도록 해보겠습니다.







전처리라는 벽을 넘어 이제는 모델링의 벽을 넘어갈 차례인 거 같습니다.




※공부하고 있어 다소 틀린점이 있을 수 있습니다. 언제든지 말해주시면 수정하도록 하겠습니다.
※용어에 대해 조금 공부 더 해서 수정하겠습니다.

profile
개발자가 되기 위한 한걸음

0개의 댓글