코사인, 자카드, 유클리드, 멘하탄 - 유사도

BABY CAT·2022년 8월 10일
0

data

목록 보기
2/6

유사도

1. 코사인 유사도 (-1 ~ +1), 커야 유사도가 높다, 두 벡터 간 코사인 각도, 방향2, 코사인0= +1 동일한 방향
2. 자카드 유사도 (0 ~ +1), 커야 유사도가 높다, 공식: 두 A,B에 대하여 교집합/합집합, 즉 동일하다면 +1
3. 유클리드 유사도 (0~x), 작아야 유사도가 높다, 벡터화된 두 점의 거리를 피타고라스 정리를 통해 구한다
4. 멘하탄 유사도 (0~x), 작아야 유사도가 높다, 사각형 격자 지도를 따라갈 수 있는 최단거리

1. 코사인 유사도

# 1. 코사인 유사도 (-1 ~ +1), 커야 유사도가 높다, 두 벡터 간 코사인 각도, 방향2성, 코사인0도 = +1 동일한 방향

# 코사인 유사도 공식을 def로 선언하여 연산하기

# 불러오기    # [ eq.wqe.ewq ]한문장이 하나의 벡터 하나의 점-원점 선의 방향
import numpy as np
# 스칼라 점 값 < 스칼라의합 벡터 1차원 <  행렬 매트릭스 2차원 행렬 <  3차원부터 텐서
data1 = np.array([1,1,1,1]) # 벡터 데이터 = 1차원 어레이 # 데이터관점에서는 4차원이다 데이터관점에서는 피처수가 차원
# np.linalg.norm(data1) # 코사인유사도 공식에서 l  l  연산임  # linalg.norm  벡터를 정규화  # 원점에서 점으로 선 긋기
# 공식 분자부분 A*B : 벡터 간 곱 > 내적 dot

# 코사인 유사도 공식 -1~+1   +1이 유사도가 가장 높다 -1이 낮다
def cos_i(A,B): #코사인유사도 # 벡터간기울기비교 방향성이 같은지 유사도 판별  #방향같으면 1 역방향이면 -1   구십도면 0 (긍정방향/부정방향)
    return A.dot(B)/(np.linalg.norm(A)*np.linalg.norm(B))

# 코사인 유사도 연산 # 1차원리스트 1차원 벡터 두개  벡터 선 두개의 방향성의 유사도를 연산
# d1 = np.array( [0,5,5,5])
# d2 = np.array( [0,-1,-1,-1])
d1 = np.array( [1,1,1,1])
d2 = np.array( [2,2,2,2])
cos_i(d1,d2) # 값 : -1  각도차 180도 #()안 값이 하나면 에러 
# 코사인 유사도를 cosine_similarity 라이브러리로 측정

# 불러오기    # [ eq.wqe.ewq ]한문장이 하나의 벡터 하나의 점-원점 선의 방향
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer  # TFITF 의 정규화로 벡터라이즈
from sklearn.metrics.pairwise import cosine_similarity # 코사인유사도

# 데이터
data = pd.read_csv('data1.csv', low_memory=False,  ) # 데이터 리드
data = data.head(20000) # 20000 줄/인덱 까지 출력 (영화타이틀:숫자)
data['overview'] = data['overview'].fillna('') # 결측지를 '' 공백문자로 치환

# 벡터라이저 핏
tfidf = TfidfVectorizer (stop_words='english') # 스탑워드 불용어  # 문장가져오기
tfidf_t = tfidf.fit_transform(data['overview']) # 문장을 가져와서 (1차원벡터리스트) 핏_트랜스폼 # 15507개 data니까 자기자신과 15506개의 다른 data의 유사도를 연산할 수 있다 자기자신포함 15507 개의 유사도를 가질 수 있다
tfidf_t

# 벡터화된 데이터로 코사인유사도 측정하는 cos 변수 선언
cos = cosine_similarity(tfidf_t, tfidf_t) # 이만개의 유사도를 가진 것이 이만개니까 # 이만*이만 개의 유사도 # 유사도가 높은 순서로 정렬이된다
cos.shape # (이만,이만)  #오버뷰를 TFIDF정규화벡터화한 것 간의 유사도 측정

# 영화타이틀 데이터 전처리
data.index # 이만개의 인덱
t_idx = dict(zip(data['title'], data.index )) # 집으로 결합해서 딕셔너리화   영화제목 : 인덱스
t_idx

# 특정 영화의 상위 유사도 뽑기
def ck_s_t(t, cosine_sim = cos ):
    idx = t_idx[t]  # (영화타이틀과 인덱) 딕셔너리 / 여기서 [타이틀]을 > 딕셔너리에서 키값을 넣었으니 인덱스를 받는다
    c_sc = list(enumerate(cosine_sim[idx])) # cos는 위에서 이미 정의내려졌다. # (유사도,인덱스) # 그인덱스를 cos로넣으면[ 유사도,유사도,유사도,유사도,유사도...]를 받고 이누머로 인덱스 붙여서 리스트화 # 받은 영화타이틀에 넘버링 #이누머-열거, 각 밸류에 인덱스를 붙여준다  (인덱스,밸류=코사인유사도)
    c_sc = sorted ( c_sc, key=lambda a:a[1] , reverse=True) # (인덱스,유사도)로 정렬# sorted정렬하는함수 # 유사도와 이누머인덱스 둘 중 1인덱값(이누머인덱)을 키로해서 정렬한다 # 인덱이 앞으로온다  (인덱:유사도)
    return c_sc  #  (인덱,유사도) 를 리턴 # c_sc에는 유사도가 높은 순서로 정렬되어있다. 
