멋쟁이 사자처럼 AI 스쿨 TIL-49

김영민·2022년 12월 14일
0

1104 번 파일의 실습 목적 : KoNLPy 로 한국어 형태소분석기를 사용해 보는 것입니다.

QnA

  • 형태소 분석기마다 품사를 태깅하는 방법이 다 다릅니다. 품사 태깅표에서 명사에는 어떤 공통점이 있을까요?
    => N이 들어간다.

  • 동사에는 어떤 공통점이 있을까요?
    => V로 시작

  • konlpy에서도 순서를 따졌나요?
    => 형태소 분석기 입니다. 순서와는 무관해요. 주로 품사태깅, 스테밍, 정규화 등에 사용합니다. 목적이 달라요.
    => 전처리를 해주면 하다, 했다, 했어요 했을까 등의 단어를 정규화 할 수 있습니다.
    정규화 => 일관되게 전처리 해서 불필요하게 토큰을 생성하지 않고 같은 의미를 부여하게 됩니다.

  • 순서, 맥락, 시퀀스 가 중요한 데이터는 어떤 데이터가 있을까요?
    => 시계열데이터, 악보, 유전자, DNA

딥러닝

KoNLPy

  • 대표적인 자연어처리 도구인 NLTK, Spacy 는 한국어를 지원하지 않습니다. 영어를 사용한다면 해당도구를 사용해도 됩니다. 하지만 한국어 형태소 분석 등의 기능을 제공하지 않기 때문에 KoNLPy로 실습합니다.

형태소 분석기

  • 속도만 봤을 때는 mecab(은전한닢 으로 일본어 형태소 분석기를 한국어에 맞게 제작한 것입니다.) 이 가장 빨라 보이지만 목적에 따라 선택해서 사용하게 됩니다.
  • 코모란은 자바에서 사용할 수 있도록 만들어진 형태소 분석기 입니다. 파이썬 환경에서 느리다라고 해서 다른 환경에서도 느린 것은 아닙니다.
  • 형태소 분석기마다 어간추출, 표제어 표기법을 제공하기도 하고 제공하지 않는 것도 있습니다.

Okt 함수화

형태소 분석기(Okt) 불러오기
['Josa', 'Eomi', 'Punctuation'] 조사, 어미, 구두점 제거
전체 텍스트에 적용해 주기 위해 함수를 만듭니다.
1) 텍스트를 입력받습니다.
2) 품사태깅을 합니다. [('문의', 'Noun'), ('하다', 'Verb'), ('?!', 'Punctuation')]
3) 태깅 결과를 받아서 순회 합니다.
4) 하나씩 순회 했을 때 튜플 형태로 가져오게 됩니다. ('을', 'Josa')
5) 튜플에서 1번 인덱스에 있는 품사를 가져옵니다.
6) 해당 품사가 조사, 어미, 구두점이면 제외하고 append 로 인덱스 0번 값만 다시 리스트에 담아줍니다.
7) " ".join() 으로 공백문자로 연결해 주면 다시 문장이 됩니다.
8) 전처리 후 완성된 문장을 반환합니다.

def okt_clean(text):
    clean_text = []
    # 품사태깅을 합니다. [('문의', 'Noun'), ('하다', 'Verb'), ('?!', 'Punctuation')]
    # 태깅 결과를 받아서 순회 합니다. 
    for word in okt.pos(text, norm=True, stem=True):
        # 해당 품사가 조사, 어미, 구두점이면 제외하고 append 로 인덱스 0번 값만 다시 리스트에 담아줍니다.
        if word[1] not in ['Josa', 'Eomi', 'Punctuation']:
            clean_text.append(word[0])
    # " ".join() 으로 공백문자로 연결해 주면 다시 문장이 됩니다.
    return " ".join(clean_text)

okt_clean("추앙해요 사랑으론 부족해 추앙해요")

벡터화

  • 머신러닝이나 딥러닝 알고리즘은 문자를 이해할 수 없습니다. 내부에서는 수치 계산이 이루어지기 때문에 문자를 숫자로 변경해 주어야 합니다.
# TfidfVectorizer 로 벡터화 합니다.
# fit 으로 변환할 어휘를 학습합니다.

