하이브리드 추천 시스템

투빅스1617 RS·2022년 4월 27일
0

복수의 추천 알고리즘을 결합해서 추천하는 것을 하이브리드 추천 알고리즘 혹은 하이브리드 추천 시스템이라고 한다.

7.1 하이브리드 추천 시스템의 장점

추천 알고리즘의 정확도는 개별 아이템에 대한 개별 사용자의 예측 평점을 알고리즘으로 계산한 후에 이 예측 평점과 실제 평점과의 차이가 정확도가 된다.

하이브리드 추천 시스템에서는 복수의 알고리즘이 계산한 개별 사용자의 개별 아이템에 대한 예측치 하나하나에 대해서 일정한 규칙으로 결합하는 것이다.

한 알고리즘이 잡아내지 못하는 평가 패턴을 다른 알고리즘이 잡아내서 이 둘을 결합하면 서로 보완적인 효과가 생기게 되는 장점이 있다.

7.2 하이브리드 추천 시스템의 원리

# 2개의 알고리즘을 결합하는 하이브리드 추천 알고리즘의 예
##### (1)
# Dummy recommender 0
def recommender0(recomm_list):
    recommendations = []
    for pair in recomm_list:
        recommendations.append(random.random() * 4 + 1)
    return np.array(recommendations) 

# Dummy recommender 1
def recommender1(recomm_list):
    recommendations = []
    for pair in recomm_list:
        recommendations.append(random.random() * 4 + 1)
    return np.array(recommendations)

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

# Hybrid 결과 얻기
weight = [0.8, 0.2]
recomm_list = np.array(ratings_test)
predictions0 = recommender0(recomm_list)
predictions1 = recommender1(recomm_list)
predictions = predictions0 * weight[0] + predictions1 * weight[1]
RMSE2(recomm_list[:,2], predictions)

7.3 하이브리드 추천 시스템(CF와 MF의 결합)

def recommender0(recomm_list, mf):
    recommendations = np.array([mf.get_one_prediction(user, movie) for (user, movie) in recomm_list])
    return recommendations

def recommender1(recomm_list, neighbor_size=0):
    recommendations = np.array([CF_knn_bias(user, movie, neighbor_size) for (user, movie) in recomm_list])
    return recommendations

recomm_list = np.array(ratings_test.iloc[:, [0,1]])
predictions0 = recommender0(recomm_list, mf)
RMSE2(ratings_test.iloc[:,2], predictions0)
predictions1 = recommender1(recomm_list, 37)
RMSE2(ratings_test.iloc[:,2], predictions1)

weight = [0.8, 0.2]
predictions = predictions0 * weight[0] + predictions1 * weight[1]
RMSE2(ratings_test.iloc[:,2], predictions)

MF 알고리즘의 RMSE는 약 0.909601, CF알고리즘의 RMSE는 약 0.946719이다.

이 둘을 결합한 하이브리드 추천 시스템은 RMSE가 0.909193으로서 미세하지만 두 알고리즘보다 더 좋은 결과를 보여준다.

# 최적의 가중치
for i in np.arange(0, 1, 0.01):
    weight = [i, 1.0 - i]
    predictions = predictions0 * weight[0] + predictions1 * weight[1]
    print('Weights - %.2f : %.2f ; RMSE = %.7f' % (weight[0], weight[1], RMSE2(ratings_test.iloc[:,2], predictions)))

0.88(MF) : 0.12(CF)의 비중이 RMSE 0.908876으로서 가장 좋은 결과를 보여준다.

Chapter 8. 대규모 데이터의 처리를 위한 Sparse matrix 사용

추천 시스템에서 사용되는 대부분의 데이터는 full matrix로 변환하면 많은 원소가 비어있는 희박행렬(sparse matrix)이다.

예를 들어, MovieLens 100K 데이터를 full matrix로 변환하면 원소 중 값을 갖는 비율이 약 0.6%, MovieLens 20M 데이터는 비율이 약 0.1%밖에 되지 않는다.

8.1 Sparse matrix의 개념과 Python에서의 사용

full matrix를 sparse matrix로 처리하면 값이 있는 원소의 인덱스와 값만 저장하면됨. 이 방식은 데이터가 희박할수록 저장공간이 절약되는 정도가 커진다.

sparse matrix의 단점은 데이터를 저장하거나 읽어올 때마다 값이 존재하는지 확인해 그에 맞는 처리를 하기에 데이터 처리의 overhead cost가 크다는 점이다.

데이터가 희박하지 않은 경우에 sparse matrix를 사용하면 공간 절약의 이점보다 속도 저하의 단점이 오히려 크게 된다.

반면 행렬의 데이터가 희박할수록 sparse matrix을 사용하는 편이 더 낫게 된다.

8.2 Sparse matrix를 추천 알고리즘에 적용하기

r_cols = ['user_id', 'movie_id', 'rating', 'timestamp']
# 20M data 읽어오기
ratings = pd.read_csv('ratings-20m.csv', names=r_cols, sep=',', encoding='latin-1')
ratings = ratings[['user_id', 'movie_id', 'rating']].astype(int)

