728x90
Collaborative Filtering
사용자와 아이템 간의 상호 상관 관계를 분석하여 새로운 사용자-아이템 관계를 찾아주는 것으로 사용자의 과거 경험과 행동 방식(User Behavior)에 의존하여 추천하는 시스템
책 추천 받을 때
1. 내가 좋아하는 장르, 작가, 출판사의 책 추천
-> Content Based Filtering
2. 나랑 비슷한 성향의 친구들이 읽은 책 책춘
-> Collaborative Filtering
Collaborative Filtering의 대표적인 한계점
- Cold Start
- 문자 그대로 새로운 사용자나 새로운 아이템 등장 시, 기존의 관련된 경험 또는 행동 방식이 없기 때문에 추천이 곤란해지는 문제
- long Tail
- 전체 추천 아이템으로 보이는 비율이 '사용자들의 관심을 많이 받은 소수의 아이템'으로 구성되어 있는 '비대칭적 쏠림 현상'이 발생하는 문제
- 계산 효율 저하
- 계산량이 많은 알고리즘이기에, 사용자가 증가할수록 계산 시간이 더 길어지게 되며 효율성이 저하되는 문제
Memory-based Collaborative Filtering(MBCF)
User Based Collaborative Filtering
- 동일한 사용자의 이웃 아이템의 점수를 기반으로 해당 아이템에 대한 사용자의 선호도 평가
- 이미 평가했거나 상호작용한 사용자를 대상으로 하는 아이템과 유사한 아이템을 찾는 방법
- 방법
- 평점을 기반으로 User-Item matrix 만들기
- 빈 값을 0으로 채우고, 사용자 사이의 유사도 계산
- 유사도를 이용해 가중평균을 구하여 유저의 아이템 선호도 예상
Item Based collaborative Filtering
- 새로운 아이템을 평가할 때, 유사한 아이템에 대해 비슷한 점수들을 매긴 다른 사용자들을 찾은 후, 해당 사용자가 상호 작용한 적 없는 아이템에 대한 아이템의 사용자 점수를 예측하는 방법
- 평점을 기반으로 User-Item matrix 만들기
- 빈 값을 0으로 채우고, 아이템 사이의 유사도 계산
- 유사도를 이용해 가중평균을 구하여 유저의 아이템 선호도 예상
MBCF의 장점
- 최적화나 훈련 과정 X
- 접근 방식이 쉬움
MBCF의 한계점
- sparse 데이터의 경우 성능 저하
- 데이터가 많아지면 계산량 증가로 확장성의 한계
실습
캐글 데이터 사용
https://www.kaggle.com/datasets/ruchi798/bookcrossing-dataset
Book-Crossing: User review ratings
A collection of book ratings
www.kaggle.com
데이터
import pandas as pd
import numpy as np
from typing import List, Set,Optional
books = pd.read_csv(path+'books.csv') # (232348,6)
# Index(['isbn', 'book_title', 'book_author', 'publisher', 'language', 'category'], dtype='object')
users = pd.read_csv(path+'users.csv') # (79516,3)
# Index(['user_id', 'location', 'age'], dtype='object')
ratings = pd.read_csv(path+'ratings.csv') # (56290,3)
# Index(['user_id', 'isbn', 'rating'], dtype='object')
# books, users, ratings 합치기
df = ratings.merge(books, on='isbn')
df = df.merge(users, on='user_id', how='inner') # (56290, 10)
User Based Collaborative Filtering (UBCF)
평점을 기반으로 User-Item matrix를 만들고 코사인 유사도를 이용해 추천 리스트를 만들기
def UBCF(df: pd.DataFrame, user_id: int, topn: Optional[int]=None) -> pd.DataFrame:
topn=11 if topn is None else topn+1
# 존재하는 유저인가?
if user_id in df['user_id'].values:
user_id = str(user_id)
# 평점을 기반으로 User-Item matrix를 만들기
user_item_matrix = df.pivot_table(index=['user_id'], columns=['book_title'], values='rating')
#유사도 계산을 위해 NaN값을 0으로 채워줍니다.
user_item_matrix = user_item_matrix.fillna(0)
#코사인 유사도 계산 (행을 기준으로 유사도)
user_similarity_df = pd.DataFrame(cosine_similarity(user_item_matrix), index=user_item_matrix.index.astype(str), columns=user_item_matrix.index.astype(str))
# user_id와 유사한 사람
sim_user_df = user_similarity_df[user_id].sort_values(ascending=False).reset_index(drop=False).rename(columns={'index':'user_id', user_id:'similarity'})
print('입력한 사용자 id: ',user_id)
display(sim_user_df[1:topn]) #비슷한 사용자를 보여줍니다
else:
print('사용자 id를 다시 확인해주세요')
# 254번과 유사한 상위 5명 유저
UBCF(df, 254, 5)
RMSE 계산
def UBCF_predict_rating(train_df: pd.DataFrame,
test_df: pd.DataFrame) -> list:
# 평점 기준으로 user-item matrix 만들고 유사도 계산
user_item_matrix = train_df.pivot_table(index=['user_id'], columns=['book_title'], values='rating')
user_item_matrix = user_item_matrix.fillna(0)
user_similarity_df = pd.DataFrame(cosine_similarity(user_item_matrix), index=user_item_matrix.index.astype(str), columns=user_item_matrix.index.astype(str))
user_similarity_df.index = user_similarity_df.index.astype(int)
# 예측 결과
rating_list=[]
# 테스트
for test_id, test_book_title in zip(test_df['user_id'].astype(str), test_df['book_title']):
pred_rating = (user_similarity_df[test_id].sort_index().values * user_item_matrix[test_book_title].sort_index().values).sum()/(user_similarity_df[test_id].values.sum())
rating_list.append(pred_rating)
return rating_list
from sklearn.model_selection import train_test_split
# 훈련, 테스트 데이터 분리
train_df, test_df = train_test_split(df, test_size=0.1, random_state=42)
rating_list = UBCF_predict_rating(train_df, test_df)
# RMSE
mean_squared_error(rating_list, test_df['rating'])**0.5 # 3.8697...
Item Based Collaborative Filtering (IBCF)
def IBCF(df: pd.DataFrame, title: str, topn: Optional[int]=None) -> pd.DataFrame:
topn=11 if topn is None else topn+1
if title in df['book_title'].values:
# rating 기준으로 책 제목 - 유저 행령 만들기 - 코사인 유사도가 행을 기준으로 계산하기 때문에
user_item_matrix = df.pivot_table(index=['book_title'], columns=['user_id'], values='rating')
user_item_matrix = user_item_matrix.fillna(0)
item_similarity_df = pd.DataFrame(cosine_similarity(user_item_matrix), index= user_item_matrix.index, columns=user_item_matrix.index)
sim_item_df = item_similarity_df[title].sort_values(ascending=False).reset_index().rename(columns={'index':'book_title',title:'similarity'})
print('입력한 책 이름: ',title)
display(sim_item_df[1:topn])
else:
print('책 제목을 다시 확인해주세요')
# 아래 책과 유사한 상위 5개 책
IBCF(df,'Harry Potter and the Chamber of Secrets (Book 2)', 5)
RMSE
def IBCF_predict_rating(train_df: pd.DataFrame, test_df: pd.DataFrame) -> list:
# 유사도 구하기
user_item_matrix = train_df.pivot_table(index=['book_title'], columns=['user_id'], values='rating')
user_item_matrix = user_item_matrix.fillna(0)
item_similarity_df = pd.DataFrame(cosine_similarity(user_item_matrix), index=user_item_matrix.index, columns=user_item_matrix.index)
# 테스트 예측
rating_list=[]
for test_id, test_book_title in zip(test_df['user_id'], test_df['book_title']):
try:
pred_rating = (item_similarity_df[test_book_title].sort_index().values * user_item_matrix[test_id].sort_index().values).sum() / item_similarity_df[test_book_title].values.sum()
except:
pred_rating=0
rating_list.append(pred_rating)
# 예측 결과
return rating_list
rating_list = IBCF_predict_rating(train_df, test_df)
# RMSE
mean_squared_error(rating_list, test_df['rating'])**0.5 # 3.85
728x90
반응형
'TIL - 외 > 추천시스템' 카테고리의 다른 글
[추천시스템] Model Based Collaborative Filtering - Unsupervised (0) | 2023.04.11 |
---|---|
[추천시스템] Content Based Filtering (0) | 2023.04.11 |
[추천시스템] 추천 시스템 개론 (2) | 2023.04.11 |
댓글