인프런 커뮤니티 질문&답변

he님의 프로필 이미지
he

작성한 질문수

Python을 이용한 개인화 추천시스템 | 추천알고리즘 | 추천인공지능

이웃을 고려한 CF

score를 실행하면 항상 nan이 출력됩니다

해결된 질문

작성

·

211

·

수정됨

0

안녕하세요! score를 실행할때마다 nan이 출력이되서 잘못쓴 부분이 있나 여러번 체크해봤는데 도저히 모르겠어서 질문남겨봅니다..

import pandas as pd

import os

import numpy as np

from sklearn.model_selection import train_test_split

# 사용자 u.user파일을 DataFrame으로 열기

base_src = './drive/MyDrive/RecoSys/Data'

os.listdir('./drive/MyDrive/RecoSys/Data')

###### 데이터불러오기 #####

# os.path.join -> 경로 합치기

u_user_src = os.path.join(base_src,'u.user')

u_cols = ['user_id','age', 'sex', 'occupation','zip_code']

users = pd.read_csv(u_user_src,

sep='|',

names = u_cols,

encoding='latin-1')

users = users.set_index('user_id')

users.head()

u_item_src = os.path.join(base_src,'u.item')

i_cols = ['movie_id','title','release date','video release date','IMDB URL','unknown','Action','Adventure','Animation','Children\'s','Comedy','Crime','Documentary','Drama','Fantasy','FilmNoir','Horror','Musical','Mystery','Romance','Sci-Fi','Thriller','War','Western']

movies = pd.read_csv(u_item_src,

sep='|',

names = i_cols,

encoding='latin-1')

movies = movies.set_index('movie_id')

movies.head()

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

# ratings = ratings.set_index('user_id')

ratings.head()

# 실제값과 예측값을 넣기

def RMSE(y_true, y_pred):

return np.sqrt(np.mean((np.array(y_true) - np.array(y_pred)) **2 ))

# # 모델별 RMSE를 계산 하는 함수

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)

# 데이터셋 만들기

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)

ratings_matrix = x_train.pivot(index = 'user_id', columns = 'movie_id', values = 'rating')

# 코사인 유사도 계산

from sklearn.metrics.pairwise import cosine_similarity

## 코사인 유사도를 구하기 위해 rating값을 복제하고, 계산 시 Nan값 에러 대비를 위해 결측치를 0으로 대처

matrix_dummy = ratings_matrix.copy().fillna(0)

## 모든 사용자 간 코사인유사도를 구함

user_similarity = cosine_similarity(matrix_dummy,matrix_dummy)

## 필요한 값 조회를 위해 인덱스 및 칼럼명 지정

user_similarity = pd.DataFrame(user_similarity,

index=ratings_matrix.index, columns=ratings_matrix.index)

# Neighbor size를 정해서 예측치를 계산하는 함수

def CF_knn(user_id, movie_id, neighbor_size=0):

if movie_id in ratings_matrix.columns:

sim_scores = user_similarity[user_id].copy()

movie_ratings= ratings_matrix[movie_id].copy()

none_movie_ratings = movie_ratings[movie_ratings.isnull()].index

# print(none_movie_ratings)

moive_ratings = movie_ratings.dropna()

sim_scores = sim_scores.drop(none_movie_ratings)

# print(sim_scores)

# 여기까지는 동일(0일 경우는 일반적인 cf)

if neighbor_size == 0:

mean_rating = np.dot(sim_scores,movie_ratings) / sim_scores.sum()

else:

# 나와 유사한 사람이 없는경우

if len(sim_scores)>1:

# 5명을 10개로 나눌수 없으니까 최소값으로 해줘야한다

neighbor_size = min(neighbor_size,len(sim_scores))

sim_scores = np.array(sim_scores)

movie_ratings = np.array(movie_ratings)

# simscore가 작은 순서대로 작은 유저아이디를 넣는다

user_idx = np.argsort(sim_scores)

sim_scores = sim_scores[user_idx][-neighbor_size:]

## sim_scores 즉, 유사도를 뽑아냈으면 무비평가값을 뽑아내

movie_ratings = movie_ratings[user_idx][-neighbor_size:]

mean_rating = np.dot(sim_scores, movie_ratings) / sim_scores.sum()

else:

mean_rating = 3.0

# movie_id가 rating train pivot table에 포함되지 않을 경우

else:

mean_rating = 3.0

return mean_rating

# 정확도 계산

score(CF_knn,neighbor_size=30)

#### 실제 주어진 사용자에 대해 추천을 받는 기능 구현(테스트 데이터와 훈련데이터를 만들필요가없다) ####

ratings_matrix = ratings.pivot_table(values='rating', index = 'user_id', columns='movie_id')

matrix_dummy = ratings_matrix.copy().fillna(0)

user_similarity = cosine_similarity(matrix_dummy,matrix_dummy)

user_similarity = pd.DataFrame(user_similarity,index = ratings_matrix.index, columns=ratings_matrix.index)

def recom_movie(user_id, n_items, neighbor_size):

# 해당 유저가 평가한 영화가 나온다

user_movie= ratings_matrix.loc[user_id].copy()

for movie in ratings_matrix.columns:

# 현재 영화평점이 null이 아닌 경우 -> 영화를 본경우는 추천 리스트에서 제외하기 위해

if pd.notnull(user_movie.loc[movie]):

user_movie.loc[movie] = 0

else:

user_movie.loc[movie] =CF_knn(user_id,movie,neighbor_size)

movie_sort = user_movie.sort_values(ascending=False)[:n_items]

recom_movie = movies.loc[movie_sort.index]

recommendation = recom_movie['title']

return recommendation

recom_movie(user_id = 729, n_items=5, neighbor_size=30)

score(CF_knn,neighbor_size=30)

 

 

+ gpt한테 물어보니

none_rating_idx = movie_ratings[movie_ratings.isnull()].index 
moive_ratings = movie_ratings.dropna() 
sim_scores = sim_scores.drop(none_rating_idx)

이 부분을

movie_ratings = movie_ratings.dropna() 
sim_scores = sim_scores.loc[movie_ratings.index]

이렇게 변경해라해서 수정했더니 nan이 아닌 실수값이 나오기는 하는데 올바른 방법인지를 모르겠습니다. 그래도 같은 방법인거같긴 한데 어디서 차이가 발생하는건지 잘 모르겠습니다!

답변 1

0

거친코딩님의 프로필 이미지
거친코딩
지식공유자

안녕하세요.

전체 코드에 대한 디버깅을 해드리긴 어렵습니다.

해당 부분 깊은 양해를 부탁드립니다.

강의에 나오는대로 그대로 따라만 하시는게 아니라,

강의에 나온 내용 이해를 토대로 차근히 따라가주시면 감사하겠습니다.

감사합니다.

he님의 프로필 이미지
he

작성한 질문수

질문하기