DL.5 _ 자연어처리(NLP)
DataScience/NLP

DL.5 _ 자연어처리(NLP)

728x90
  • 자연어 처리에서 등장하는 용어들
    • 말뭉치(Corpus) : 특정한 목적을 가지고 수집한 텍스트 데이터
    • 문서(Document) : 문장(Sentence)들의 집합
    • 문장(Sentence) : 여러 개의 토큰(단어, 형태소 등)으로 구성된 문자열. 마침표, 느낌표 등의 기호로 구분
    • 어휘집합(Vocabulary) : 코퍼스에 있는 모든 문서, 문장을 토큰화한 후 중복을 제거한 토큰의 집합
  • 전처리(Preprocessing)
    • 토큰화(Tokenization)
    • 차원의 저주(Curse of Dimensionality)
    • 불용어(Stop words)
    • 어간 추출(Stemming)
    • 표제어 추출(Lemmatization)
  • 등장 횟수 기반의 단어 표현(Count-based Representation)
    • 문서-단어 행렬(Document-Term Matrix, DTM)
    • Bag-of-words
    • TF-IDF
    • TfidfVectorizer

자연어처리란?

자연어 혹은 자연 언어는 사람들이 일상적으로 쓰는 언어를 인공적으로 만들어진 언어인 인공어와 구분하여 부르는 개념인데 이런 자연어를 컴퓨터로 처리하는 기술을 자연어 처리(Natural Language Processing, NLP)라고 한다.

자연어 처리 실습

Job descrition을 찾아 스크래핑한 데이터를 이용해 실습을 진행

- 텍스트 전처리

모델의 성능을 높이기 위해서는 전처리가 필수이다.

  • 내장 메서드를 사용한 전처리 (lower, replace, ...)
  • 정규 표현식(Regular expression, Regex)
  • 불용어(Stop words) 처리
  • 통계적 트리밍(Trimming)
  • 어간 추출(Stemming) 혹은 표제어 추출(Lemmatization)
# 데이터 불러오기
df = pd.read_csv('https://ds-lecture-data.s3.ap-northeast-2.amazonaws.com/indeed/Data_Scientist.csv')

# 필요한 칼럼만 설정
df = df[['title','company','description']]

# description칼럼의 중복을 제거
df = df.drop_duplicates(['description'], keep='last')

# 토큰을 정제
import spacy
from spacy.tokenizer import Tokenizer

nlp = spacy.load("en_core_web_sm")
tokenizer = Tokenizer(nlp.vocab)

# 토큰화를 위한 파이프라인을 구성
tokens = []

for doc in tokenizer.pipe(df['description']):
    doc_tokens = [re.sub(r"[^a-z0-9]", "", token.text.lower()) for token in doc]
    tokens.append(doc_tokens)

df['tokens'] = tokens

- 불용어 사전을 사용해 토큰을 정제

정제된 단어에는 'I', 'and', 'of'같은 단어들이 있는데 리뷰 관점에서 아무런 의미가 없다.

이러한 단어를 'Stop words(불용어)'라고 한다.

NLP 라이브러리는 접속사, 관사, 부사, 대명사, 일반동사 등을 포함한 일반적인 불용어를 내장하고 있는데 내장함수에 커스터마이징을 통해서 추가하거나 삭제해서 사용가능하다.

STOP_WORDS = nlp.Defaults.stop_words.union(["data", "work",""])

tokens = []

for doc in df['tokens']:
    
    doc_tokens = []
    
    for token in doc: 
        if token not in STOP_WORDS:
            doc_tokens.append(token)
   
    tokens.append(doc_tokens)
    
df['tokens'] = tokens

import squarify
import matplotlib.pyplot as plt

wc_top20 = wc[wc['rank'] <= 20]

squarify.plot(sizes=wc_top20['percent'], label=wc_top20['word'], alpha=0.6 )
plt.axis('off')
plt.show()

사용 빈도가 상위 20개인 단어 시각화