from sklearn.feature_extraction.text import TfidfVectorizer


tfidfvect = TfidfVectorizer()
tfidfvect.fit(X_train_text)

transform

주의해서 볼 것은 열(columns, 어휘)의 수가 같은지 확인

# transform
X_train = tfidfvect.transform(X_train_text)
X_test = tfidfvect.transform(X_test_text)

X_train.shape, X_test.shape

oov_token

  • oov가 word index에서 1번
  • 마스크값, 종결, 패딩 등으로 사용하기도 합니다. "" 를 사용하지 않고 다른 문자를 사용해도 상관은 없습니다
  • [UNK]로도 unknown의 의미
# tokenizer = Tokenizer(num_words=10, oov_token="[oov]")
# tokenizer = Tokenizer(num_words=10, oov_token="?모름?")
# tokenizer = Tokenizer(num_words=10, oov_token="[PAD]")
# tokenizer = Tokenizer(num_words=10, oov_token="<패딩?")
# tokenizer = Tokenizer(num_words=10, oov_token="[종결]")
# tokenizer = Tokenizer(num_words=10, oov_token="[MASK]")
# tokenizer = Tokenizer(num_words=10, oov_token="[마스크]")

Padding

  • 자연어 처리를 하다보면 각 문장(또는 문서)은 서로 길이가 다를 수 있습니다. 그런데 기계는 길이가 전부 동일한 문서들에 대해서는 하나의 행렬로 보고, 한꺼번에 묶어서 처리할 수 있습니다. 병렬 연산을 위해서 여러 문장의 길이를 임의로 동일하게 맞춰주는 작업이 필요할 때가 있습니다.

  • 텍스트는 신경망에 주입하기 전에 텐서로 변환되어야 합니다. 변환하는 방법에는 몇 가지가 있습니다.

  • 원-핫 인코딩(one-hot encoding)은 정수 배열을 0과 1로 이루어진 벡터로 변환합니다. 예를 들어 배열 [3, 5]을 인덱스 3과 5만 1이고 나머지는 모두 0인 10,000차원 벡터로 변환할 수 있습니다. 그다음 실수 벡터 데이터를 다룰 수 있는 층-Dense 층-을 신경망의 첫 번째 층으로 사용합니다. 이 방법은 num_words * num_reviews 크기의 행렬이 필요하기 때문에 메모리를 많이 사용합니다.

  • 다른 방법으로는, 정수 배열의 길이가 모두 같도록 패딩(padding)을 추가해 max_length * num_reviews 크기의 정수 텐서를 만듭니다. 이런 형태의 텐서를 다룰 수 있는 임베딩(embedding) 층을 신경망의 첫 번째 층으로 사용할 수 있습니다.

  • 이 튜토리얼에서는 두 번째 방식을 사용하겠습니다.

  • 텍스트의 길이가 같아야 하므로 pad_sequences 함수를 사용해 길이를 맞추겠습니다.

pad_sequences(sequences, maxlen=None, dtype='int32', padding='pre', truncating='pre', value=0.0)


>>> sequence = [[1], [2, 3], [4, 5, 6]]
>>> tf.keras.preprocessing.sequence.pad_sequences(sequence)
array([[0, 0, 1],
       [0, 2, 3],
       [4, 5, 6]], dtype=int32)

>>> tf.keras.preprocessing.sequence.pad_sequences(sequence, value=-1)
array([[-1, -1,  1],
       [-1,  2,  3],
       [ 4,  5,  6]], dtype=int32)

>>> tf.keras.preprocessing.sequence.pad_sequences(sequence, padding='post')
array([[1, 0, 0],
       [2, 3, 0],
       [4, 5, 6]], dtype=int32)

>>> tf.keras.preprocessing.sequence.pad_sequences(sequence, maxlen=2)
array([[0, 1],
       [2, 3],
       [5, 6]], dtype=int32)

시퀀스(순서) 방식의 인코딩은 시퀀스(순서)를 고려하는 알고리즘(RNN)에서 더 나은 성능을 보여줍니다.
머신러닝에서 사용했을 때는 오히려 TF-IDF 가 더 나은 성능을 보여주기도 합니다.

profile
배운걸 다 흡수하는 제로민

0개의 댓글