KNN 협업 필터링 실습

2024. 3. 27. 01:42·Machine Learning/Recommendation
03_KNN 협업필터링 실습

KNN 협업 필터링 실습¶

유저-영화 평점 데이터를 이용해 유저가 아직 평가하지 않은 영화를 추천을 해보겠습니다.

In [1]:
import pandas as pd
import numpy as np


np.random.seed(2021)

1. Data¶

1.1 Data Load¶

데이터에서 유저 고유 아이디를 나타내는 userId, 영화 고유 아이디를 나타내는 movieId, 유저가 영화를 평가한 점수 rating 컬럼을 이용합니다.

In [2]:
ratings = pd.read_csv("ratings_small.csv")
ratings = ratings[["userId", "movieId", "rating"]]
In [3]:
ratings.head()
Out[3]:
userId movieId rating
0 1 31 2.5
1 1 1029 3.0
2 1 1061 3.0
3 1 1129 2.0
4 1 1172 4.0

다른 두 데이터를 이용해 ratings 데이터의 movieId에 맞는 영화 제목을 얻습니다.

In [4]:
movies = pd.read_csv("movies_metadata.csv")
links = pd.read_csv("links_small.csv")
C:\Users\sjy99\AppData\Local\Temp\ipykernel_38316\1408741908.py:1: DtypeWarning: Columns (10) have mixed types. Specify dtype option on import or set low_memory=False.
  movies = pd.read_csv("movies_metadata.csv")

1.2 Data Preprocessing¶

movies 데이터에서 "tt숫자"로 이루어진 imdb_id에서 숫자 부분과 links 데이터의 "숫자"로 이루어진 imdbId와 연결합니다.

In [5]:
movies = movies.fillna('')
movies = movies[movies["imdb_id"].str.startswith('tt')]
movies["imdbId"] = movies["imdb_id"].apply(lambda x: int(x[2:]))
movies = movies.merge(links, on="imdbId")
In [6]:
movies = movies[["title", "movieId"]]
movies = movies.set_index("movieId")
In [7]:
movies.head()
Out[7]:
title
movieId
1 Toy Story
2 Jumanji
3 Grumpier Old Men
4 Waiting to Exhale
5 Father of the Bride Part II

pivot함수를 이용해 유저 아이디가 인덱스이고, 영화 아이디가 컬럼, 값이 평가 점수인 user_movie_matrix를 만듭니다.

In [8]:
user_movie_matrix = ratings.pivot(
    index="userId",
    columns="movieId",
    values="rating",
)
In [9]:
user_movie_matrix.iloc[-5:, -5:]
Out[9]:
movieId 161944 162376 162542 162672 163949
userId
667 NaN NaN NaN NaN NaN
668 NaN NaN NaN NaN NaN
669 NaN NaN NaN NaN NaN
670 NaN NaN NaN NaN NaN
671 NaN NaN NaN NaN NaN

유저가 평가하지 않은 영화에 대해서 결측값을 0으로 대체합니다.

In [10]:
user_movie_matrix = user_movie_matrix.fillna(0)
In [11]:
user_movie_matrix.shape
Out[11]:
(671, 9066)

2. KNN Basic¶

k가 5인 KNN Basic을 이용해 유저 "124" 가 아직 평가하지 않은 영화 "648"에 대한 점수를 예측해 보겠습니다.

In [12]:
k = 5
user_i = 124
movie_id = 648

2.1 유저 간의 유사도를 계산한다.¶

cosin_similarity 함수를 이용해 유저별 코사인 유사도를 계산합니다.

In [13]:
from sklearn.metrics.pairwise import cosine_similarity