# train test 분리
from sklearn.utils import shuffle
TRAIN_SIZE = 0.75
ratings = shuffle(ratings, random_state=1)
cutoff = int(TRAIN_SIZE * len(ratings))
ratings_train = ratings.iloc[:cutoff]
ratings_test = ratings.iloc[cutoff:]

# Sparse matrix 사용
from scipy.sparse import csr_matrix
data = np.array(ratings['rating'])
row_indices = np.array(ratings['user_id'])
col_indices = np.array(ratings['movie_id'])
ratings = csr_matrix((data, (row_indices, col_indices)), dtype=int)

# New MF class for training & testing
class NEW_MF():
    def __init__(self, ratings, K, alpha, beta, iterations, verbose=True):
        self.R = ratings
        self.num_users, self.num_items = np.shape(self.R)
        self.K = K
        self.alpha = alpha
        self.beta = beta
        self.iterations = iterations
        self.verbose = verbose
        
    # Root Mean Squared Error(RMSE) 계산
    def rmse(self):
        xs, ys = self.R.nonzero()
        self.predictions = []
        self.errors = []
        for x, y in zip(xs, ys):
            prediction = self.get_prediction(x, y)
            self.predictions.append(prediction)
            self.errors.append(self.R[x, y] - prediction)
        self.predictions = np.array(self.predictions)
        self.errors = np.array(self.errors)
        return np.sqrt(np.mean(self.errors**2))
    
    # Rating prediction for user i and item j
    def get_prediction(self, i, j):
        prediction = self.b + self.b_u[i] + self.b_d[j] + self.P[i, :].dot(self.Q[j, :].T)
        return prediction
    
    # Stochastic gradient descent to get optimized P and Q matrix
    def sgd(self):
        for i, j, r in self.samples:
            prediction = self.get_prediction(i, j)
            e = (r - prediction)
            
            self.b_u[i] += self.alpha * (e - self.beta * self.b_u[i])
            self.b_d[j] += self.alpha * (e - self.beta * self.b_d[j])
            
            self.P[i,:] += self.alpha * (e * self.Q[j, :] - self.beta * self.P[i, :])
            self.Q[j,:] += self.alpha * (e * self.P[i, :] - self.beta * self.Q[j, :])
        
    # Test set을 선정
    def set_test(self, ratings_test):
        test_set = []
        for i in range(len(ratings_test)):
            x, y, z = ratings_test.iloc[i]
            test_set.append([x,y,z])
            self.R[x,y] = 0
        self.test_set = test_set
        return test_set
    
    # Test set의 RMSE 계산
    def test_rmse(self):
        error = 0
        for one_set in self.test_set:
            predicted = self.get_prediction(one_set[0], one_set[1])
            error += pow(one_set[2] - predicted, 2)
        return np.sqrt(error / len(self.test_set))
    
    # Training 하면서 test set의 정확도를 계산
    def test(self):
        self.P = np.random.normal(scale=1./self.K, size=(self.num_users, self.K))
        self.Q = np.random.normal(scale=1./self.K, size=(self.num_items, self.K))
        self.b_u = np.zeros(self.num_users)
        self.b_d = np.zeros(self.num_items)
        self.b = np.mean(self.R[self.R.nonzero()])
        
        rows, columns = self.R.nonzero()
        self.samples = [(i,j,self.R[i,j]) for i,j in zip(rows, columns)]
        training_process = []
        for i in range(self.iterations):
            np.random.shuffle(self.samples)
            self.sgd()
            rmse1 = self.rmse()
            rmse2 = self.test_rmse()
            training_process.append((i+1, rmse1, rmse2))
            if self.verbose:
                if (i+1) % 10 == 0:
                    print('Iteration : %d ; Train RMSE = %.4f ; Test RMSE = %.4f' % (i+1, rmse1, rmse2))
        return training_process
    
    def get_one_prediction(self, user_id, item_id):
        return self.get_prediction(user_id, item_id)
    
    def full_prediction(self):
        return self.b + self.b_u[:,np.newaxis] + self.b_d[np.newaxis,:] + self.P.dot(self.Q.T)

# Testing MF RMSE
R_temp = ratings.copy()
mf = NEW_MF(R_temp, K=30, alpha=0.001, beta=0.02, iterations=100, verbose=True)
test_set = mf.set_test(ratings_test)
result = mf.test()

데이터의 크기가 커지면서 RMSE가 0.7877로 MovieLens 100K 데이터보다 매우 향상되었음을 알 수 있다.

profile
투빅스 추천시스템 1617기

6개의 댓글

comment-user-thumbnail
2022년 5월 3일

투빅스 17기 염제윤입니다.

  1. 하이브리드 추천시스템

