사용자의 평가 경향을 고려한 CF

김민영·2024년 1월 12일

사용자의 평가 경향을 고려한 CF

최적의 이웃을 구한 후, 보다 더 CF를 개선시키기 위해 사용자의 평가 경향을 고려한 CF 알고리즘을 짜본다.

  1. 각 사용자의 평점 평균을 구한다.
  2. 각 평점에서 위에서 구한 각 사용자의 평균을 뺀다.(‘평점’ - ‘평점 평균’ = '평점편차' )
  3. 평점 편차 임시 예측값 계산
  4. 실제 예측값 = 평점 편차 임시 예측값 + 평점 평균

남성은 보통 2점대로 평점을 주고, 여성은 보통 4점대로 준다고 가정한다면,
둘이 한 영화에 대해 같은 3점을 주었다고 해도 이 둘의 평가 경향을 고려한다면 다른 의미의 3점일 것이다.
남자는 3점이 높은 점수, 여자는 3점이 낮은 점수로 활용되어야 더 알맞다.

예를 들어서 어떠한 추천을 받는 사용자가 있는데,
이 사람의 평점 평균이 3점이라고 가정하고 가중평균을 구한 유사한 집단의 평점 평균이 4점이라면
이 둘 간의 가중 평균을 통해 나온 결과값이 3.5라고 했을 때 우리는 이 3.5를 바로 쓰지 않고, -알파값의 어느 정도의 조정치가 필요할 것이다. (여기서 알파값은 집단과 사용자 간의 평점 평균의 차이(평점 편차)

3.5(예측값) - 1.0(집단의 평점평균 - 개인의 평점평균) = 2.5(최종예측값)

그렇다면 예측치는 3.5 - 1 인 2.5라고 하는 것이 합리적인 예측일 것이다.
이런 식으로 평점 편차를 이용해 예측값을 조정해주어야 하는데, 코드에서는 예측값을 구한 후, 평점편차를 빼는 방식이 아니라 평점 평균을 빼서 평점편차를 구한 후, 평점편차 예측값을 구한 후 다시 평점 평균을 더해주어 최종 예측값을 낸다.


##(데이터준비단계는 생략)##

# 정확도(RMSE)를 계산하는 함수
def RMSE(y_true, y_pred):
  return np.sqrt(np.mean((np.array(y_true)-np.array(y_pred))**2))

# 모델별 RMSE를 계산하는 함수
def score(model, neighbor_size = 0): # 테스트 데이터 성능을 계산하는 함수
  id_pairs = zip(x_test['user_id'], x_test['movie_id'])
  y_pred = np.array([model(user, movie, neighbor_size) for (user, movie) in id_pairs])
  y_true = np.array(x_test['rating'])
  return RMSE(y_true, y_pred)


x = ratings.copy()
y = ratings['user_id']


x_train, x_test, y_train, y_test = train_test_split(x, y,
                                                    test_size = 0.25,
                                                    stratify = y)

rating_matrix = x_train.pivot(index = 'user_id',
                              columns = 'movie_id',
                              values = 'rating')

## 코사인 유사도 계산
from sklearn.metrics.pairwise import cosine_similarity

matrix_dummy = rating_matrix.copy().fillna(0)
user_similarity = cosine_similarity(matrix_dummy, matrix_dummy)

user_similarity = pd.DataFrame(user_similarity,
                               index = rating_matrix.index,
                               columns = rating_matrix.index)

###############################아래부분변경################################
# 사용자 평가 경향을 고려한 함수
rating_mean = rating_matrix.mean(axis = 1) #1.사용자별 평점 평균을 구한다.
rating_bias = (rating_matrix.T - rating_mean).T #2.평점 평균의 편차를 구한다.

def CF_knn_bias(user_id, movie_id, neighbor_size = 0):
  if movie_id in rating_bias.columns:
    sim_scores = user_similarity[user_id].copy()
    movie_ratings = rating_bias[movie_id].copy()
    none_rating_idx = movie_ratings[movie_ratings.isnull()].index
    movie_ratings = movie_ratings.drop(none_rating_idx)
    sim_scores = sim_scores.drop(none_rating_idx) 
    
    if neighbor_size == 0:
      prediction = np.dot(sim_scores, movie_ratings) / sim_scores.sum()
      prediction = prediction + rating_mean[user_id]

    else:
      if len(sim_scores) > 1:
        neighbor_size = min(neighbor_size, len(sim_scores))
        sim_scores = np.array(sim_scores)
        movie_ratings = np.array(movie_ratings)  
        user_idx = np.argsort(sim_scores)
        sim_scores = sim_scores[user_idx][-neighbor_size:]
        movie_ratings = movie_ratings[user_idx][-neighbor_size:]
        prediction = np.dot(sim_scores, movie_ratings) / sim_scores.sum() #3.평점편차로 임시예측값 구하기
        prediction = prediction + rating_mean[user_id] #4.빼줬던 평점 평균 rating_mean 다시 더하기
      
      else:
        prediction = rating_mean[user_id] #이전과 다르게 3.0을 default값으로 하지 않고, 사용자의 평점평균을 넣어주는 것이 사용자의 경향을 고려하는 것.
  else:
    prediction = rating_mean[user_id]

  return prediction

score(CF_knn_bias, 30)
-> 0.9437466674623004

최적의 해가 30인 것을 구하고 나서 적용시킨 것이며, 확실히 성능이 많이 좋아진 것을 알 수 있다. (1.01 -> 0.94)

profile
data analysis, data science

0개의 댓글