user_similarity = cosine_similarity(user_movie_matrix)
In [14]:
user_similarity.shape
Out[14]:
(671, 671)
In [15]:
user_similarity[:10, :10]
Out[15]:
array([[1.        , 0.        , 0.        , 0.07448245, 0.01681799,
        0.        , 0.08388416, 0.        , 0.01284289, 0.        ],
       [0.        , 1.        , 0.12429498, 0.11882103, 0.10364614,
        0.        , 0.21298521, 0.11319045, 0.11333307, 0.04321284],
       [0.        , 0.12429498, 1.        , 0.08163991, 0.15153112,
        0.06069128, 0.15471414, 0.24978072, 0.13447489, 0.1146725 ],
       [0.07448245, 0.11882103, 0.08163991, 1.        , 0.13064868,
        0.07964833, 0.31974534, 0.19101336, 0.03041726, 0.13718558],
       [0.01681799, 0.10364614, 0.15153112, 0.13064868, 1.        ,
        0.06379575, 0.0958878 , 0.16571211, 0.08661604, 0.03237017],
       [0.        , 0.        , 0.06069128, 0.07964833, 0.06379575,
        1.        , 0.        , 0.12850206, 0.02174493, 0.04526415],
       [0.08388416, 0.21298521, 0.15471414, 0.31974534, 0.0958878 ,
        0.        , 1.        , 0.14957182, 0.05972764, 0.18649318],
       [0.        , 0.11319045, 0.24978072, 0.19101336, 0.16571211,
        0.12850206, 0.14957182, 1.        , 0.15735626, 0.16272417],
       [0.01284289, 0.11333307, 0.13447489, 0.03041726, 0.08661604,
        0.02174493, 0.05972764, 0.15735626, 1.        , 0.12734115],
       [0.        , 0.04321284, 0.1146725 , 0.13718558, 0.03237017,
        0.04526415, 0.18649318, 0.16272417, 0.12734115, 1.        ]])
In [16]:
user_similarity = pd.DataFrame(
    data=user_similarity,
    index=user_movie_matrix.index,
    columns=user_movie_matrix.index,
)
In [17]:
user_similarity.head(5)
Out[17]:
userId 1 2 3 4 5 6 7 8 9 10 ... 662 663 664 665 666 667 668 669 670 671
userId
1 1.000000 0.000000 0.000000 0.074482 0.016818 0.000000 0.083884 0.000000 0.012843 0.000000 ... 0.000000 0.000000 0.014474 0.043719 0.000000 0.000000 0.000000 0.062917 0.000000 0.017466
2 0.000000 1.000000 0.124295 0.118821 0.103646 0.000000 0.212985 0.113190 0.113333 0.043213 ... 0.477306 0.063202 0.077745 0.164162 0.466281 0.425462 0.084646 0.024140 0.170595 0.113175
3 0.000000 0.124295 1.000000 0.081640 0.151531 0.060691 0.154714 0.249781 0.134475 0.114672 ... 0.161205 0.064198 0.176134 0.158357 0.177098 0.124562 0.124911 0.080984 0.136606 0.170193
4 0.074482 0.118821 0.081640 1.000000 0.130649 0.079648 0.319745 0.191013 0.030417 0.137186 ... 0.114319 0.047228 0.136579 0.254030 0.121905 0.088735 0.068483 0.104309 0.054512 0.211609
5 0.016818 0.103646 0.151531 0.130649 1.000000 0.063796 0.095888 0.165712 0.086616 0.032370 ... 0.191029 0.021142 0.146173 0.224245 0.139721 0.058252 0.042926 0.038358 0.062642 0.225086

5 rows × 671 columns

2.2 아이템 i를 평가한 유저들 중에서 유저 u와 비슷한 유저 k명을 찾는다.¶

이제 유저 "124"와 유사한 다른 유저 k명을 찾습니다.

In [18]:
user_i_similarity = user_similarity.loc[user_i]
In [19]:
user_i_similarity
Out[19]:
userId
1      0.000000
2      0.129669
3      0.224600
4      0.147568
5      0.159521
         ...   
667    0.065720
668    0.074023
669    0.049342
670    0.201474
671    0.330381
Name: 124, Length: 671, dtype: float64
In [20]:
user_i_similarity = user_i_similarity.sort_values(ascending=False)
In [21]:
user_i_similarity
Out[21]:
userId
124    1.000000
458    0.455216
379    0.433607
355    0.432242
282    0.423280
         ...   
640    0.000000
642    0.000000
341    0.000000
76     0.000000
1      0.000000
Name: 124, Length: 671, dtype: float64

