# 코사인 유사 도 # cosineSilmilarity # 영화 추천 시스템 ​ ■ 코사인 유사 도 ( Cosine Similarity ) ​​​​​​- 코사인 유사 도 는 두 벡터 간 의 코사인 각도 를 이용 해서 구할 수 있 는 두 벡터 의 유사 도 를 말 함 - 두 벡터 의 방향 이 완전히 동일 할 경우 엔 1 , 90 도 각 을 이루 면 0 , 180 도 반대 방향 이 면 - 1 의 값 을 갖 게 됨 - 즉 , 코사인 유사 도 는 [ - 1 ~ 1 ] 사이 값 을 가지 며 , 1 에 가까울 수록 유사 도 가 높 다고 판단 함 - 직관 적 으로 이해 하 면 , 두 벡터 가 가리키 는 방향 이 얼마나 유사 한가 ​ 를 의미 ​​- 두 벡터 A , B 에 대해서 코사인 유사 도 는 식 으로 표현 하 면 아래 와 같 음 - 분자 에 A 와 B 의 각 원소 별 로 곱해 주 고 , - 분모 는 각 원소 를 제곱 해서 루트 씌워 준 것 ( Norm ) 을 각각 곱해 줌 ㄴ 선형 대수학 에서 , Norm 은 절대값 에서 추상 화 된 개념 ​​- 문서 단어 행렬 ( DTM - Document - Term Matrix ) 이나 TF - IDF ( Term Frequency ( 단어 빈도 ) - Inverse Document Frequency ( 역 문서 빈도 ) ) 행렬 을 통해서 문서 의 유사 도 를 구하 는 경우 에 는 , 문서 단어 행렬 이나 TF - IDF 행렬 이 각각 의 특징 벡터 A , B 가 됨 ※ TF - IDF : 단어 의 빈도 와 역 문서 빈도 를 사용 해 , DTM 내 의 각 단어 들 마다 중요 한 정도 를 가중치 로 줌 ​- 문서 단어 행렬 에 대해서 코사인 유사 도 를 구하 는 간단 한 예제 를 보 자 · 문서 1 : 저 는 사과 좋 아요 · 문서 2 : 저 는 바나나 좋 아요 · 문서 3 : 저 는 바나나 좋 아요 저 는 바나나 좋 아요 ​- 위 세 문서 에 대해 문서 단어 행렬 ( DTM ) 을 만들 면 아래 와 같 음 ​​- 파이썬 에서 코사인 유사 도 를 구하 는 방법 은 여러 가지 가 있 는데 , Numpy 이용 해서 계산 해 보 자 ​ from numpy import dotfrom numpy . linalg import normimport numpy as npdef cos _ sim ( A , B ) : return dot ( A , B ) / ( norm ( A ) * norm ( B ) ) ​ doc 1 = np . array ( [ 0 , 1 , 1 , 1 ] ) # 문서 1 , 2 , 3 을 array 로 생 성 doc 2 = np . array ( [ 1 , 0 , 1 , 1 ] ) doc 3 = np . array ( [ 2 , 0 , 2 , 2 ] ) ​- 예 를 들 었 던 문서 1 , 문서 2 , 문서 3 에 대해 각각 Bow 를 만들 었 음 . 각 문서 에 대한 코사인 유사 도 계산 해 보 자 ​ print ( cos _ sim ( doc 1 , doc 2 ) ) 0 . 67 print ( cos _ sim ( doc 1 , doc 3 ) ) 0 . 67 print ( cos _ sim ( doc 2 , doc 3 ) ) 1 . 00 ​- 문서 1 과 문서 2 그리고 문서 1 과 문서 3 의 코사인 유사 도 가 같 고 ( 0 . 67 ) , 문사 2 와 문서 3 의 코사인 유사 도 는 1 로 나왔 음 ㄴ 문서 3 은 문서 2 에서 , 단지 모든 단어 의 빈도수 가 1 씩 증가 한 것 - 다시 말 해 , 한 문서 내 의 모든 단어 의 빈도수 가 동일 하 게 증가 하 는 경우 에 는 , 기존 의 문서 와 코사인 유사 도 값 이 1 이 라는 것 임 ​- 다른 문서 들 과 거의 동일 한 패턴 을 가진 문서 가 있 는데 , 단지 원문 길이 가 길 다는 이유 로 다른 문서 들 보다 유사 도 가 더 높 게 나온다면 원 하 는 결과 가 아님 - 이렇 듯 코사인 유사 도 는 문서 의 길이 가 다른 상황 에서 도 비교 적 공정 한 비교 를 할 수 있 도록 함 ​- 이 는 코사인 유사 도 를 구할 때 , 벡터 의 크기 가 아니 라 벡터 의 방향 ( 패턴 ) 에 초점 을 두 기 때문 - 코사인 유사 도 가 벡터 의 유사 도 를 구하 는 또 다른 방법 인 내적 과 는 다른 차이점 임 ! ■ 영화 추천 시스템 ​- kaggle 에서 사용 되 었 던 데이터 셋 받 아서 사용 해 보 자 ㄴ https : / / www . kaggle . com / rounakbanik / the - movies - dataset ㄴ 위 링크 에서 movies _ metadata . csv 파일 다운로드 받 으면 됨 ㄴ 총 24 개 의 열 을 가진 45 , 466 개 샘플 로 구성 된 영화 정보 데이터 ​ import pandas as pddata = pd . read _ csv ( "/ content / drive / My Drive / dataset / movies _ metadata . csv ", low _ memory = False ) ​ data . head ( 2 ) # 양 옆 에 정보 더 많 은데 , 가운데 부분 만 우선 캡쳐 ​... . ..​- 코사인 유사 도 에 사용 할 데이터 는 영화 제목 에 해당 하 는 title 열 과 줄거리 에 해당 하 는 overview 열 - 좋 아 하 는 영화 를 입력 하 면 , 해당 영화 의 줄거리 와 줄거리 가 유사 한 영화 를 찾 아서 추천 하 는 시스템 만들 각 ​ data = data . head ( 2000 ) # 데이터 많 아서 2 천 개 만 가져옴 , 더 가져와도 무방 ㅋㅋ data [ ' overview ']. isnull ( ) . sum ( ) # 16 , TF - IDF 를 할 때 , Null 값 이 있 으면 에러 발생 data [ ' overview '] = data [ ' overview ']. fillna ( '') # Null 값 에 공백 을 넣 어 줌 data [ ' overview ']. isnull ( ) . sum ( ) # 0 , Null 없 어 진 것 확인 완료 ​ from sklearn . feature _ extraction . text import TfidfVectorizer ​ tfidf = TfidfVectorizer ( stop _ words =' english ') # 불 용어 tfidf _ matrix = tfidf . fit _ transform ( data [ ' overview ']) # overview 에 대해서 tf - idf 수행 ​ print ( tfidf _ matrix . shape ) ( 2000 , 13918 ) # 2 천 개 단어 에 , 13 , 918 단어 사용 ​ from sklearn . metrics . pairwise import linear _ kernel # 두 벡터 의 dot productcosine _ sim = linear _ kernel ( tfidf _ matrix , tfidf _ matrix ) # 코사인 유사 도 구함 ​ indices = pd . Series ( data . index , index = data [ ' title ']). drop _ duplicates ( ) print ( indices . head ( ) ) # 타이틀 과 인덱스 를 가진 테이블 을 만 듦 , 영화 타이틀 입력 하 면 인덱스 리턴 하 기 위함 titleToy Story 0 Jumanji 1 Grumpier Old Men 2 Waiting to Exhale 3 Father of the Bride Part II 4 dtype : int 64 ​ idx = indices [ ' Toy Story '] print ( idx ) 0 ​ def get _ recommendations ( title , cosine _ sim = cosine _ sim ) : # 선택 한 영화 의 타이틀 로부터 해당 되 는 인덱스 를 받 아 옴 , 이제 선택 한 영화 를 가지 고 연산 할 수 있 음 ​ idx = indices [ title ] ​ # 모든 영화 에 대해서 해당 영화 와 의 유사 도 를 구함 sim _ scores = list ( enumerate ( cosine _ sim [ idx ] ) ) ​ # 유사 도 에 따라 영화 들 을 정렬 ​ sim _ scores = sorted ( sim _ scores , key = lambda x : x [ 1 ] , reverse = True ) ​ # 가장 유사 한 10 개 의 영화 를 받 아 옴 ​ sim _ scores = sim _ scores [ 1 : 11 ] ​ # 가장 유사 한 10 개 의 영화 의 인덱스 를 받 아 옴 ​ movie _ indices = [ i [ 0 ] for i in sim _ scores ] ​ # 가장 유사 한 10 개 의 영화 의 제목 을 리턴 ​ return data [ ' title ']. iloc [ movie _ indices ] ​ get _ recommendations ( ' Toy Story ')​ 1071 Rebel Without a Cause 1932 Condorman 485 Malice 448 For Love or Money 1032 The Sunchaser 1884 Child ' s Play 3748 I Shot Andy Warhol 591 Window to Paris 314 The Shawshank Redemption 180 Mute WitnessName : title , dtype : object ​