영화 추천 - 높은 평균 평점 기준

2022. 3. 21. 18:36AI/Big data

    목차
반응형

data loading

 

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split


u_cols = ['user_id', 'age', 'sex', 'occupation', 'zip_code']
users = pd.read_csv('u.user', sep='|', names=u_cols, encoding='latin-1')
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', sep='|', names=i_cols, encoding='latin-1')
r_cols = ['user_id', 'movie_id', 'rating', 'timestamp']
ratings = pd.read_csv('u.data', sep='\t', names=r_cols, encoding='latin-1')

 
user_id movie_id rating timestamp
0 196 242 3.0 881250949.0
1 186 302 3.0 891717742.0
2 22 377 1.0 878887116.0
3 244 51 2.0 880606923.0
4 166 346 1.0 886397596.0
... ... ... ... ...
53149 642 1311 3.0 886569715.0
53150 405 29 4.0 885545639.0
53151 151 614 4.0 879528729.0
53152 592 678 2.0 882607690.0
53153 194 2 NaN NaN
53154 rows × 4 columns

 

data cleaning

timestamp 제거
 

ratings = ratings.drop('timestamp', axis=1)

 

 

movies = movies[['movie_id', 'title']]

 

RMSE 및 score 함수 정의

 

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

def score(model):
    id_pairs = zip(x_test['user_id'], x_test['movie_id'])
    y_pred = np.array([model(user, movie) for (user, movie) in id_pairs])
    y_true = np.array(x_test['rating'])
    return RMSE(y_true, y_pred)

 

data split

test와 train set으로 분리

 

x_train, x_test, y_train, y_test = train_test_split(ratings.copy(), ratings['user_id'], test_size=0.25, stratify=ratings['user_id'])

 

모든 user_id에 대해 movie_id를 갖도록 (NaN) matrix 생성

 

rating_matrix = x_train.pivot(index='user_id', columns='movie_id', values='rating')
    movie_id    1    2    3    4    5    6    7    8    9    10    ...    1669    1670    1671    1672    1676    1677    1678    1680    1681    1682
    user_id                                                                                    
    1    NaN    3.0    NaN    3.0    3.0    5.0    4.0    1.0    5.0    3.0    ...    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
    2    4.0    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    2.0    ...    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
    3    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    ...    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
    4    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    ...    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
    5    4.0    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    ...    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
    ...    ...    ...    ...    ...    ...    ...    ...    ...    ...    ...    ...    ...    ...    ...    ...    ...    ...    ...    ...    ...    ...
    939    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    5.0    NaN    ...    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
    940    NaN    NaN    NaN    NaN    NaN    NaN    NaN    5.0    3.0    NaN    ...    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
    941    NaN    NaN    NaN    NaN    NaN    NaN    4.0    NaN    NaN    NaN    ...    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
    942    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    ...    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
    943    NaN    5.0    NaN    NaN    NaN    NaN    NaN    NaN    3.0    NaN    ...    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN    NaN
    943 rows × 1654 columns

 

movie_id 별 모든 평점에 대한 평균 계산

 

train_mean = x_train.groupby(['movie_id'])['rating'].mean()

 

def best_seller(user_id, movie_id):
    try:
        rating = train_mean[movie_id]
    except:
        rating = 3.0
    return rating

 

모든 user에 대해 모든 movie로 모델 구동 후 RMSE의 평균 리턴

 

score(best_seller)

 

    1.0283376783529838

train data와 user data의 merge

merge 하여 두 table을 비정규화

 

merged_ratings = pd.merge(x_train, users)
    user_id    movie_id    rating    age    sex    occupation    zip_code
0    18    408    5    35    F    other    37212
1    18    963    5    35    F    other    37212
2    18    692    3    35    F    other    37212
3    18    476    3    35    F    other    37212
4    18    753    4    35    F    other    37212
...    ...    ...    ...    ...    ...    ...    ...
74995    801    332    5    22    M    writer    92154
74996    801    313    5    22    M    writer    92154
74997    801    326    4    22    M    writer    92154
74998    801    681    1    22    M    writer    92154
74999    801    890    2    22    M    writer    92154
75000 rows × 7 columns

movie_id 별 sex로 평균을 구분하여 계산

 

g_mean = merged_ratings[['movie_id', 'sex', 'rating']].groupby(['movie_id', 'sex'])['rating'].mean()
movie_id  sex
1         F      3.787234
          M      3.910204
2         F      3.500000
          M      3.214286
3         F      2.642857
                   ...   
1677      F      3.000000
1678      M      1.000000
1680      M      2.000000
1681      M      3.000000
1682      M      3.000000
Name: rating, Length: 3057, dtype: float64

 

def cf_gender(user_id, movie_id):
    if movie_id in rating_matrix:
        gender = users.loc[user_id]['sex']
        if gender in g_mean[movie_id]:
            gender_rating = g_mean[movie_id][gender]
        else:
            gender_rating = 3.0
    else:
        gender_rating = 3.0
    return gender_rating

 

score(cf_gender)

 
1.0481358433234231

 

movie를 직업으로 구분하여 평균 계산

 

o_mean = merged_ratings[['movie_id', 'sex', 'rating', 'occupation']].groupby(['movie_id', 'occupation'])['rating'].mean()
  movie_id  occupation   
  1         administrator    4.086957
            artist           4.000000
            doctor           3.333333
            educator         3.793103
            engineer         4.171429
                               ...   
  1677      student          3.000000
  1678      student          1.000000
  1680      student          2.000000
  1681      writer           3.000000
  1682      engineer         3.000000
  Name: rating, Length: 16775, dtype: float64

 

def cf_occupation(user_id, movie_id):
    if user_id >= 943:
        return 3.0

    if movie_id in rating_matrix:

        gender = users.loc[user_id]['occupation']
        if gender in o_mean[movie_id]:
            gender_rating = o_mean[movie_id][gender]
        else:
            gender_rating = 3.0
    else:
        gender_rating = 3.0
    return gender_rating

score(cf_occupation)
    1.1415335518618561

 

반응형

'AI > Big data' 카테고리의 다른 글

CF considering neighbor  (0) 2022.03.22
Collaboration Filtering  (0) 2022.03.21
hyperparameter tuning  (0) 2022.03.19
Titanic data training  (0) 2022.03.19
Titanic data analysis  (0) 2022.03.19