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

sj8504123님의 프로필 이미지
sj8504123

작성한 질문수

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

그 외의 CF 정확도 개선 방법

ValueError: setting an array element with a sequence

해결된 질문

작성

·

321

0

아래 부분에서 불균일한 데이터임을 나타내는 에러가 발생하는데 이유를 못찾겠습니다.

전체 코드입니다.

from inspect import Signature
import os
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split

### 데이터 불러오기 및 필요한 함수 정의 ###

# user 데이터
base_src = 'drive/MyDrive/RecoSys/Data'
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')
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',
          'Film-Noir','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')
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')

# 정확도(RMSE)를 계산하는 함수
def RMSE(y_true, y_pred):
  return np.sqrt(np.mean((np.array(y_true) - np.array(y_pred))**2))

# 유사집단의 크기를 미리 정하기 위해서 기존 score 함수에 neighbor_size 인자값 추가
def score(model, neighbor_size=0):
  id_pairs = zip(x_test['user_id'],x_test['movie_id'])  # user_id와 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)

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

# 코사인 유사도 계산
# train set의 모든 가능한 사용자 pair의 cosine similarity 계산
from sklearn.metrics.pairwise import cosine_similarity
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)


### 사용자 평가 경향을 고려한 함수 ###
rating_mean = rating_matrix.mean(axis=1)
rating_bias = (rating_matrix.T - rating_mean).T  # 평점 평균에 대한 편차

#####################################

rating_binary_1 = np.array(rating_matrix > 0).astype(float)  # 0 초과의 값이 있는 셀은 true, 나머지는 false로
rating_binary_2 = rating_binary_1.T

counts = np.dot(rating_binary_1, rating_binary_2)
counts = pd.DataFrame(counts,
                      index=rating_matrix.index,
                      columns=rating_matrix.index).fillna(0)

def CF_knn_bias_sig(user_id, movie_id, neighbor_size=0):
  if movie_id in rating_bias:
    sim_scores = user_similarity[user_id].copy()
    movie_ratings = rating_bias[movie_id].copy()

    no_rating = movie_ratings.isnull()  # 평가가 없는 
    common_counts = counts[user_id]  # 주어진 user_id를 기준으로 다른 user들과 공통으로 평가한 영화의 개수들을 담은 배열
    low_significance = common_counts < SIG_LEVEL  # 공통 평가한 영화 개수가 미리 정해진 level보다 낮은 사용자에 대해 false 처리
    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 = min(neighbor_size, len(sim_scores))
        sim_scores = np.array(sim_scores)  # 행렬 연산을 위해 배열 형태로 변환
        movie_ratings = np.array(movie_ratings)
        user_idx = np.argsort(sim_scores)
        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
      else:
        prediction = rating_mean[user_id]
  else:
    prediction = rating_mean[user_id]

  # RMSE 개선을 위한 조정
  # if prediction <= 1:
  #   prediction = 1
  # elif prediction >= 5:
  #   prediction = 5

  return prediction

SIG_LEVEL = 3
MIN_RATINGS = 3
score(CF_knn_bias_sig, 30)

답변 1

0

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

안녕하세요.

코드 일일이 확인하여서 도움드리기는 조금 어렵습니다.

강의 보시면서,

코드에 오류가 없으신지 확인부탁드립니다.

감사합니다

sj8504123님의 프로필 이미지
sj8504123

작성한 질문수

질문하기