본문 바로가기

AI Theory/key concept of AI

사이킷런을 활용한 추천 시스템

사이킷런을 활용한 추천 시스템

추천 시스템

  • 사용자(user)에게 관련된 아이템(item)을 추천해 주는 것

영화 추천 시스템을 만든다고 생각해보자.

추천 시스템은 영화들을 아래 사진과 같이 좌표 평면에 배치하여 표현한다.

그리고 영화들 간 거리가 좁을수록 유사도가 높다고 판단하여 사용자가 예전에 봤던 영화와 유사한 영화를 추천한다.

 

신규 사용자에 대해서도 개인정보가 유사한 기존 사용자의 영화 데이터를 기반으로 영화를 추천한다.

 

이때 추천 시스템은

  • 범주형 데이터를 다룬다.
  • 범주형 데이터를 숫자 벡터로 변환한 뒤 유사도를 계산하여 유사도가 높은 제품을 추천한다.

는 사실을 알 수 있다.


코사인 유사도(cosine similarity)

  • 유사도를 계산하는 가장 잘 알려진 방법
  • 자연어 처리(Natural Language Processing) 분야의 문서 유사도 측정, 추천 시스템, 검색 엔진 등 다양한 분야에서 활용된다.
  • 두 벡터간 코사인 값을 이용해 두 벡터의 유사도를 계산한다.
  • 두 벡터 방향이 이루는 각에 코사인을 취해서 구한다. 
    • 따라서 두 벡터의 방향이 동일할 경우 1, 90도를 이룰 경우 0, 180도를 이룰경우 -1이다.
    • 1에 가까울수록 유사도가 높다고 볼 수 있다.

 

두 벡터간 유사도를 구하는 방법으로는 코사인 유사도 외에도 유클리드 거리, 자카드 유사도, 피어슨 상관계수 등이 있다.

 

numpy를 활용한 코사인 유사도

import numpy as np

t1 = np.array([1, 1, 1])
t2 = np.array([2, 0, 1])

# 코사인 유사도를 구하는 함수
from numpy import dot
from numpy.linalg import norm

