CF considering user bias

2022. 3. 22. 21:27AI/Big data

    목차
반응형

평가를 보통 높게 하는 경향이 있는 사람과 그렇지 않은 사람등이 있음

  1. 사용자 별 bias를 고려
  2. 추천 대상의 평균 3.0, 예측치를 구하는데 사용된 사용자들의 평균은 4.0
    • 이웃의 원래 평점으로 예측한 값이 3.5면
    • 3.5 - 1
    data loading

 

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics.pairwise import cosine_similarity


u_cols = ['user_id', 'age', 'sex', 'occupation', 'zip_code']
users = pd.read_csv('u.user', sep='|', names=u_cols, encoding='latin-1')
i_cols = ['movie_id', 'title', 'release date', 'video release date', 'IMDB URL', 'unknown', 
          'Action', 'Adventure', 'Animation', 'Children\'s', 'Comedy', 'Crime', 'Documentary', 
          'Drama', 'Fantasy', 'Film-Noir', 'Horror', 'Musical', 'Mystery', 'Romance', 'Sci-Fi', 
          'Thriller', 'War', 'Western']
movies = pd.read_csv('u.item', sep='|', names=i_cols, encoding='latin-1')
r_cols = ['user_id', 'movie_id', 'rating', 'timestamp']
ratings = pd.read_csv('u.data', sep='\t', names=r_cols, encoding='latin-1')

 

cleansing

 

ratings = ratings.drop('timestamp', axis=1)
movies = movies[['movie_id', 'title']]

 

split

 

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)

 

define RMSE/score

 

def RMSE(y_true, y_pred):
    return np.sqrt(np.mean((np.array(y_true) - np.array(y_pred))**2))


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)

 

create rating matrix

 

rating_matrix = x_train.pivot(index='user_id', columns='movie_id', values='rating')
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)

 

create bias matrix

rating_matrix를 row 기준(axis=1, 즉 user 기준)으로 평균을 내고, rating_mean에 저장
rating_matrix를 transpose하여 user가 x축에 가게 한 후 user 개수만큼의 크기인 rating_means를 뺌
(numpy각 각 row에 대해 벡터 차감을 수행)
이후 이를 다시 transpose하여 원복한 후 rating_bias에 저장

즉, rating_bias는 각 영화 rating에서 user의 평균을 뺀 rating임
이로서 값이 모두 같은 scale이 되게 만듦 (이는 정규분포를 표준 정규 분포로 만드는 것과 같은 방식)

 

rating_mean = rating_matrix.mean(axis=1)
rating_bias = (rating_matrix.T - rating_mean).T

 

bias를 적용한 matrix로 CF knn을 수행

user와 가장 유사한 neighbor_size 개의 이웃 user와
해당 이웃 user들이 특정 영화(movie_id)에 매긴 평점의 평균으로 user_id가 볼 점수를 예측한 후,
(그런데 이 점수는 bias가 제거된 rating이니)
user의 bias를 (평균) 더한 값을 "예상평점"으로 구함

 

def CF_knn_bias(user_id, movie_id, neighbor_size=0):
    if movie_id not in rating_bias:
        return rating_mean[user_id]

    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()
        return prediction + rating_mean[user_id]

    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()
        prediction = prediction + rating_mean[user_id]
    else:
        prediction = rating_mean[user_id]

    return prediction

 

 

score(CF_knn_bias, 30)

 

0.9405751962613611

 

평균 오차가 개선되었음을 확인할 수 있음

반응형

'AI > Big data' 카테고리의 다른 글

Matrix Factorization 2  (0) 2022.03.23
CF 정확도 개선  (0) 2022.03.22
최적의 이웃 크기 설정  (0) 2022.03.22
CF considering neighbor  (0) 2022.03.22
Collaboration Filtering  (0) 2022.03.21