카테고리 없음

12. Text Data

nananakh 2023. 7. 6. 16:22

만약 A문서, B문서 두개의 text 문서가 있다고 가정을 해보자.

우리는 A문서와 B문서 두 문서의 유사도 분석을 진행하고자 한다.

 

문서의 유사도를 분석할때 각 문서의 stopwords(불용어)를 제거한 모든 문장의 단어의 출현 횟수를 counting 해주고, 그 단어들로 두 문서의 내용이 얼마나 유사한지 유사도를 분석한다.

 

그런데 두 문서의 유사도 분석에서 중요한 것이 있다. 만약 우리가 문서를 작성할 때 문서의 내용과는 관계 없이 흔히 쓰이는 표현 혹은 단어가 있다고 생각을 해보자.

 

A문서와 B문서가 완전 상반된 내용을 가지고 있는 문서라도 흔히 쓰이는 표현 혹은 단어로 인해 유사도가 높다고 분석이 될 수도 있는 경우가 발생한다. 이때 TF-IDF vectonnizer를 사용한다.

 

TF-IDF vectonnizer는 각 문서에서 나오는 각 단어의 출현 횟수를 모두 TF-IDF 값으로 변환시켜준다.

 TF-IDF 값이란, 출현 횟수가 높은 흔히 쓰이는 단어의 존재감을 0에 수렴하게 낮춰주고, 문서의 주요 내용을 결정하는 출현 횟수가 낮은 희귀한 단어의 존재감을 올려줘서 문서간 유사도 비교의 정확성을 높혀준다.

  That Nice Car Has
A 100 4 1 0
B 105 0 1 2
~ ~ ~ ~ ~
1000개 문서 999개 문서에서 출현  ~ 9개 문서에서 출현

TF-IDF 값 계산 공식은 다음과 같다. 하지만 외울 필요는 없다. 함수를 사용하면 자동으로 계산이 된다.

 

A문서에서 단어 ThathasTF-IDF를 구한다고 생각해보자.

TF-IDF = tf(A문서에서 That or has 단어의 출현 횟수)*idf

Idf = log(전체 문서의 수 / 1+단어 That or has이 출현한 문서의 수)

 

ThatA문서 >> 100*log(1000/1000) => 100*log1 >> 100*0 = 0

HasB문서 >> 2*log(1000/10) => 2*log100 > 2*2 = 4

 

ThatIDF 값이 0이므로 That의 모든 문서의 TF-IDF 값은 다 0이다. 그런데 보통 0.~~~이 나온다. 0은 안나온다.

 

이렇게 문서의 유사도 비교를 준비 했다면 cosine similarity를 사용해 비교한다

cosine similarity는 간단하다. 그냥 두 벡터간 코사인값을 이용해서 측정하는 방법이다.

 

계산된 유사도가 -1(180)이면 서로 완전히 반대되는 경우, 0(90)이면 서로 독립된 경우, 1(0)이면 서로 완전히 같은 경우를 말한다.

 

정리하면, 문서의 유사도 비교를 위해서는 문서의 내용을 결정하는 던어의 존재감을 극대화 하기 위해 비교하고자 하는 각 문서의 token 출현 횟수를 TF-idf 값으로 변환 시킨 뒤, cosin similarity를 이용해 문서의 유사도를 비교하는 것이다.

 

이제 설명을 마치고, 두개의 영화 리뷰의 유사도를 분석하는 코드를 만들어보자.

우선, 유사도 분석 코드와 머신러닝의 기본 순서가 유사해서 머신러닝 모델을 기준으로 설명을 진행하겠습니다.

 

첫번째, 선형회귀라는 간단한 모델을 만들었습니다.

model = linear_model.LinearRegression()

 

 

두번째, fit()이라는 함수를 사용해서 모델에게 원하는 학습을 시켜주었습니다.

model.fit(x, y)

세번째, predict()함수로 학습이 끝나면 새로운 데이터로 예측을 해달라는 명령을 주었습니다.

model.predict(x_test)

마지막으로, 예측된 값과 실제 값을 비교하며 평가 지표를 계산해달라고 했습니다.

metrics library 안에 mean_squared_error 함수가 들어있습니다.

metrics.mean_squared_error(model.predict(x_test), y_test)

 

이제 코드를 짜줍니다.

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

sklearn은 파이썬을 대표하는 머신러닝 라이브러리입니다. 저희는 sklearn의 라이브러리의 feature_extraction에서 TfidfVectorizer을 가져올 것입니다. feature_extraction란, eature는 x데이터 열의 값이고 extraction는 추출이라는 뜻입니다.

