KNN 기반 협업 필터링 정리

코딩다시시작·2025년 3월 25일

LG DX SCHOOL

목록 보기
28/33

개요

  • 협업 필터링(Collaborative Filtering)은 다른 사용자 또는 다른 아이템의 평점을 바탕으로 내가 평가하지 않은 항목의 점수를 예측
  • KNN 기반 협업 필터링은 그중에서도 비슷한 사용자 또는 비슷한 아이템(K개의 이웃)을 찾아 그들의 평가를 바탕으로 평점을 예측
  • 핵심 아이디어는 "나와 비슷한 K명의 이웃이 좋아하는 건 나도 좋아할 확률이 높음"

사용 이유

  • 추천 시스템에서 사용자 또는 아이템 간 유사성을 활용해 아직 평가되지 않은 항목의 평점 예측 가능
  • 간단한 로직과 직관성으로 인해 널리 사용됨
  • 학습 과정 없이 즉시 적용 가능

수식

r^u,i=vNk(u)(sim(u,v)×rv,i)vNk(u)sim(u,v)\hat{r}_{u,i} = \frac{\sum_{v \in N_k(u)} (sim(u, v) \times r_{v,i})}{\sum_{v \in N_k(u)} sim(u, v)}
  • r^u,i\hat{r}_{u,i} : 사용자 uu의 아이템 ii에 대한 예측 평점
  • sim(u,v)sim(u, v) : 사용자 uuvv 사이의 유사도 (코사인 유사도 사용)
  • rv,ir_{v,i} : 사용자 vv의 아이템 ii에 대한 실제 평점
  • Nk(u)N_k(u) : 사용자 uu와 가장 유사한 K명의 이웃 집합

코드 및 설명

1. 데이터프레임 구성

import numpy as np
import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity

ratings_dict = {
    'User1': [5, 3, np.nan, 1],
    'User2': [4, np.nan, np.nan, 1],
    'User3': [1, 1, np.nan, 5],
    'User4': [1, np.nan, 5, 4],
    'User5': [np.nan, 1, 5, 4]
}
df = pd.DataFrame(ratings_dict, index=['Item1', 'Item2', 'Item3', 'Item4']).T
print("평점 데이터프레임:\n", df)
  • NaN은 아직 평점이 없는 항목
  • 행은 사용자, 열은 아이템

출력

       Item1  Item2  Item3  Item4
User1    5.0    3.0    NaN    1.0
User2    4.0    NaN    NaN    1.0
User3    1.0    1.0    NaN    5.0
User4    1.0    NaN    5.0    4.0
User5    NaN    1.0    5.0    4.0

2. 유사도 행렬 계산

rating_matrix = df.fillna(0).to_numpy()
user_similarity = cosine_similarity(rating_matrix)
  • fillna(0)으로 결측치는 0 처리
  • 코사인 유사도로 사용자 간 유사도 행렬 구함

3. 사용자 기반 KNN 평점 예측 함수

def predict_rating(user_index, item_index, k=2):
    sim_scores = user_similarity[user_index]  
    # 현재 사용자와 다른 사용자 간 유사도 벡터
    
    neighbor_indices = [i for i in range(len(df)) 
                        if not np.isnan(df.iloc[i, item_index]) and i != user_index]
    # 해당 아이템에 대해 실제로 평가를 남긴 이웃 사용자 인덱스 추출
    
    neighbors = sorted(neighbor_indices, key=lambda i: sim_scores[i], reverse=True)[:k]
    # 유사도가 높은 순으로 K명의 이웃 추출
    
    numerator = 0
    denominator = 0
    
    for neighbor in neighbors:
        sim = sim_scores[neighbor]
        rating = df.iloc[neighbor, item_index]
        numerator += sim * rating
        denominator += sim
    
    if denominator == 0:
        return np.nan  # 유사한 이웃이 없을 경우 NaN 반환
    
    return round(numerator / denominator, 2)

동작 방식

  1. user_similarity[user_index] 통해 대상 사용자와 다른 사용자 간 유사도 추출
  2. neighbor_indices로 해당 아이템에 평점을 남긴 사용자 중 자기 자신 제외
  3. neighbors로 유사도 높은 K명의 사용자 선택
  4. 유사도를 가중치로 평점을 예측
  5. 분모가 0이면 NaN 반환 (계산 불가능)

4. 예측 테스트

user_idx = df.index.get_loc("User2")  # User2 인덱스 찾기
item_idx = df.columns.get_loc("Item2")  # Item2 인덱스 찾기

predict_result = predict_rating(user_idx, item_idx, k=2)
print(f'User2의 Item2에 대한 예측 평점: {predict_result}')

출력

User2의 Item2에 대한 예측 평점: 2.34
  • User2는 Item2를 평가하지 않았으므로
  • 비슷한 K명의 이웃들의 평점을 참고해 약 2.34점으로 예측

어디에 쓰이는지

  • 넷플릭스 영화 추천
  • 쿠팡 상품 추천
  • 스포티파이 음악 추천
  • 온라인 쇼핑몰 개인화 추천

정리

항목내용
목적평가하지 않은 항목의 평점을 예측하고 추천 시스템에 활용
이유협업 필터링 핵심은 '비슷한 이웃의 의견 참고'이며 이는 KNN 개념과 동일
방식1) 평점 행렬 생성 → 2) 코사인 유사도 계산 → 3) 이웃 선택 → 4) 가중 평균으로 예측
활용 분야넷플릭스, 왓챠, 유튜브, 쿠팡, 무신사 등 추천 시스템 전반
profile
gpt로 다시 배우는 개발

0개의 댓글