OFMY (Ony for me and you)

[파이썬 머신러닝 완벽가이드] 09 추천시스템 - 잠재요인 협업필터링(2) 본문

머신러닝/책 리뷰

[파이썬 머신러닝 완벽가이드] 09 추천시스템 - 잠재요인 협업필터링(2)

선뭉 2023. 9. 18. 17:46

SVD는 NaN 값이 없는 행렬에만 적용 가능하기 때문에 이런경우에는 확률적 경사 하강법을 이용해 행렬분해를 수행함 


확률적 경사 하강법을 이용한 행렬분해 

:P와 Q 행렬로 계산된 예측 R 행렬 값이 실제 R 행렬값과 가장 최소의 오류를 가질 수 있또록 반복적인 비용 함수 최적화를 통해 P와Q를 유추해 내는 것

1. P와 Q 행렬을 임의의 값을 가진 행렬로 초기화 한다.
2. P와 Q 전치행렬을 곱해 예측 R 행렬을 계산하고, 실제 R 행렬과의 차이를 계산한다.
3. 차이를 최소화할 수 있도록 P와 Q 행렬의 값을 적절한 값으로 각각 업데이트한다.
4. 특정임계치 아래로 수렴할 때까지 2, 3번 작업을 반복하면서 P와 Q 행렬을 업데이트해 근사화한다.

과적합을 피하기 위해서 규제(L2규제)를 반영한 비용 함수 적용 

 

import numpy as np
 
# 원본 행렬 R 생성, 분해 행렬 P와 Q 초기화, 잠재요인 차원 K는 3 설정.
R = np.array([[4, np.NaN, np.NaN, 2, np.NaN ],
              [np.NaN, 5, np.NaN, 3, 1 ],
              [np.NaN, np.NaN, 3, 4, 4 ],
              [5, 2, 1, 2, np.NaN ]])
num_users, num_items = R.shape
K=3
 
# P와 Q 매트릭스의 크기를 지정하고 정규분포를 가진 random한 값으로 입력합니다.
np.random.seed(1)
P = np.random.normal(scale=1./K, size=(num_users, K))
Q = np.random.normal(scale=1./K, size=(num_items, K))
print('실제 행렬:\n', R)
* get_rmse(): 실제 R 행렬의 널이 아닌 행렬 값의 위치 인덱스를 추출해 이 인덱스에 있는 실제 R 행렬 값과 분해된 P,Q를 이용해 다시 조합 된 예측 행렬값의 RMSE 값을 반환
from sklearn.metrics import mean_squared_error
 
def get_rmse(R, P, Q, non_zeros):
    error = 0
    # 두개의 분해된 행렬 P와 Q.T의 내적으로 예측 R 행렬 생성
    full_pred_matrix = np.dot(P, Q.T)
     
    # 실제 R 행렬에서 널이 아닌 값의 위치 인덱스 추출하여 실제 R 행렬과 예측 행렬의 RMSE 추출
    x_non_zero_ind = [non_zero[0] for non_zero in non_zeros]
    y_non_zero_ind = [non_zero[1] for non_zero in non_zeros]
    R_non_zeros = R[x_non_zero_ind, y_non_zero_ind]
    full_pred_matrix_non_zeros = full_pred_matrix[x_non_zero_ind, y_non_zero_ind]
       
    mse = mean_squared_error(R_non_zeros, full_pred_matrix_non_zeros)
    rmse = np.sqrt(mse)
     
    return rmse
 
 
# R > 0 인 행 위치, 열 위치, 값을 non_zeros 리스트에 저장.
non_zeros = [ (i, j, R[i,j]) for i in range(num_users) for j in range(num_items) if R[i,j] > 0 ]
 
steps=1000
learning_rate=0.01
r_lambda=0.01
 
# SGD 기법으로 P와 Q 매트릭스를 계속 업데이트.
for step in range(steps):
    for i, j, r in non_zeros:
        # 실제 값과 예측 값의 차이인 오류 값 구함
        eij = r - np.dot(P[i, :], Q[j, :].T)
        # Regularization을 반영한 SGD 업데이트 공식 적용
        P[i,:] = P[i,:] + learning_rate*(eij * Q[j, :] - r_lambda*P[i,:])
        Q[j,:] = Q[j,:] + learning_rate*(eij * P[i, :] - r_lambda*Q[j,:])
 
    rmse = get_rmse(R, P, Q, non_zeros)
    if (step % 50) == 0 :
        print("### iteration step : ", step," rmse : ", rmse)

steps 는 SGD를 반복해서 업데이트 할 횟수

learning_rate: SGD의 학습률

r_lambda: L2 규제의 계수 

 

=> steps=1000번 동안 반복하면서 새로운 p,u 값으로 업데이트 

get_rmse() 함수를 통해 50회 반복할 때 마다 오류값 출력

 

 

 

[파이썬 머신러닝 완벽가이드] 09 추천시스템 - 잠재요인 협업필터링(1)

추천 시스템의 유형 콘텐츠 기반 필터링 (Content based filtering) 협업 필터링 (Collabrotice Filtering) 최근접 이웃 협업필터링 (= 메모리 협업 필터링) 아마존: 아이템 기반의 최근접 이웃 협업 필터링 방

bunnysideup.tistory.com