유사도 상위 k명의 유사도와 id 추출합니다.
이때 가장 유사도가 높은 id는 user_i로 제외합니다.

In [22]:
top_k_similarity = user_i_similarity[1: k + 1]
top_k_similar_user_ids = top_k_similarity.index
C:\Users\sjy99\AppData\Local\Temp\ipykernel_38316\3664279467.py:1: FutureWarning: The behavior of `series[i:j]` with an integer-dtype index is deprecated. In a future version, this will be treated as *label-based* indexing, consistent with e.g. `series[i]` lookups. To retain the old behavior, use `series.iloc[i:j]`. To get the future behavior, use `series.loc[i:j]`.
  top_k_similarity = user_i_similarity[1: k + 1]
In [23]:
top_k_similar_user_ids
Out[23]:
Int64Index([458, 379, 355, 282, 271], dtype='int64', name='userId')
In [24]:
top_k_similarity
Out[24]:
userId
458    0.455216
379    0.433607
355    0.432242
282    0.423280
271    0.409402
Name: 124, dtype: float64

2.3 K명의 유사한 유저들이 아이템 i에 평가한 선호도를 유사도 기준으로 가중 평균한다.¶

In [25]:
tok_k_similar_ratings = user_movie_matrix.loc[top_k_similar_user_ids, movie_id]
In [26]:
movie_id
Out[26]:
648
In [27]:
tok_k_similar_ratings
Out[27]:
userId
458    4.5
379    0.0
355    3.5
282    4.0
271    0.0
Name: 648, dtype: float64

평가 점수가 있는 유저에 대한 Weight 추출합니다

In [28]:
top_k_weight = (tok_k_similar_ratings > 0) * top_k_similarity
In [29]:
top_k_weight
Out[29]:
userId
458    0.455216
379    0.000000
355    0.432242
282    0.423280
271    0.000000
dtype: float64

유사도가 곱해진 평가 점수의 합을 유사도 합으로 나눕니다.

In [30]:
weighted_rating = top_k_weighted_ratings.sum()
weight = top_k_weight.sum()
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
c:\Users\sjy99\Desktop\패스트\Part4. 머신러닝 알고리즘의 모든 것\2. 실습자료\Chapter 12_recommendation_system\03_KNN 협업필터링 실습.ipynb Cell 49 line 1
----> <a href='vscode-notebook-cell:/c%3A/Users/sjy99/Desktop/%ED%8C%A8%EC%8A%A4%ED%8A%B8/Part4.%20%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%9D%98%20%EB%AA%A8%EB%93%A0%20%EA%B2%83/2.%20%EC%8B%A4%EC%8A%B5%EC%9E%90%EB%A3%8C/Chapter%2012_recommendation_system/03_KNN%20%ED%98%91%EC%97%85%ED%95%84%ED%84%B0%EB%A7%81%20%EC%8B%A4%EC%8A%B5.ipynb#X66sZmlsZQ%3D%3D?line=0'>1</a> weighted_rating = top_k_weighted_ratings.sum()
      <a href='vscode-notebook-cell:/c%3A/Users/sjy99/Desktop/%ED%8C%A8%EC%8A%A4%ED%8A%B8/Part4.%20%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D%20%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%9D%98%20%EB%AA%A8%EB%93%A0%20%EA%B2%83/2.%20%EC%8B%A4%EC%8A%B5%EC%9E%90%EB%A3%8C/Chapter%2012_recommendation_system/03_KNN%20%ED%98%91%EC%97%85%ED%95%84%ED%84%B0%EB%A7%81%20%EC%8B%A4%EC%8A%B5.ipynb#X66sZmlsZQ%3D%3D?line=1'>2</a> weight = top_k_weight.sum()

NameError: name 'top_k_weighted_ratings' is not defined
In [ ]:
weight
Out[ ]:
1.31073817898241

weight가 0보다 작은 경우 유저 모두 평가하지 않은 경우입니다.

In [ ]:
if weight > 0:
    prediction_rating = weighted_rating / weight
else:
    prediction_rating = 0
