간단한 유사도 측정
import numpy as np
from numpy import dot
from numpy.linalg import norm #벡터 크기 구하기
#영화 3가지
#각 열은 영화 대사에 등장한 단어들(사랑, 돈, 운명, 증오)
d1 = np.array([1,1,1,0])
d2 = np.array([0,1,1,1])
d3 = np.array([0,5,5,5])
문서1과 2사이의 유클리디안 거리 구하기
d1d2 사이거리 = 루트 2
d2d3 사이거리 = 루트 48
유클리디안 거리 공식으로는 d2문서가 d1과 가까움.
#d1, d2코사인 유사도
dot(d1, d2) / (norm(d1)*norm(d2))
#d2, d3코사인 유사도
dot(d3, d2) / (norm(d3)*norm(d2))
자카드 유사도
자카드 유사도(d1, d2) = (d1 교집합 d2) / (d1 합집합 d2)
0~1 값
1:분모 = 분자 | 두 문서에 완벽하게 동일한 단어들이 있다.
0:동일한 단어가 없다.
EX)
d1 = '대한민국 하늘 육지'
d2 = '바다 들판 우주'
자카드 유사도 = 0
d1 = '바다 하늘 육지'
d2 = '바다 들판 우주'
자카드 유사도 = 1/5
단어가방(Bag Of Words): corpus에 등장한 단어들의 빈도수 조사
ex) array([[1, 2, 2, 1, 1, 1]])
from sklearn.feature_extraction.text import CountVectorizer
#CountVectorizer: 단어의 빈도수로 벡터 생성
corpus=['나는 지금 자연어 처리를 공부해요. 나는 자연어 좋아요.']
vector=CountVectorizer()
vector.fit_transform(corpus)
#fit: 각각 유니크한 단어별로 인덱스 부여
#transform: corpus에 저장된 문장을 fit결과에 맞춰 변환(빈도수)해라
ex)
corpus=['나는 지금 자연어 처리를 공부해요. 나는 자연어 좋아요.']
fit 각 단어마다 인덱스 (0~5)
transform [2 1 2 1 1 1]
sparse matrix(희소행렬: 행렬 요소값이 대부분 0인 행렬 => 공간 낭비, 연산량이 많음)
[
[2 1 2 1 1 1]
]
vector.fit_transform(corpus).toarray()
vector.vocabulary_ #인덱스 번호 출력
영화 추천 시스템 만들기
영화의 줄거리를 기반으로 추천(tfidf -> cosine sim[코사인유사도] -> 추천)
영화 데이터로 유사도 측정해보기
import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity
1.데이터 불러오기
from google.colab import drive
drive.mount('/content/drive')
df = pd.read_csv("/content/drive/MyDrive/NLP/movies_metadata.csv")
2.상위 5000개의 영화데이터만 추출하여 변수에 저장
df = df.head(10000)
df
3.description열 추출
결측값 처리방법: groupby, fillna, replace, interpolate
df.info()
df.isnull().sum(axis=0) #열단위로 결측값 정보
#Nan을 빈 문자열로 대체하기
df['overview'] = df['overview'].fillna("")
df['overview'].isnull().sum() #결측값 없음
4.TFIDF 행렬 구성 (오천*단어개수)
tfidf = TfidfVectorizer(stop_words = 'english')
# stop_words = 'english' 에 해당하는 단어를 제거하고 작동
tfidf_m = tfidf.fit_transform(df['overview'])
tfidf_m.shape #크기(10000, 32350) 단어 32350개
tfidf_m
5.코사인 유사도
cos_sim = cosine_similarity(tfidf_m, tfidf_m)
cos_sim.shape
cos_sim[0] #토이스토리와 다른 영화 사이의 코사인 유사도
6.자기 자신 제외하고 그중에서 상위 10개 찾기
df['title'] # title 행인덱스, 테이터 출력
df.index# 행의 인덱스 번호가 나온다.
data = dict(zip(df['title'],df.index)) # key-value 쌍
i = data['Toy Story']
print(i)
data
def recommend(t, cos_sim=cos_sim): #t:영화 제목 전달
idx = data[t] #해당 영화의 인덱스 값
#내림 차순 정렬후 상위 10뽑기, 제일 높은 값은 자기 자신이니 0번 제거. 1번부터 10까지
sim_scores = list(enumerate(cos_sim[idx]))
ss = sorted(sim_scores, key = lambda x:x[1],reverse = True)#인덱스번호, 코사인유사도
ss = ss[1:11]
res = [i[0] for i in ss]#상위 10개 인덱스 번호
return df['title'].iloc[res]#상위 10개 인덱스와 영화 제목
recommend('Toy Story')
단어가방(Bag Of Words)
corpus에 등장한 단어들의 빈도수 조사
ex) array([[1, 2, 2, 1, 1, 1]])
from sklearn.feature_extraction.text import CountVectorizer
#CountVectorizer: 단어의 빈도수로 벡터 생성
corpus=['나는 지금 자연어 처리를 공부해요. 나는 자연어 좋아요.']
vector=CountVectorizer()
vector.fit_transform(corpus)
#fit: 각각 유니크한 단어별로 인덱스 부여
#transform: corpus에 저장된 문장을 fit결과에 맞춰 변환(빈도수)해라
ex)
corpus=['나는 지금 자연어 처리를 공부해요. 나는 자연어 좋아요.']
fit 각 단어마다 인덱스 (0~5)
transform [2 1 2 1 1 1]
sparse matrix(희소행렬: 행렬 요소값이 대부분 0인 행렬 => 공간 낭비, 연산량이 많음)
[
[2 1 2 1 1 1]
]
vector.fit_transform(corpus).toarray()
vector.vocabulary_ #인덱스 번호 출력
TFIDF(TF * IDF)
참고 문서 링크: https://ko.wikipedia.org/wiki/Tf-idf
tf-idf - 위키백과, 우리 모두의 백과사전
위키백과, 우리 모두의 백과사전. TF-IDF(Term Frequency - Inverse Document Frequency)는 정보 검색과 텍스트 마이닝에서 이용하는 가중치로, 여러 문서로 이루어진 문서군이 있을 때 어떤 단어가 특정 문서
ko.wikipedia.org
1. DTM 만들기
from sklearn.feature_extraction.text import CountVectorizer,TfidfVectorizer
#CountVectorizer: DTM을 만든다.
#TfidfVectorizer :
corpus=[#문서 3개가 있다고 가정
'I love you.',
'I can do it',
'I want your love'
]
#행 문서 | 열 단어 종류 개수
v = CountVectorizer()
v.fit_transform(corpus)
#유니크한 단어를 뽑고 빈도수 조사
#fit정보를 바탕으로 수치로 변환
v.fit_transform(corpus).toarray()
#3행 7열: 문서를 구성하는 단어들을 수치로 표시
#출력값은 DTM이다. CountVectorizer으로 DTM을 만든다.
v.vocabulary_
#인덱스번호와 함께 딕셔너리 형태로 출력
#내부적으로 I의 단어길이가 2보다 작아서 없어짐.
2.TFIDF객체 생성하기
tfv = TfidfVectorizer()
tfv.fit_transform(corpus).toarray()
# tfidf 형태로 출력
# tfidf값이 크다 tf , idf 모두 크다 -> 단어의 빈도수가 큼
#idf가 크려면 분모의 df(t)가 커질수록 = idf가 작아짐 = 단어가 많은 문서에서 등장, 단어가 흔하다.는 의미
#특정 단어가 많이 등장하면서, 흔치 않은 단어여야한다.
#ex) "love" 단어는 여러문서에 걸쳐서 나온다. can은 흔하지 않은 단어다.
#한 문서에서 'love'와 'can'이 등장하는 빈도는 같지만 'love'는 다른 문서에도 흔함. 'can'은 이 문장에서만 볼 수 있어 흔치 않다.
#'can'이 더 중요한 요소다.
# 각각의 문서에서 중요한 단어가 무엇인지 알 수 있음.
NLP 인코딩 과정 정리
1.문서구성 단어 추출
2.DTM 구성: 문서단위로 단어의 빈도수 행렬
3.유클리디안 거리가 아닌 코사인 유사도를 구함
-> 단순히 두벡터의 거리만 아니라 두벡터간 각도를 이용해 유사도를 나타냄
4.DTM을 TFIDF로 변환해서 사용
5,TFIDF로 코사인유사도을 이용해서 유사한 문서를 검색
(1)해당 단어를 매우 중요한 단어로 사용한다는 것을 구분할 수 있음
(2)빈도수가 많지만 다른 문서에서도 등장하면 중요하지 않은 단어
(3)다른 문서와 비교해서 중요도를 알 수 있어 tfidf를 사용한다.
ex) 'The' 단어는 빈도수 높음, 단어를 포함하는 문서 많음, tfidf값 작음. -> 중요한 단어 아님
참고)
TF-IDF 값은 한 문서에서 단어가 등장하는 빈도가 높을수록 커지고(term frequency),
반대로 코퍼스에서 해당 단어를 포함하는 문서가 많을수록 반비례해서 작아진다(inverse document frequency).
특정 문서 내에서 단어 빈도가 높을 수록, 그리고 전체 문서들 중 그 단어를 포함한 문서가 적을 수록 TF-IDF값이 높아진다.
따라서 이 값을 이용하면 모든 문서에 흔하게 나타나는 단어를 걸러내는 효과를 얻을 수 있다.
IDF의 로그 함수 안의 값은 항상 1 이상이므로, IDF값과 TF-IDF값은 항상 0 이상이 된다.
특정 단어를 포함하는 문서들이 많을 수록 로그 함수 안의 값이 1에 가까워지게 되고,
이 경우 IDF값과 TF-IDF값은 0에 가까워지게 된다.
'자연어처리(NLP) & CHAT GPT > NLP' 카테고리의 다른 글
| [NLP] 신경망기반 텍스트 분류 - 실습 (0) | 2023.08.02 |
|---|---|
| [NLP] 신경망기반 텍스트 분류 - 개념 (0) | 2023.08.01 |
| [NLP] 중요한 정규표현식 (0) | 2023.07.30 |
| [NLP] 언어 모델링 - 개념 (0) | 2023.07.29 |
| [NLP] 텍스트전처리 - 실습 (0) | 2023.07.28 |