본문 바로가기
Data Science/RecoSys

[Collaborative Filtering Recommendation System]

by hyelog 2022. 6. 26.

Collaborative Filtering(협업 필터링)

collaborative filtering 알고리즘은 유저들의 행동에서 부터 시작합니다.

어떤 것에 대해 비슷한 취향을 갖는다면, 다른 것에 대해서도 비슷한 취향을 가질 것이다 라는 전제에 기반합니다.

이러한 전제 하에 user의 관심사 일 수 있는 정보를 예측하고, 추천합니다.

 

먼저, 추천하고자 하는 대상과 취향이 비슷한 집단이 있을 것이다 라고 가정합니다.

이때 두 가지 방법으로 나뉘는데,

  • User Based : 비슷한 user를 찾아 비슷한 user가 공통적으로 소비(좋게 평가)한 내가 관심을 표하지 않은 item을 추천하는 방식
    • user data가 풍부한 경우, 정확한 추천이 가능하다.
    • data 업데이트에 대한 결과 변동 위험성이 존재한다.

user 👩‍🦳과 user 👱‍♀️은 높은 유사도를 가진다

  • Item Based : 내가 관심을 표한(소비한) item과 비슷한 item을 소비한 user의 다른(내가 관심을 표하지 않은) item을 추천하는 방식
    • 연산속도가 빠르다.
    • data 업데이트에 대한 영향이 적다.
    • user 간 평가 패턴을 바탕으로 아이템 간 유사도를 계산 하여 유저 별로 특정 아이템에 대한 평점이 어떨지 예측하여 추천한다.
      • 예측 대상이 평가한 아이템의 평점과 다른 각 아이템 간의 유사도를 가중 평균하여 예측값으로 사용한다.

 

item D와 item E는 높은 유사도를 가진다.

이 있습니다.

 

구현 해보기

코드로 간단하게 구현해 보겠습니다!

가장 대표적인 예시인 영화 추천으로 구현합니다.

User Based 

## 주어진 영화(movie_id)의 rating 
def user_CF(user_id, movie_id):
	if movie_id in ratings: 
    	sim_score = user_similarity[user_id].copy()
        movie_rate = ratings[movie_id].copy()
        
        mean_rating = np.dot(sim_scores, movie_rate)/ sim_socre.sum() # 가중평균을 이용한 rating
    else:
    	mean_rating = 3.0
    return mean_rating

Item Based

ratings_t = np.transpose(ratings)

def item_CF(user_id, movie_id):
	if movie_id in item_similarity.columns:
    	sim_score = item_similarity[movie_id]
        user_rate = ratings_t[user_id]
        
        mean_rating = np.dot(sim_score, user_rate) / sim_score.sum()
    else:
    	mean_rating = 3.0
    
    return mean_rating

 

간단히 코드로 비교해 봤는데요,

그렇다면 유사도를 구하는 방법은 어떤게 있을까요?

 

유사도 지표

1. 상관계수

이 지표 하나로는 유사도를 판단할 수 없습니다. 다만 선형적일때  유의미한 관계를 알아볼 수 있어요!

곡선관계는 유의미한 특성을 띄지만 상관계수로 발견할 수 없음을 알 수 있다.

 

2. 코사인 유사도

collaborative filtering 알고리즘에서 널리 쓰이는 유사도로 continuous value입니다.

각 item, user가 하나의 차원이라고 생각하여 좌표값으로 설정 합니다.

평가값이 유사하다면, $\theta$ 가 작아지고, $\cos\theta$ 값은 커집니다

3. 타니모토 계수

데이터가 이진 값이라면, 타니모토 계수가 권장됩니다.

이는 자카드 계수의 변형으로

자카드 계수란, a와 b가 선호하는 모든 아이템 분의 a와 b의 공통적으로 선호하는 아이템을 나타낸 값입니다. 

$N_a$ = a가 선호하는 아이템 수

def tanimoto(a,b):
  c=[v for v in a if v in b]
  return float(len(c))/len(a)+len(b)-len(c)

그 식을 코드로 구현하면 위와 같습니다.

 

 

틀린 부분이 있다면 언제든 피드백 부탁드려요!

 

 

댓글