In [ ]:
prediction_rating
Out[ ]:
4.008763709331574

2.4 예측 선호도가 높은 아이템을 유저에게 추천한다.¶

모든 영화에 대해서 점수를 예측하고 예측 평가 점수가 높은 영화를 유저에게 추천합니다.

2.4.1 선호도 계산¶

In [ ]:
prediction_dict = {}

# 모든 영화 아이디에 대해 평점 예측
for movie_id in user_movie_matrix.columns:

    # 이미 유저가 평가한 경우 제외
    if user_movie_matrix.loc[user_i, movie_id] > 0:
        continue
    
    tok_k_similar_ratings = user_movie_matrix.loc[top_k_similar_user_ids, movie_id]

    top_k_weighted_ratings = tok_k_similar_ratings * top_k_similarity
    top_k_weight = (tok_k_similar_ratings > 0) * top_k_similarity

    weighted_rating = top_k_weighted_ratings.sum()
    weight = top_k_weight.sum()

    if weight > 0:
        prediction_rating = weighted_rating / weight
    else:
        prediction_rating = 0

    # 영화 아이디별로 예측 평가 점수 저장
    prediction_dict[movie_id] = prediction_rating

영화 아이디별 예측 평가 점수를 내림차순으로 정렬합니다.

In [ ]:
prediction = pd.Series(prediction_dict).sort_values(ascending=False)

2.4.2 상위 아이템 추출¶

예측 평가 점수 상위 10개의 영화 아이디 추출합니다.

In [ ]:
recommend = prediction[:10].index
In [ ]:
movies.loc[recommend]
Out[ ]:
title
movieId
1258 The Shining
924 2001: A Space Odyssey
3861 The Replacements
524 Rudy
3916 Remember the Titans
260 Star Wars
2692 Run Lola Run
1207 To Kill a Mockingbird
3949 Requiem for a Dream
3039 Trading Places

3. KNN with Means¶

k가 5인 KNN Basic을 이용해 유저 "124" 가 아직 평가하지 않은 영화 "31"에 대한 점수를 예측하는 과정입니다.

In [ ]:
user_id = 124
k = 5
movie_i = 648

pivot함수를 이용해 영화 아이디가 인덱스이고, 유저 아이디가 컬럼, 값이 평가 점수인 movie_user_matrix를 만듭니다.

결측값은 0으로 대체합니다.

In [ ]:
movie_user_matrix = ratings.pivot(
    index="movieId",
    columns="userId",
    values="rating",
)
movie_user_matrix = movie_user_matrix.fillna(0)

3.1 아이템간의 유사도를 계산한다.¶

영화간의 피어슨 유사도를 계산합니다.

In [ ]:
movie_similarity = np.corrcoef(movie_user_matrix)
In [ ]:
movie_similarity = pd.DataFrame(
    data=movie_similarity,
    index=movie_user_matrix.index,
    columns=movie_user_matrix.index,
)
In [ ]:
movie_similarity.shape
Out[ ]:
(9066, 9066)

3.2 아이템 i와 비슷한 아이템을 k개 찾는다.¶

영화 "648"과 유사한 다른 영화 k개를 찾습니다.

우선 movie_i와 다른 영화 간의 유사도 추출

In [ ]:
movie_i_similarity = movie_similarity.loc[movie_i]

다른 영화와의 유사도 내림차순 정렬합니다.

In [ ]:
movie_i_similarity = movie_i_similarity.sort_values(ascending=False)

유사도 상위 k개의 유사도와 id 추출 합니다.
이 때 가장 유사도가 높은 id는 movie_i로 제외합니다.

In [ ]:
top_k_similarity = movie_i_similarity[1: k + 1]
top_k_similar_movie_ids = top_k_similarity.index
In [ ]:
top_k_similar_movie_ids
Out[ ]:
Int64Index([780, 733, 736, 786, 376], dtype='int64', name='movieId')
In [ ]:
top_k_similarity
Out[ ]:
movieId
780    0.534337
733    0.522740
736    0.430270
786    0.401280
376    0.370700
Name: 648, dtype: float64

3.3 아이템 i의 평균 선호도를 계산한다.¶