- 표제어 추출(Lemmatization) 사용

표제어 추출(Lemmatization)은 어간추출보다 체계적이다.
단어들은 기본 사전형 단어 형태인 Lemma(표제어)로 변환되는데 명사의 복수형은 단수형으로, 동사는 모두 타동사로 변환된다.
이렇게 단어들로부터 표제어를 찾아가는 과정은 Stemming 보다 많은 연산이 필요하기때문에 시간이 오래걸린다는 단점이 있다.

Stemming 에서는 wolf -> wolf, wolves -> wolv 로 변형되었지만,
Lemmatization에서는 wolf -> wolf, wolves -> wolf 로 변형되는 것을 볼 수 있다.

# Lemmatization 과정을 함수로 만들어 봅시다
def get_lemmas(text):

    lemmas = []
    
    doc = nlp(text)

    for token in doc: 
        if ((token.is_stop == False) and (token.is_punct == False)) and (token.pos_ != 'PRON'):
            lemmas.append(token.lemma_)
    
    return lemmas
   
wc = word_count(df['lemmas'])

wc = wc.iloc[2:]
wc.head(10)

 

등장 횟수 기반의 단어 표현

- 텍스트 문서 벡터화

머신러닝 모델에서 텍스트를 분석하기 위해서는 벡터화(Vectorization)하는 과정이 필요하다.
벡터화란 텍스트를 컴퓨터가 계산할 수 있도록 수치정보로 변환하는 과정이다.

등장 횟수 기반의 단어 표현(Count-based Representation)은 단어가 특정 문서(혹은 문장)에 들어있는 횟수를 바탕으로 해당 문서를 벡터화한다.
대표적인 방법으로는 Bag-of-Words(TF, TF-IDF) 방식이 있다.

  • 문서-단어 행렬(Document-Term Matrix, DTM)

 

- Bag-of-Words(BoW) : TF(Term Frequency)

Bag-of-Words(BoW)는 가장 단순한 벡터화 방법 중 하나입니다.
문서(혹은 문장)에서 문법이나 단어의 순서 등을 무시하고 단순히 단어들의 빈도만 고려하여 벡터화하는 방법이다.

 

- Bag-of-Words(BoW) : TF-IDF (Term Frequency - Inverse Document Frequency)

다른 문서에 잘 등장하지 않는 단어라면 해당 문서를 대표할 수 있는 단어가 될 수 있다.

TF-IDF(Term Frequency-Inverse Document Frequency)이렇게 다른 문서에 등장하지 않는 단어, 즉 특정 문서에만 등장하는 단어에 가중치를 두는 방법이다.

TF-IDF의 수식은 다음과 같다.

- 유사한 문서 찾기(TfidfVectorizer 사용)

TfidfVectorizer를 이용해 각 문서들을 벡터화 한 후 KNN 모델을 만들고,
내가 원하는 job description을 질의해 가장 가까운 검색 결과들을 가져오고 분석한다.

나는 88번 index의 job description와 5개의 가장 유사한 job description이 있는 index를 찾아보겠다.

from sklearn.feature_extraction.text import TfidfVectorizer

tfidf = TfidfVectorizer(stop_words='english', max_features=3000,tokenizer=get_lemmas)

data_tfidf = tfidf.fit_transform(df['description'])

data_tfidf = pd.DataFrame(data_tfidf.todense(), columns=tfidf.get_feature_names())

from sklearn.neighbors import NearestNeighbors

# dtm을 사용히 NN 모델을 학습시킵니다. (디폴트)최근접 5 이웃.
nn = NearestNeighbors(n_neighbors=5, algorithm='kd_tree')
nn.fit(data_tfidf)

# 88번째와 유사한 인덱스 찾기
nn.kneighbors([data_tfidf.iloc[88]])

array([[ 88, 268, 267, 192, 178]]))

 

88번째와 유사한 문장의 index 5개는 [ 88, 268, 267, 192, 178] 이러한 결과로 나타났다.

728x90