1104 번 파일의 실습 목적 : KoNLPy 로 한국어 형태소분석기를 사용해 보는 것입니다.
형태소 분석기마다 품사를 태깅하는 방법이 다 다릅니다. 품사 태깅표에서 명사에는 어떤 공통점이 있을까요?
=> N이 들어간다.
동사에는 어떤 공통점이 있을까요?
=> V로 시작
konlpy에서도 순서를 따졌나요?
=> 형태소 분석기 입니다. 순서와는 무관해요. 주로 품사태깅, 스테밍, 정규화 등에 사용합니다. 목적이 달라요.
=> 전처리를 해주면 하다, 했다, 했어요 했을까 등의 단어를 정규화 할 수 있습니다.
정규화 => 일관되게 전처리 해서 불필요하게 토큰을 생성하지 않고 같은 의미를 부여하게 됩니다.
순서, 맥락, 시퀀스 가 중요한 데이터는 어떤 데이터가 있을까요?
=> 시계열데이터, 악보, 유전자, DNA
형태소 분석기(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)
주의해서 볼 것은 열(columns, 어휘)의 수가 같은지 확인
# transform
X_train = tfidfvect.transform(X_train_text)
X_test = tfidfvect.transform(X_test_text)
X_train.shape, X_test.shape
# 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="[마스크]")
자연어 처리를 하다보면 각 문장(또는 문서)은 서로 길이가 다를 수 있습니다. 그런데 기계는 길이가 전부 동일한 문서들에 대해서는 하나의 행렬로 보고, 한꺼번에 묶어서 처리할 수 있습니다. 병렬 연산을 위해서 여러 문장의 길이를 임의로 동일하게 맞춰주는 작업이 필요할 때가 있습니다.
텍스트는 신경망에 주입하기 전에 텐서로 변환되어야 합니다. 변환하는 방법에는 몇 가지가 있습니다.
원-핫 인코딩(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 가 더 나은 성능을 보여주기도 합니다.