영화별로 특징이 되는 평균 선호도를 계산합니다.
평점이 0인 경우 평가하지 않음을 반영하기 위해 결측값으로 대체합니다.

In [ ]:
movie_user_matrix = movie_user_matrix.replace(0, np.NaN)
In [ ]:
movie_bias = movie_user_matrix.mean(1)
In [ ]:
movie_bias
Out[ ]:
movieId
1         3.872470
2         3.401869
3         3.161017
4         2.384615
5         3.267857
            ...   
161944    5.000000
162376    4.500000
162542    5.000000
162672    3.000000
163949    5.000000
Length: 9066, dtype: float64

3.4 유저가 평가한 K개의 아이템의 선호도의 편차를 유사도 기준으로 가중 평균한다.¶

3.4.1 유저별 영화 평가 점수 편차 계산¶

In [ ]:
movie_user_matrix_wo_bias = movie_user_matrix.sub(movie_bias, axis=0)
In [ ]:
movie_user_matrix_wo_bias
Out[ ]:
userId 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 ... 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
movieId
1 NaN NaN NaN NaN NaN NaN -0.87247 NaN 0.12753 NaN NaN NaN 1.12753 NaN -1.872470 NaN NaN NaN -0.872470 -0.37247 NaN NaN -0.87247 NaN NaN 1.12753 NaN NaN NaN 0.127530 NaN NaN NaN NaN NaN NaN 0.12753 NaN NaN NaN ... NaN NaN NaN NaN -0.87247 NaN NaN NaN NaN 0.127530 NaN NaN NaN NaN 1.127530 0.12753 NaN 0.127530 NaN NaN NaN 0.12753 1.127530 NaN NaN NaN NaN NaN -1.37247 NaN NaN 0.12753 -0.37247 NaN NaN NaN NaN NaN 0.12753 1.12753
2 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN -1.401869 NaN NaN NaN -0.401869 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN -1.401869 NaN 0.598131 NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN 0.598131 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN -0.401869 0.598131 NaN NaN NaN NaN NaN NaN 1.598131 NaN NaN -0.401869 NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN 0.838983 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN -0.161017 NaN NaN NaN NaN NaN -0.161017 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN 0.838983 -0.161017 NaN NaN NaN NaN 1.838983 NaN NaN NaN -0.161017 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN -0.161017 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 0.615385 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN -1.384615 NaN NaN NaN NaN 0.615385 -1.384615 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
5 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN 1.232143 NaN NaN -0.267857 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN -0.267857 0.732143 NaN NaN NaN NaN NaN NaN NaN NaN -0.267857 NaN NaN NaN 0.732143 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN -0.267857 NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
161944 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
162376 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
162542 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
162672 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
163949 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

9066 rows × 671 columns

3.4.2 상위 k개의 선호도 추출¶

In [ ]:
tok_k_similar_ratings = movie_user_matrix_wo_bias.loc[top_k_similar_movie_ids, user_id]
top_k_weighted_ratings = tok_k_similar_ratings * top_k_similarity
In [ ]:
tok_k_similar_ratings
Out[ ]:
movieId
780         NaN
733         NaN
736         NaN
786   -0.108696
376         NaN
Name: 124, dtype: float64
In [ ]:
top_k_weighted_ratings
Out[ ]:
movieId
780         NaN
733         NaN
736         NaN
786   -0.043617
376         NaN
dtype: float64

추출된 영화중 평가 점수가 있는 영화에 대한 가중치만 남깁니다.

In [ ]:
top_k_weight = (pd.notna(tok_k_similar_ratings)) * top_k_similarity
top_k_weight
Out[ ]:
movieId
780    0.00000
733    0.00000
736    0.00000
786    0.40128
376    0.00000
dtype: float64

3.4.3 가중 평균¶

유사도가 곱해진 평가 점수의 편차 합을 유사도 합으로 나눔

In [ ]:
weighted_rating = top_k_weighted_ratings.sum()
weight = top_k_weight.sum()
In [ ]:
weight
Out[ ]:
0.40128029563155065

영화 평균 평점 추출

