4장 SGD를 사용한 MF 기본 알고리즘 오류
안녕하세요
좋은 강의 감사합니다.
4장 SGD를 사용한 MF 기본 알고리즘 오류 에서
pivot 테이블을 만드는 과정에서 오류가 생겨 질문드립니다.
아래와 같은 오류가 생기는데 어떤 이유인지요? 코드가 잘못된 것 같지는 않습니다.
pivot 대신 pivot_table 을 쓰니 또 되네요. pivot_table 은 값이 중복인 경우에 첫 값을 쓴다고 되어있는데 올바른 해결책이 맞나요?
R_temp = ratings.pivot(index = 'user_id',
columns = 'movie_id',
values = 'rating').fillna(0)---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-10-bcd5f752ec01> in <cell line: 1>()
----> 1 R_temp = ratings.pivot(index = 'user_id',
2 columns = 'movie_id',
3 values = 'rating').fillna(0)
7 frames
/usr/local/lib/python3.10/dist-packages/pandas/core/reshape/reshape.py in _make_selectors(self)
187
188 if mask.sum() < len(self.index):
--> 189 raise ValueError("Index contains duplicate entries, cannot reshape")
190
191 self.group_index = comp_index
ValueError: Index contains duplicate entries, cannot reshape
추가로 질문드립니다. pivot_table을 사용해도 rmse가 계속 nan이 나오네요
저는 코드가 잘못된 부분을 찾기가 힘든데 도움 부탁드립니다.
prediction = self.b + self.b_u[i] + self.b_d[j] + self.P[i, :].dot(self.Q[j, :].T) 으로 바꾸어도 같은 오류가 납니다.
class MF():
def __init__(self, ratings, hyper_params):
self.R = np.array(ratings)
self.num_users, self.num_items = np.shape(self.R)
self.K = hyper_params['K'] # feature의 개수
self.alpha = hyper_params['alpha'] # learning rate
self.beta = hyper_params['beta'] # regularization coef
self.iterations = hyper_params['iterations'] # SGD 반복 횟수
self.verbose = hyper_params['verbose'] # 출력 여부
def rmse(self):
xs, ys = self.R.nonzero() # R에서 0이 아닌 요소의 index
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))
def train(self):
# P, Q 의 값 초기화
self.P = np.random.normal(scale = 1. / self.K, # 표준편차 설정, mean은 설정 안하면 자동으로 0
size = (self.num_users, self.K))
self.Q = np.random.normal(scale = 1. / self.K,
size = (self.num_users, 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()]) # 평점의 전체 평균, 0이 아닌 것에 대해서만 평균을 낸다.
rows, columns = self.R.nonzero() # 평점이 있는 요소들의 idx만 가져오겠다는 뜻 --> 나중에 SGD를 적용하기 위해서
self.samples = [(i,j, self.R[i,j]) for i,j in zip(rows, columns)]
training_process = [] # SGD 실행될때마다 RMSE 기록
for i in range(self.iterations):
np.random.shuffle(self.samples) # 다양한 시작점 지정
self.sgd()
rmse = self.rmse()
training_process.append((i+1, rmse))
if self.verbose:
if (i+1) % 10 == 0:
print('Iteration : %d ; train RMSE = %.4f'%(i+1, rmse))
return training_process
def get_prediction(self, i,j): # i 유저의 j 번째 아이템에 대한 예측치
# 전체 평점 + 유저의 경향성 + 아이템의 경향성 + i번째 유저의 j번째 아이템에 대한 예측
prediction = self.b + self.b_u[i] + self.b_d[j] + self.P[i, :].dot(self.Q[j, ].T)
return prediction
def sgd(self):
for i,j,r in self.samples: # i,j는 인덱스, r은 평점
prediction = self.get_prediction(i,j)
e = (r-prediction) # 오차
# 사용자의 평가경향 업데이트, 4장 슬라이드 10페이지 식
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,:]))
# 원코드는 pivot_table 대신 pivot 사용
R_temp = ratings.pivot_table(index = 'user_id',
columns = 'movie_id',
values = 'rating').fillna(0)
hyper_params = {
'K':30,
'alpha' : 0.001,
'beta' : 0.02,
'iterations' : 100,
'verbose' : True
}
mf = MF(R_temp, hyper_params)
train_process = mf.train()
get_prediction 함수에서 아래를 해보니까, 처음에는 조금 숫자가 나오다가 계속 nan이 나오는데 여기에서 문제가 있는것 같습니다. 근데 원인을 모르겠어요;
print(self.b)
print(self.b_u[i])
print(self.b_d[j])
print(self.P[i, :].dot(self.Q[j, ].T))
답변 1
0
안녕하세요.
일단 전달주신 부분으로만으로 확인했을 때는 크게 오류가 없어보이는데,
강의에 대한 원본 코드를 드려보겠습니다.
혹시 전달 드린 코드 보시고,
코드 오류가 없는지 확인 부탁드려도 괜찮을까요 ? :)
import os
import numpy as np
import pandas as pd
base_src = 'drive/MyDrive/RecoSys/Data'
u_data_src = os.path.join(base_src,'u.data')
r_cols = ['user_id','movie_id','rating','timestamp']
ratings = pd.read_csv(u_data_src,
sep = '\t',
names = r_cols,
encoding='latin-1')
# timestamp 제거
ratings = ratings[['user_id','movie_id','rating']].astype(int)
# MF class
# MF라는 이름의 클래스는 MF를 위한 데이터와 메소드를 가진 클래스이다.
class MF():
# 클래스가 생성될 때 실행되는 초기화 함수이다.
def __init__(self,ratings,hyper_params):
# DataFrame 형식으로 전달된 평점(ratings)을 numpy array 형태로 바꿔서 클래스 변수인 self.R에 저장
self.R = np.array(ratings)
# 사용자 수(num_users)와 아이템 수(num_iterms)를 받아온다.
self.num_users,self.num_items = np.shape(self.R)
# 아래는 MF weight 조절을 위한 하이퍼파라미터이다.
# K : 잠재요인(latent factor)의 수
self.K = hyper_params['K']
# alpha : 학습률
self.alpha = hyper_params['alpha']
# beta : 정규화 계수
self.beta = hyper_params['beta']
# iterations : SGD의 계산을 할 때의 반복 횟수
self.iterations = hyper_params['iterations']
# verbose : SGD의 학습 과정을 중간중간에 출력할 것인지에 대한 여부
self.verbose = hyper_params['verbose']
# 현재의 P,Q를 가지고 Root Mean Squared Error(RMSE) 계산하는 함수이다.
def rmse(self):
# self.R에서 평점이 있는(0이 아닌) 요소의 인덱스를 가져온다.
xs, ys = self.R.nonzero()
# prediction과 error를 담을 리스트 변수 초기화
self.predictions = []
self.errors = []
# 평점이 있는 요소(사용자 x, 아이템 y) 각각에 대해서 아래의 코드를 실행한다.
for x,y in zip(xs,ys):
# 사용자 x, 아이템 y에 대해서 평점 예측치를 get_prediction() 함수를 사용해서 계산한다.
prediction = self.get_prediction(x,y)
# 예측값을 예측값 리스트에 추가한다.
self.predictions.append(prediction)
# 실제값(R)과 예측값의 차이(errors) 계산해서 오차값 리스트에 추가한다.
self.errors.append(self.R[x,y] - prediction)
# 예측값 리스트와 오차값 리스트를 numpy array형태로 변환한다.
self.predictions = np.array(self.predictions)
self.errors = np.array(self.errors)
# error를 활용해서 RMSE 도출
return np.sqrt(np.mean(self.errors**2))
# 정해진 반복 횟수만큼 P(사용자 요인), Q(아이템 요인), bu(사용자 평가경향),bd(아이템 평가경향)을 업데이트하는 함수
def train(self):
# Initializing user-feature and movie-feature matrix
# P행렬 정규분포(평균=0, 표준편차=1/K)로 난수 초기화
self.P = np.random.normal(scale=1./self.K,
size=(self.num_users,self.K))
# Q행렬 정규분포(평균=0, 표준편차=1/K)로 난수 초기화
self.Q = np.random.normal(scale=1./self.K,
size=(self.num_items,self.K))
# Initializing the bias terms
# 사용자 평가경향 0으로 초기화
self.b_u = np.zeros(self.num_users)
# 아이템 평가경향 0으로 초기화
self.b_d = np.zeros(self.num_items)
# 평점의 전체 평균으로 b로 할당
self.b = np.mean(self.R[self.R.nonzero()])
# List of training samples
# 평점행렬 R 중에서 평점이 있는 요소의 인덱스를 가져온다.
rows, columns = self.R.nonzero()
# SGD를 적용할 대상, 즉 평점이 있는 요소의 인덱스와 평점을 리스트로 만들어서 samples에 저장한다.
self.samples = [(i,j,self.R[i,j]) for i,j in zip(rows,columns)]
# Stochastic Gradient Descent for given number of iterations
# training_process 리스트에 SGD가 한 번 실행될 때마다 RMSE가 얼마나 개선되는지 기록
training_process = []
for i in range(self.iterations):
# 기계학습 알고리즘과 비슷하게 SGD를 어디서 시작하느냐에 따라서 수렴의 속도가 달라질 수 있기 때문에
# 매 반복마다 다양한 시작점에서 출발하기 위해 samples를 임의로 섞는다.
np.random.shuffle(self.samples)
# SGD를 실행하는 함수 호출
self.sgd()
# SGD로 P,Q,bu,bd가 업데이트되었으므로 이에 따른 새로운 RMSE를 계산
rmse = self.rmse()
# 결과 저장
training_process.append((i+1,rmse))
# verbose가 True일 때 10회 반복마다 중간 결과 출력
if self.verbose:
if (i+1) % 10 == 0:
print("Iteration : %d ; Train RMSE = %.4f"%(i+1,rmse))
# 최종 결과 반환
return training_process
# Rating prediction for user i and item j
# 평점 예측값을 구하는 함수이다.
def get_prediction(self,i,j):
# 사용자 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
# 실제로 최적의 P, Q, b_u, b_d를 구하기 위한 SGD 실행 함수
def sgd(self):
for i,j,r in self.samples:
# 사용자 i, 아이템 j에 대한 평점 예측치 계산
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]))
# P 행렬 계산 및 업데이트
self.P[i,:] += self.alpha * ((e * self.Q[j,:]) - (self.beta * self.P[i,:]))
# Q 행렬 계산 및 업데이트
self.Q[j,:] += self.alpha * ((e * self.P[i,:]) - (self.beta * self.Q[j,:]))
# 전체 데이터 사용 MF
# DataFrame 형식으로 된 ratings 데이터를 full matrix로 변환
R_temp = ratings.pivot(index='user_id',
columns='movie_id',
values='rating').fillna(0)
# 모델 MF 계산에 필요한 하이퍼파라미터 정의
hyper_params = {
"K":30,
"alpha":0.001,
"beta":0.02,
"iterations":100,
"verbose":True
}
# MF 클래스 생성
mf = MF(R_temp,hyper_params)
# MF 모델 학습
train_process = mf.train()
강의 자료 이게 맞나요?
0
69
3
6장 Keras로 MF 구현하기 학습 결과
0
166
2
초심자의 질문
0
122
1
코드 공유 폴더가 비어 있습니다.
0
187
1
코드 공유 관련 부탁드립니다.
1
260
2
section 4 네번째 강의에서 pd.merge(x_train, users) 에러 발생
0
289
1
section 2 네번째 강의 score(cf_gender) 실행하면 Error 발생합니다.
0
201
1
MF알고리즘에서 질문이있습니다.
0
365
1
ean_rating = np.dot(sim_scores,movie_ratings) / sim_scores.sum() 부분에서 질문이있습니다.
0
310
1
score를 실행하면 항상 nan이 출력됩니다
0
328
1
user_id가 인덱스범위를 벗어난 값으로 들어옵니다
0
255
1
인덱스 칼럼은 어떻게 접근해야하나요
0
227
1
제공해주신 데이터링크에 들어가면 404가 뜨는데요?
0
365
1
코드 자동완성 속도가 상당히 느린데 개선할 방법이 있을까요?
0
304
1
ValueError: setting an array element with a sequence
0
475
1
users에 대한 인덱스 설정 기준
0
290
1
ppt 자료
0
286
1
train_test_split에 관한 질문입니다.
0
332
1
Timestamp 제거 이유
0
398
1
사용자 집단별 추천 강의 11:56 부분에 성별에 따른 예측값 계산에서 MergeError가 발생합니다.
0
436
1
local variable 'movie_ratings' referenced before assignment
0
260
2
3장 CF_knn 코드 질문
0
264
1
실습 중 에러 'numpy.ndarray' object has no attribute 'drop'
0
1169
2
IntCastingNaNError: 관련 에러
0
438
1