하이브리드 추천시스템은 복수의 알고리즘을 활용한 모델을 뜻하며, 앙상블 모델은 하이브리드 모델안에 포함된다. 하이브리드 추천 시스템은 복수의 알고리즘이 계산한 개별 사용자의 개별 아이템에 대한 예측치 하나하나에 대해서 일정한 규칙으로 결합하는 것이다. 개별 알고리즘이 잡아내지 못하는 평가 패턴을 다른 알고리즘이 잡아내서 이 둘을 결합하면 서로 보완적인 효과가 생기게 되는 장점이 있다.

  1. 대규모 데이터의 처리를 위한 Sparse matrix 사용
    대부분의 정보를 full matrix로 표현할시 매우 sparse한 데이터가된다. 이것은 연산과 저장공간적인 측면에서 매우 비효율적이다. 따라서 이것을 sparse matrix로 변환하여 처리한다. 이럴 경우 원소의 인덱스와 값만 저장하면 되므로 희박할수록 절약정도가 커진다. 단 데이터를 정정하고 읽어올 때마다 일일이 확인하게 되므로 데이터처리의 overhead cost가 크다는 단점이 있다. 따라서 dense한 데이터일 경우 fullmatrix 희박할수록 sparse matrix를 추천한다.
답글 달기
comment-user-thumbnail
2022년 5월 3일

투빅스 17기 박나윤입니다.

하이브리드 추천시스템

  • 하이브리드 추천시스템은 복수의 알고리즘이 계산한 개별 사용자의 개별 아이템에 대한 예측치에 대해 결합하므로 평가 패턴 파악에 보완적인 효과가 생기게 되는 장점이 있다.
  • 이 알고리즘을 이용하면 더 좋은 성능을 보인다.

대규모 데이터 처리 Sparse matrix

  • 행렬의 데이터가 희박하지 않은 경우에는 cost가 크므로 속도 저하의 단점이 있을 수 있다.
  • 행렬의 데이터가 희박하면 sparse matrix를 사용하는 것이 더 좋다.
  • 데이터의 크기가 커지면 sparse matrix 의 성능이 매우 향상된다.
답글 달기
comment-user-thumbnail
2022년 5월 3일

투빅스 16기 박한나입니다.

[하이브리드 추천 시스템]

  • 복수의 추천 알고리즘을 결합한 것이 하이브리드 추천 알고리즘이다.
  • 하이브리드 추천 시스템은 한 알고리즘이 잡아내지 못하는 평가 패턴을 다른 알고리즘이 보완하여 효과가 생긴다는 장점이 있다.

[Sparse matrix]

  • Sparse matrix란 희소행렬로, 추천시스템의 대부분의 데이터는 원소가 상당히 많이 비어있는 데이터이다.
  • Full matrix를 sparse matrix로 처리하면 값이 있는 원소의 인덱스와 값만 저장하면 되기 때문에 저장공간이 절약된다.
  • Sparse matrix의 단점은 데이터 처리의 오버헤드 비용이 크다는 것이다.
답글 달기
comment-user-thumbnail
2022년 5월 3일

투빅스 16기 이승주
1. 하이브리드 추천 시스템
복수의 알고리즘이 계산한 예측 평점에 대해서 일정한 규칙으로 결합하는 것이다. 한 알고리즘이 잡아내지 못하는 평가 패턴을 다른 알고리즘이 잡아내서 이 둘을 결합하면 서로 보완적인 효과가 생기게 되는 장점이 있다.
2. Sparse matrix
full matrix를 sparse matrix로 처리하면 값이 있는 원소의 인덱스와 값만 저장하면된다. 해당 방식은 데이터가 희박할수록 저장공간이 절약되는 정도가 커지지만 데이터를 저장하거나 읽어올 때마다 값이 존재하는지 확인해 그에 맞는 처리를 하기때문에 데이터 처리의 overhead cost가 크다는 단점이 존재한다.

답글 달기
comment-user-thumbnail
2022년 5월 4일

하이브리드 추천시스템은 여러가지의 알고리즘을 섞어서 사용한 모델을 의미합니다. 하나의 모델이 좋은 성능을 가지는 경우도 있지만 여러가지의 알고리즘을 활용하여 더 나은 모델을 만들 수 있습니다.
또한, sparse matrix는 희소 행렬로 불리며, 대부분의 값이 관측되지 않거나, 없는 값으로 이루어져 있습니다. 값이 이루어져있는 인덱스만 표시하기 때문에 큰 데이터에서 주로 사용이 됩니다. 하지만 단점으로는 매번 해당 인덱스에 값이 있는지 확인 후 불러오기 때문에 overhead cost가 있다는 단점이있습니다.

답글 달기
comment-user-thumbnail
2022년 5월 4일

투빅스 17기 김상윤입니다.
하이브리드 추천 시스템을 통해 다양한 알고리즘이 잡아낸 패턴을 상호보완 할 수 있다. 각 알고리즘이 도출한 개별 예측치 각각을 일정한 규칙으로 결합한다. 앙상블도 하나의 방법이다.
CF와 MF의 결합.
값이 존재 하는 것만 저장하는 Sparse Matrixdml 사용으로 메모리 공간 절약을 할 수 있다. 하지만 속도 저하의 부작용이 나타난다.

답글 달기