ck_s_t('Toy Story')[0] # 유사도가장높은것 (자기자신)
ck_s_t('Toy Story')[0:5] # 유사도 상위 5위 뽑기 # (인덱스,유사도) (15348, 0.5258229300737997), 이렇게 뽑혀서 무슨 영화인지 알아보기 힘들다

# 특정 영화의 상위 유사도 영화제목으로 뽑기
def ck_s_t(t, cosine_sim = cos ):
    idx = t_idx[t]
    c_sc = list(enumerate(cosine_sim[idx])) # 넘버링 #이누머-열거
    c_sc = sorted ( c_sc, key=lambda x:x[1] , reverse=True) # reverse=True 내림차순 , 코사인유사도는 높은 것이 좋은 거니까, 디폴트는 오름차순
    m_d = c_sc[1:6] # (인덱스,유사도) (15348, 0.5258229300737997),  # 0인덱은 자기자신이니까 빼고 상위 1,2,3,4,5 위의 유사도가 높은 것을 뽑는다. 
    m_i = [i[0]for i in m_d]  # (인덱스,유사도) 를 하나 뽑아서 [0]인덱스 > 인덱스 뽑아서 리스트로 >  상위 5위까지 인덱스를 뽑았다
    return data['title'].iloc[m_i] #영화타이틀 시리즈에서 그 인덱 값들만 뽑아온다 (판다스시리즈 타입으로 뽑힌다)
pd.DataFrame(ck_s_t('Toy Story'))

2. 자카드 유사도

# 2. 자카드 유사도 (0 ~ +1), 커야 유사도가 높다, 공식: 두 A,B에 대하여 교집합/합집합, 즉 동일하다면 +1

# 자카드 유사도 기본 : len(교집합)/len(합집합) # [ eq.wqe.ewq ]한문장이 하나의 벡터 하나의 점-원점 선의 방향

# 교집합과 합집합
A = set([1,2,3,4,5]) # set 중복제거
B = set([4,5,6,7,8,9])
A&B  # and  교집합
A|B  # or   합집합

# 여러 문장을 자카드 유사도로
data1 = '나는 오늘 정말 피곤해 그래서 힘들어'.split()
data2 = '나는 오늘 정말 못해 그래서 힘들어'.split()
data3 = '나는 오늘 너무 즐거와 그래서 행복해'.split()
data1
intd = set(data1) & set(data2) # 교집합
intd
un = set(data1) | set(data2) # 합집합
un
len(intd)/len(un) # data1과 dat2의 자카드 유사도 : 0.7
un1=set(data1) | set(data3)
intd1=set(data1) & set(data3)
len(intd1)/len(un1) # 0.3  # data1은 data3보다 data2와 더 유사도가 높다

3. 유클리드 유사도

# 아래 유클리드 유사도 라이브러리를 사용하는 방법이 좋다
# 3. 유클리드 유사도 (0~x), 작아야 유사도가 높다, 벡터화된 두 점의 거리를 피타고라스 정리를 통해 구한다

# 피타고라스 정리를 def로 선언하여 연산하는 유클리드 유사도

data1 = '나는 오늘 정말 피곤해 그래서 힘들어'    # [ eq.wqe.ewq ]한문장이 하나의 벡터 하나의 점-원점 선의 방향
data2 = '나는 오늘 정말 못해 그래서 힘들어' 
data3 = '나는 오늘 너무 즐거와 그래서 행복해' 
t_v = TfidfVectorizer()
m_data = t_v.fit_transform( [data1,data2,data3] ) # 각각의 문장들로 점 3개가 만들어졌다.
a = m_data.toarray() # 각각의 문장들로 점 3개가 만들어졌다.
pd.DataFrame(a)

# 피타고라스 정리로 두 점의 거리 계산
def f(A,B):
    return np.sqrt( np.sum((A-B)**2)  ) #  뺴기제곱+빼기제곱에 루트 : 피타고라스정리로 A,B간의 거리를 구한다
    
A = m_data.toarray()[0] #하나의문장으로뽑음 (벡터)  3개의 점
B = m_data.toarray()[1] #하나의문장으로뽑음 (벡터)
C = m_data.toarray()[2] #하나의문장으로뽑음 (벡터)

f(A,B), f(A,C)  

# A는 C와 더 유사하다 # 벡터라이저를 기반으로 뽑았기 때문에 정규화가 필요하다
# > 정규화작업
def e_f(m):
    return m/np.sum(m)
e_f(m_data) #정규화끝난매트릭스데이터
e_b_d = e_f(m_data)
print(e_b_d)
#유클리드 유사도 라이브러리 사용

from sklearn.metrics import euclidean_distances #유클리드거리 소문자-매소드
# m_data 벡터화된 숫자 데이터
euclidean_distances(m_data[0:1], m_data[1:2]) #거리값 # 각 벡터화된 문장을 넣어줌
# e_b_d 는 m_data의 > 유클리드유사도 > 정규화
euclidean_distances(e_m_d[0:1], e_m_d[1:2])

4. 멘하탄 유사도

# 4. 멘하탄 유사도 (0~x), 작아야 유사도가 높다, 사각형 격자 지도를 따라갈 수 있는 최단거리

# 멘하탄 유사도 라이브러리를 활용

from sklearn.metrics.pairwise import manhattan_distances
print( manhattan_distances(m_data[0:1], m_data[1:2])  , manhattan_distances(m_data[0:1], m_data[2:])  )
print( manhattan_distances(e_m_d[0:1], e_m_d[1:2])  ,manhattan_distances(m_data[0:1], m_data[2:])     )

0개의 댓글