즉, x데이터 열의 값을 추출한다는 뜻입니다.

  단어 단어 단어 단어
A문서 TF-IDF TF-IDF TF-IDF TF-IDF
B문서 TF-IDF TF-IDF TF-IDF TF-IDF

각 x데이터 열의 값을 추출해서 TF-IDF 값으로 변환하기 때문입니다.

metrics는 평가지표라는 뜻입니다. 이곳에 cosine similarity가 있어서 꺼내줍니다.

 

우선 'shawshank.txt', 'godfather.txt' 두개의 파일을 모두 꺼내줍니다.

file = open('godfather.txt', 'r', encoding = 'utf-8')
lines = file.readlines()
print(lines)

여기서 godfather 리뷰 파일은 리스트 형식으로 ['~', '~~', ~~] 되어 있었다. 그래서 우리는 for문을 돌려서 문자열을 뽑아 냈는데 join()함수를 사용하면 바로 출력이 가능하게 코드가 간단해진다.

file = open('godfather.txt', 'r', encoding='utf-8')
lines = file.readlines()
doc1 = ' '.join(lines)

file = open('shawshank.txt', 'r', encoding='utf-8')
lines = file.readlines()
doc2 = ' '.join(lines)

join()함수는 ()에 리스트가 들어간다. 리스트에 있는 값을 꺼내서 리스트 값마다 ' '에 있는 값으로 채워주는 것이다.

여기서는 ' '.join(['리뷰 내용', '리뷰 내용', ~~~]) 이므로 리뷰 내용 '리뷰 내용 리뷰 내용 ~~'으로 바꿔준다.

 

이제 두 문서의 리스트를 하나의 문자열로 바꿔주었다. 이제 두 문서를 하나의 리스트로 묶어주자. TF-IDF 계산을 위해서이다.

couple = [doc1, doc2]

TF-IDF 계산은 머신러닝의 fit()함수를 사용할 때와 비슷하다.

 

첫번째,  TF-IDF 계산을 위한 변수를 하나 생성해준다.

vector = TfidfVectorizerf()

두번째, 비교 대상의 두 문서가 묶인 리스트를 TF-IDF 계산을 위한 변수에게 학습을 시킨다.

vector.fit(couple)

세번째, 학습을 시킨 뒤 couple 값을 TF-IDF 값으로 바꿔준다.

result = vector.transform(couple)

여기서 시각화를 좋게 만들고 싶으면 todense() 함수를 추가 시킨다. 하지만 모델의 성능을 위해서는 추가하지 않는 것이 좋다. 왜냐면 todense() 함수는 null 값도 전부 표현해서 보여주기 때문이다.

  단어 단어 단어 단어 단어 단어 단어
doc1 12 0 123 0 12 21 42
doc2 0 23 0 120 0 123 232

0이 지금은 괜찮아 보이지만 매우 긴 문장이라면 메모리 용량을 많이 차지한다. todense() 함수는 안쓰는 것이 좋다.

 

이 코드를 한줄로 다시 작성해보자.

couple = [doc1, doc2]
vector = TfidfVectorizer()
result = vector.fit_transform(couple) #.todense()

이제 유사도 비교를 진행하자.

우선 지금 result는 [[doc1의 TF-IDF 값], [doc2의 TF-IDF 값]]으로 이루어져 있다.

result[0]은 doc1의 TF-IDF 값, result[1]은 doc2의 TF-IDF 값이다.

print(cosine_similarity(result[0], result[1]))
[[0.9437827]]

DataFrame으로 시각화를 시켜보자.

import pandas as pd

x = pd.DataFrame(cosine_similarity(result[0], result[1]))
print(x)

이때, 시각화를 위해서는 위의 코드에서 todense() 함수를 활성화 시켜야 한다.

 

만약 비교 파일이 100개라고 하면 result[0]~result[100] 이렇게 하나하나 칠 수가 없다.

import pandas as pd

couple = [doc1, doc2, doc3]
vector = TfidfVectorizer()
result = vector.fit_transform(couple).todense()

x = pd.DataFrame(cosine_similarity(result, result)
x.index = ['영화 이름1', '영화 이름2', '영화 이름3']
x.columns = ['영화 이름1', '영화 이름2', '영화 이름3']

print(x)

이렇게 전체 행과 전체 행을 비교하거나, 전체 행과 특정 행 하나만 비교가 가능하다.