def cos_sim(A, B):
	return dot(A, B)/(norm(A)*norm(B)
    
cos_sim(t1, t2) #0.775

 

사이킷런을 활용한 코사인 유사도

from sklearn.metrics.pairwise import cosine_similarity

# 해당 모듈은 2차원 배열을 받으므로 수정해준다
t1 = np.array([[1, 1, 1]])
t2 = np.array([[2, 0, 1]])
cosine_similarity(t1,t2)

추천시스템의 종류

  • 협업 필터링 방식과 콘텐츠 기반 필터링 방식, 딥러닝을 활용한 추천 방식, 여러 방법을 결합한 하이브리드 방식이 있다.
  • 협업 필터링 방식은 다시 사용자 기반, 잠재요인 협업 필터링 방식으로 나뉜다.

추천 시스템의 종류 (출처: 모두의 연구소)

 


콘텐츠 기반 필터링(Content Based Filtering)

  • 어떤 사람이 한 영화를 좋아했다면, 비슷한 콘텐츠의 아이템을 추천하는 방식
    • 예를 들어 아이언맨1을 본 사람에게 아이언맨2,3을 추천해 주는 것
  • 순수하게 콘텐츠의 내용만을 비교해서 추천
  • 아이템의 속성 정보를 이용해 아이템간 유사도를 계산하고 사용자가 이전에 선호한 아이템과 유사한 아이템을 추천한다.
  • 장르, 배우, 감독 등 영화의 특성(feature)들이 콘텐츠의 유사도를 판단할 수 있는 요인이다.

 

영화 데이터를 예제 데이터로 콘텐츠 기반 필터링을 하는 코드를 작성해보자

데이터셋 출처: https://github.com/codeheroku/Introduction-to-Machine-Learning/tree/master/Building%20a%20Movie%20Recommendation%20Engine

# import 
import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer #텍스트 데이터 벡터화
from sklearn.metrics.pairwise import cosine_similarity #코사인유사도

# 데이터셋 불러오기
import os
csv_path = 'csv 데이터주소'
df = pd.read_csv(csv_path)
df.head()

#데이터셋 컬럼 확인
df.columns

# 일부 컬럼만 선택(연습이므로!)
features = ['keywords','cast','genres','director']

def combine_features(row):
    return row['keywords']+" "+row['cast']+" "+row['genres']+" "+row['director']

# 특성 결합하는 방식
combine_features(df[:5])

for feature in features:
    df[feature] = df[feature].fillna('')

df["combined_features"] = df.apply(combine_features,axis=1)


#텍스트 데이터 벡터화 진행
cv = CountVectorizer()
count_matrix = cv.fit_transform(df["combined_features"]) # CSR(Compressed Sparse Row) Matrix 타입. (4802, 5900) 2 형태


## CSR(Compressed Sparse Row) Matrix?
### Sparse한 matrix에서 0이 아닌 유효한 데이터로 채워지는 데이터의 값과 좌표 정보로만으로 구성하여 
###메모리 사용량을 최소화하면서도 Sparse한 matrix와 동일한 행렬을 표현할 수 있도록 하는 데이터 구조
### 예를 들어 (0, 3115) 2라는 CSR은 1번째 row는 3116번째 단어가 2번 출현한다는 뜻이다.


# 코사인 유사도 계산
cosine_sim = cosine_similarity(count_matrix)


# 코사인 유사도 기반 영화 추천
def get_title_from_index(index):
    return df[df.index == index]["title"].values[0]
def get_index_from_title(title):
    return df[df.title == title]["index"].values[0]

movie_user_likes = "Avatar"
movie_index = get_index_from_title(movie_user_likes)
similar_movies = list(enumerate(cosine_sim[movie_index]))

sorted_similar_movies = sorted(similar_movies,key=lambda x:x[1],reverse=True)[1:]

i=0
print(movie_user_likes+"와 비슷한 영화 3편은 "+"\n")
for item in sorted_similar_movies:
    print(get_title_from_index(item[0]))
    i=i+1
    if i==3:
        break

협업 필터링

  •  과거의 사용자 행동 양식(User Behavior) 데이터를 기반으로 추천하는 방식
  • 크게 사용자 기반과 아이템 기반 그리고 잠재요인(latent factor) 방식이 있다
    • 사용자 기반과 아이템 기반 방식 
      • 유사도를 계산하는 방식
      • 영화데이터의 평점행렬을 유사도를 계산하여 추천하는 방식
    • 잠재요인 방식
      • 행렬 인수분해(matrix factorization)를 이용해 잠재요인을 분석하는 방식
      • 평점행렬을 분해하여 더 많은 정보들을 고려하는 방식
  • 최근에는 잠재요인을 분석하는 사례가 많아지는 추세이다.

 

영화 추천을 예시로 사용자 기반, 아이템 기반, 잠재요인 방식의 과정을 살펴보자

 

먼저 영화 관련 데이터를 사용자와 아이템간  평점 행렬, interaction matrix로 변환한다.

이때 평점 행렬은 대부분의 값이 0인 희소 행렬이다.

영화 데이터 → 사용자-아이디 간 평점행렬

이후 사용자 기반과 아이템 기반 그리고 잠재요인(latent factor) 방식에 따라 협업 필터링의 방식이 달라진다.


사용자 기반 방식

  • 동일한 제품에 대해 평점을 매긴 데이터를 분석하여 추천
  • "당신과 비슷한 고객들이 해당 상품을 구매했습니다"라고 정리할 수 있다.

아래와 같은 평점 행렬이 있을 때 user4에게는 어떤 제품을 추천하는 게 좋을까? 단 user2와 user4는 유사한 특성을 갖고 있다.

정답은 바로 item3!

user2가 선호한 제품이다.


아이템 기반 방식

  •  아이템 간의 유사도를 측정하여 해당 아이템을 추천하는 방식이다.
  • "이 상품을 선택한 다른 고객들은 다음 상품을 구매했습니다"라고 정리할 수 있다.
  • 사용자들이 선호하는 아이템이 유사하다는 가정하에, 특정 사용자가 이전에 선호한 아이템과 다른 사용자가 선호한 아이템 간에 유사도를 계산하고 아이템을 추천함
  • 아이템 자체의 정보보다는 사용자의 선호도 정보가 중요하다
  • 일반적으로 사용자 기반 방식보다 정확도가 더 높다.

아래와 같은 표에서 user4에게는 어떤 아이템을 추천해주는 게 좋을까?

user2와 user4는 모두 item1을 구매했고 positive한 반응을 보였다.

이때 user4에게는 user2가 positive하게 반응했던 또다른 제품인 item3를 추천한다.


    이제 마지막으로 잠재요인 협업 필터링 방식을 살펴보자.

잠재요인 협업 필터링 방식은 평점행렬을 행렬 인수분해(matrix factorization)하여 얻은 잠재요인(latent factor)을 분석한다.

행렬 인수분해가 뭔지 모르니까 행렬 인수분해에 대해 먼저 알아보자!

 

 

 

cf. 행렬 인수분해란?

  • 인수분해와 비슷하다
  • 숫자를 인수분해할 때와 마찬가지로 행렬을 여러 행렬의 곱으로 분해한다.
  • 행렬 인수분해를 통해 추천 알고리즘의 파라미터 수를 줄일 수 있다!
  • SVD(Singular Vector Decomposition), ALS(Alternating Least Squares), NMF(Non-negative Matrix Factorization) 등이 있다.

cf. SVD(특잇값 분해)

  • M X N 형태의 행렬 A을 다음과 같은 형태로 분해하여 나타내는 것

  • SVD가 유용한 이유
    • 행렬이 정방행렬이든 아니든 관계없이 모든 M*N 행렬에 대해 적용 가능
    • 정보 복원을 위해 사용된다.  기존의 U,Σ,VTU,Σ,VT로 분해되어 있던 AA행렬을 특이값 p개만을 이용해 A’라는 행렬로 ‘부분 복원’ 할 수 있다. 따라서  최대한 중요한 정보들만 부분 복원해서 사용하면 사진의 용량은 줄어들지만 여전히 사진이 보여주고자 하는 내용은 살릴 수 있다.
    • 참고자료
 

[선형대수학 #4] 특이값 분해(Singular Value Decomposition, SVD)의 활용

활용도 측면에서 선형대수학의 꽃이라 할 수 있는 특이값 분해(Singular Value Decomposition, SVD)에 대한 내용입니다. 보통은 복소수 공간을 포함하여 정의하는 것이 일반적이지만 이 글에서는 실수(real

darkpgmr.tistory.com

 

numpy를 이용한 svd 구현

# 4*4 형태의 행렬 A를 SVD 해보자!

import numpy as np
from numpy.linalg import svd

np.random.seed(30)
A = np.random.randint(0, 100, size=(4, 4))

svd(A) #순서대로 U,S,Vh 출력

# unpacking을 통한 할당
U, Sigma, VT = svd(A)

# 재복원
Sigma_mat = np.diag(Sigma) #sigma는 1차원이므로 0을 포함한 대각행렬로 변환한 뒤 내적을 진행해야 함

A_ = np.dot(np.dot(U, Sigma_mat), VT)
A_


잠재요인 기반 방식

  •  평점행렬을 행렬 인수분해(matrix factorization)하여 얻은 잠재요인(latent factor)을 분석
  • 행렬 인수분해 방식으로는 SVD 중 Truncated SVD를 사용한다.
    • 다른 말로 LSA(Latent semantic analysis), 잠재 의미 분석 이라고 번역
    • SVD와 다르게 Truncated SVD는 차원을 축소 후 행렬 분해를 진행한다.
    • 따라서 SVD와 비교했을 때 계산 비용이 더 적고, 노이즈를 제거하는 효과가 있으며, 메모리 사용량이 상대적으로 적다는 장점이 있다. 
    • 그러나 Truncated SVD를 이용해 분해한 뒤 복원하면 SVD 처럼 완벽히 같은 행렬이 나오지 않는다는 단점이 있다.
    • 사이킷런의 TruncatedSVD 함수를 사용해 구현할 수 있다.

예제의 평점 행렬을 인수분해하면 다음과 같이 분해된다.

잠재요인 기반 방식에서는 사용자가 평점을 매기는 요인을 '잠재요인'으로 취급하고 행렬 인수분해를 통해 사용자-아이템 행렬을 분해한 뒤 다시 합치는 방법으로 영화에 평점을 매긴 이유를 벡터화하고 이를 기반으로 유사도, 사용자 평점을 계산하여 영화를 추천한다.

 

이러한 잠재요인 분석 기법은 효과가 뛰어나서 많은 기업들이 사용하고 있는 방식이다.


실제 추천 시스템

  • 실제 대형 기업에서는 더 많은 것들을 고려한다.
  • 사용자의 구매 여부와 평점 데이터, 얼마나 오랜 시간 동안 시청(혹은 해당 웹 사이트에 머물렀는지), 어떤 사이트에서 유입이 되었는지, 그리고 시청한 뒤 구매로 이어지기까지의 시간 등의 모든 Digital Footprint를 전부 분석한다.
  • 그리고 이 중 가장 중요한 지표로 CTR(Click Through Rate, 클릭률)이 사용된다.
  • 이러한 데이터들을 모아 추천을 한 뒤, 해당 아이템이 적절한 추천인지 여부를 평가한다.
  • 추천한 제품이 구매로 이어졌는지를 통해 추천에 성공했는지를 평가하기도 하고 모델 단계에서 평가하기도 한다.

이처럼  추천 시스템은 매우 큰 시스템이며 좋은 추천시스템을 만들기 위해서는 적합한 데이터를 선택하여 사용하는 과정이 반드시 필요하다. 그래서 실제 기업에서는 사용자와 연관성이 있고, 구매와 직결되는 각종 데이터를 수집하고 정렬(sorting)하여 다시 순위(ranking)를 매긴 다음 평가하는 과정을 무한히 반복한다.

 

AB TEST

넷플릭스에서 활용하는 방법

 

'AI Theory > key concept of AI' 카테고리의 다른 글

[CV] GAN 과 cGAN  (0) 2023.07.18
[NLP] Text Summarization  (0) 2023.07.17
비지도학습(Unsupervised Learning)  (0) 2023.07.07
선형 회귀와 로지스틱 회귀  (0) 2023.07.05
Regularization(정칙화)  (0) 2023.07.05