In [ ]:
bias = movie_bias.loc[movie_i]
In [ ]:
bias
Out[ ]:
3.5327380952380953
In [ ]:
if weight != 0:
    # 평균 평점에 가중 편차 합
    prediction_rating = bias + weighted_rating / weight

# weight가 0인 경우 유사 영화 모두 평가하지 않은 경우
else:
    prediction_rating = 0
In [ ]:
prediction_rating
Out[ ]:
3.4240424430641823

3.5 예측 선호도가 높은 아이템을 유저에게 추천한다.¶

모든 영화에 대해서 점수를 예측하고 예측 평가 점수가 높은 영화를 유저에게 추천합니다.

In [ ]:
prediction_dict = {}

# 모든 영화 아이디에 대해 평점 예측
for movie_id in movie_user_matrix.index:

    # 이미 유저가 평가한 경우 제외
    if movie_user_matrix.loc[movie_i, user_id] > 0:
        continue
    
    tok_k_similar_ratings = movie_user_matrix_wo_bias.loc[top_k_similar_movie_ids, user_id]

    top_k_weighted_ratings = tok_k_similar_ratings * top_k_similarity
    top_k_weight = (tok_k_similar_ratings != 0) * top_k_similarity

    weighted_rating = top_k_weighted_ratings.sum()
    weight = top_k_weight.sum()

    bias = movie_bias.loc[movie_i]

    if weight > 0:
        prediction_rating = bias + weighted_rating / weight
    else:
        prediction_rating = 0

    # 영화 아이디 별로 예측 평가 점수 저장
    prediction_dict[movie_id] = prediction_rating

영화 아이디별 예측 평가 점수를 내림차순으로 정렬

In [ ]:
prediction = pd.Series(prediction_dict).sort_values(ascending=False)

예측 평가 점수 상위 10개의 영화 아이디 추출

In [ ]:
recommend = prediction[:10].index
In [ ]:
movies.loc[recommend]
Out[ ]:
title
movieId
163949 The Beatles: Eight Days a Week - The Touring Y...
3774 House Party 2
3785 Scary Movie
3784 The Kid
3783 Croupier
3780 Rocketship X-M
3777 Nekromantik
3775 Make Mine Music
3773 House Party
3787 Shower
In [ ]:
 

'Machine Learning > Recommendation' 카테고리의 다른 글

Matrix Factorization 실습  (0) 2024.03.27
TF-IDF 실습  (0) 2024.03.27
유사도 함수 실습  (0) 2024.03.27
'Machine Learning/Recommendation' 카테고리의 다른 글
  • Matrix Factorization 실습
  • TF-IDF 실습
  • 유사도 함수 실습
Juson
Juson
  • Juson
    Juson의 데이터 공부
    Juson
  • 전체
    오늘
    어제
    • 분류 전체보기 (95)
      • RAG (2)
      • AI (2)
        • NLP (0)
        • Generative Model (0)
        • Deep Reinforcement Learning (2)
        • LLM (0)
      • Logistic Optimization (0)
      • Machine Learning (37)
        • Linear Regression (2)
        • Logistic Regression (2)
        • Decision Tree (5)
        • Naive Bayes (1)
        • KNN (2)
        • SVM (2)
        • Clustering (4)
        • Dimension Reduction (3)
        • Boosting (6)
        • Abnomaly Detection (2)
        • Recommendation (4)
        • Embedding & NLP (4)
      • Reinforcement Learning (5)
      • Deep Learning (10)
        • Deep learning Bacis Mathema.. (10)
      • Optimization (2)
        • OR Optimization (0)
        • Convex Optimization (0)
        • Integer Optimization (0)
      • SNA 분석 (0)
      • 포트폴리오 최적화 공부 (0)
        • 최적화 기법 (0)
        • 금융 베이스 (0)
      • Finanancial engineering (0)
      • 프로그래머스 데브코스(Boot camp) (15)
        • SQL (9)
        • Python (5)
        • Machine Learning (1)
      • Python (22)
      • Project (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
Juson
KNN 협업 필터링 실습
상단으로

티스토리툴바