아이템 기반에서는 dummy_rating을 transpose 시켜준 뒤 나머지 과정은 동일합니다.
# 아이템 기반
import numpy as np
import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity
# 데이터셋
dummy_rating = {
"scifi1": [4.0, 5.0, 1.0, np.nan, 1.0],
"scifi2": [5.0, 3.0, np.nan, 2.0, np.nan],
"scifi3": [3.0, 3.0, np.nan, 1.0, 2.0],
"comedy1": [np.nan, 2.0, 4.0, 4.0, 3.0],
"comedy2": [2.0, 2.0, 5.0, np.nan, 3.0],
"comedy3": [1.0, np.nan, 4.0, 3.0, 4.0]
}
# DataFrame으로 변환
df = pd.DataFrame(dummy_rating)
# NaN 값을 0으로 처리하거나, 다른 값으로 처리할 수 있지만 여기선 0으로 처리
df_filled = df.fillna(0)
# 아이템 간 코사인 유사도 계산
cosine_sim = cosine_similarity(df_filled.T) # .T로 전치하여 아이템 간 유사도를 계산
# 결과를 DataFrame 형태로 보기 좋게 표시
cosine_sim_df = pd.DataFrame(cosine_sim, index=df.columns, columns=df.columns)
# 출력
cosine_sim_df
계산과정
정규화 적용 버전
4. Surprise 라이브러리를 활용한 협업필터링 구현
데이터 로드
from surprise import Dataset, Reader, KNNBasic
from surprise.model_selection import train_test_split
from surprise import accuracy
import pandas as pd
import numpy as np
# 1. 데이터 로드
!wget "https://grepp-reco-test.s3.ap-northeast-2.amazonaws.com/movielens/ratings.csv"
movies_df = pd.read_csv("https://grepp-reco-test.s3.ap-northeast-2.amazonaws.com/movielens/movies.csv")
# pandas로 데이터 로드
ratings_df = pd.read_csv("ratings.csv")
# 2. NaN 값 처리 (예: NaN을 0으로 채우기) NaN 값을 처리하지 않으면 모델 학습과 예측에서 오류가 발생
ratings_df['rating'] = ratings_df['rating'].fillna(0)
# 3. 'surprise' 포맷으로 변환
reader = Reader(line_format='user item rating timestamp', sep=',', skip_lines=1)
dataset = Dataset.load_from_df(ratings_df[['userId', 'movieId', 'rating']], reader)
# 학습용, 테스트용 데이터 분리
trainset, testset = train_test_split(dataset, test_size=0.2)
사용자 기반 유사도 계산시 sim_options에서 user_based=True,
아이템 기반 유사도 계산시 sim_options에서 user_based=False로 설정하면 됩니다.
🔎 sim_options - name: 유사도를 계산할 방법을 정의 ('cosine', 'pearson', 'msd' 등) - user_based: 사용자 기반 추천인지 아이템 기반 추천인지를 설정 (True이면 사용자 기반, False이면 아이템 기반)
# 사용자 기반 KNN 모델 만들기
sim_options = {
'name': 'cosine',
'user_based': True, # 사용자 기반 유사도 계산
}
model = KNNBasic(sim_options=sim_options)
# 모델 학습
model.fit(trainset)
# 테스트셋에서 예측
predictions = model.test(testset)
# 예측 정확도 출력
rmse = accuracy.rmse(predictions)
print(f"RMSE: {rmse}")
# 예를 들어 user1에게 'scifi1'을 추천할 경우
user_id = "user1"
item_id = "scifi1"
# 예측된 평점 출력
prediction = model.predict(user_id, item_id)
print(f"Prediction for {user_id} on {item_id}: {prediction.est}")
사용자 기반 출력 예시화면
아이템 기반 출력 예시 화면
그런데 기억기반 방식은 평점을 예측하는게 아니라, 유사도를 측정하는 것이라고 앞선 이론에서 설명했는데, output의 결과를 보니 user1의 scifi1의 예상 평점이 나오네요. 조금 의아할 수 있습니다. 사용자 기반 CF로 평점을 예측할 수 있을까요?
답변은 그렇다 입니다.
1️⃣ 사용자 기반 CF는 기본적으로유사한 사용자를 찾는 방법이지만, 2️⃣ 유사한 사용자들의 평점을 기반으로 특정 아이템에 대한 예상 평점도 계산할 수 있습니다. 3️⃣평점 예측 공식: 유사한 사용자들의 평점을 가중 평균하여 예측하고 4️⃣ surprise에서 KNNBasic을 사용하면유사한 사용자를 기반으로 평점 예측이 가능합니다.
🔎 KNNBasic 수행 로직 1. 유사도 계산 2. KNN 알고리즘 적용 - 계산된 유사도 매트릭스를 바탕으로, 각 사용자 또는 아이템에 대해 k개의 최근접 이웃을 찾는 KNN 알고리즘을 사용 - 아이템 기반 추천일 경우 k는 유사도가 높은 아이템의 개수 3. 예측값 계산 - 아이템 기반 추천이라면 아이템들의 평점의 가중 평균을 계산하여 점수 예측 - 사용자 기반 추천이라면 유사한 사용자들의 평점의 가중평균을 계산하여 점수 예측