CF 정확도 개선

2022. 3. 22. 22:17AI/Big data

    목차
반응형

신뢰도 가중 (significance weighting)

user간 겹치는 아이템이 별로 없는 경우
별로 없는 아이템간의 유사도가 높아도 겹치는 아이템이 더 많은 경우보다 유사도가 높게 계산되지 않음

"공통 아이템이 많은 사용자의 유사도에 더 높은 가중치를 부여"

공통으로 평가한 아이템의 수가 일정 개수 이상인 사용자만 사용
 

data loading, cleansing, generate rating matrix

 

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')

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


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)


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)


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)

 

bias matrix

각 영화의 rating에서 평균 user의 평균을 뺀 rating을 계산

 

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

 

공통 영화 개수를 계산

각 user별 공통으로 평점을 매긴 영화의 개수를 '내적'으로 계산

 

rating_binary1 = np.array((rating_matrix > 0).astype(float))
rating_binary2 = rating_binary1.T
counts = np.dot(rating_binary1, rating_binary2)
counts = pd.DataFrame(counts, index=rating_matrix.index, columns=rating_matrix.index).fillna(0)

공통 인자의 가중치를 반영한 CF kNN

이번에는 평점이 없는 user의 rating과 user만 제거하는 것이 아니라,
공통으로 평점을 매긴 영화 개수가 특 정 개수 (e.g., 3개) 미만인 항목들도 제거함

none_rating_idx = movie_ratings[no_rating | low_significance].index

SIG_LEVEL = 3
MIN_RATINGS = 2


def CF_knn_bias_sig(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]
    movie_ratings = rating_bias[movie_id]
    no_rating = movie_ratings.isnull()

    common_counts = counts[user_id]
    low_significance = common_counts < SIG_LEVEL

    none_rating_idx = movie_ratings[no_rating | low_significance].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) > MIN_RATINGS:
            # 지정된 neighbor size 값과 해당 영화를 평가한 총사용자 수 중 작은 것으로 결정
            neighbor_size = min(neighbor_size, len(sim_scores))

            # array로 바꾸기 (argsort를 사용하기 위함)
            sim_scores = np.array(sim_scores)
            movie_ratings = np.array(movie_ratings)
            user_idx = np.argsort(sim_scores)  # 유사도를 순서대로 정렬

            # 유사도와 rating을 neighbor size만큼 받기
            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]

 

 

score(CF_knn_bias_sig, 30)

 

반응형

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

Matrix Factorization impl.  (0) 2022.03.25
Matrix Factorization 2  (0) 2022.03.23
CF considering user bias  (0) 2022.03.22
최적의 이웃 크기 설정  (0) 2022.03.22
CF considering neighbor  (0) 2022.03.22