본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.

https://abit.ly/lisbva

 

공부 시작



강의 종료


강의장


학습 인증샷



강의 후기

 

 

ch02-06. 트리 기반 모델

 

 

추천시스템에 주로 사용되는 트리기반모델과 행렬분해 알고리즘을 다루었습니다.

 

트리 기반 모델은 사용자와 아이템의 다양한 피처를 활용해 예측하는 지도 학습 방식입니다.

 

대표적으로 XGBoost나 LightGBM같은 앙상블 모델이 있습니다.

 

이 모델들은 피처 엔지니어링 성능에 큰 영향을 주기 때문에 학습데이터가 충분해야합니다.

다양한 맥락 정보를 반영할 수 있다는 점에서 실제 서비스에 많이 활용됩니다.

 

반대로 행렬 분해는 사용자와 아이템 간의 상호작용 행렬을 분해해 잠재요인을 추출하는 방식으로

SVD, ALS 등이 있습니다.

이는 벡타 공간에 매핑하고 내적으로 선호도를 계산합니다.

다양한 맥락보다는 암묵적인 피드백에도 적절히 기능하는 것이 장점입니다.

 

트리기반은 구조적 정보에, 행렬 분해는 패턴 기반 예측에 강점이 있습니다.

두 방식은 상호 보완적으로 사용될 수 있습니다.

 


 

 

왜 트리 기반 모델은 유저-아이템 매트릭스 자체를 쓰지 않고 피처를 추가로 만들어야하는가?

행렬 분해는 유저-아이템 간 상호작용으로 예측을 할 수 있는데 트리 모델은 왜 피처 엔지니어링이 필요한가?

=>

 

트리 모델은 보통 피처를 기준으로 루트를 나누며 학습하기 때문에 일반화된 패턴을 찾기 어렵다.

행렬 분해는 암묵적인 요인을 학습하기 때문에 유사성을 파악할 수 있다.

 

이 차이로 트리 모델은 아이템의 피터를 수치화해야 좋은 성능을 낼 수 있다.

 

이런 명시적인 요인과 암묵적인 요인을 둘 다 고려하기 위해 하이브리드 방식이 자주 쓰이는지 이해했다.

 


간단한 sklearn 베이스라인 코드

# recommender_baseline.py

import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.decomposition import TruncatedSVD

# 1. 샘플 사용자-아이템 평점 데이터 생성
np.random.seed(42)
n_users = 100
n_items = 50

data = []
for user in range(n_users):
    for item in range(np.random.randint(10, 30)):
        item_id = np.random.randint(0, n_items)
        rating = np.random.randint(1, 6)  # 평점 1~5
        data.append([user, item_id, rating])

df = pd.DataFrame(data, columns=["user_id", "item_id", "rating"])

# 2. Train/Test 분리
train_df, test_df = train_test_split(df, test_size=0.2, random_state=42)

# -----------------------
# 트리 기반 모델 (GradientBoosting)
# -----------------------

# 사용자 ID, 아이템 ID를 단순 숫자 피처로 사용
X_train_tree = train_df[["user_id", "item_id"]]
y_train_tree = train_df["rating"]
X_test_tree = test_df[["user_id", "item_id"]]
y_test_tree = test_df["rating"]

tree_model = GradientBoostingRegressor()
tree_model.fit(X_train_tree, y_train_tree)
tree_preds = tree_model.predict(X_test_tree)
tree_rmse = mean_squared_error(y_test_tree, tree_preds, squared=False)
print(f"트리 기반 모델 RMSE: {tree_rmse:.4f}")

# -----------------------
# 행렬 분해 모델 (SVD)
# -----------------------

# 사용자-아이템 평점 행렬 생성
rating_matrix = df.pivot_table(index="user_id", columns="item_id", values="rating").fillna(0)

# Truncated SVD로 잠재 요인 추출
svd = TruncatedSVD(n_components=10, random_state=42)
user_factors = svd.fit_transform(rating_matrix)
item_factors = svd.components_

# 예측 함수 정의
def predict_svd(user, item):
    if user >= user_factors.shape[0] or item >= item_factors.shape[1]:
        return 3.0  # 기본값
    return np.dot(user_factors[user], item_factors[:, item])

# SVD 예측
svd_preds = []
svd_targets = []

for _, row in test_df.iterrows():
    pred = predict_svd(int(row["user_id"]), int(row["item_id"]))
    svd_preds.append(pred)
    svd_targets.append(row["rating"])

svd_rmse = mean_squared_error(svd_targets, svd_preds, squared=False)
print(f"행렬 분해(SVD) 모델 RMSE: {svd_rmse:.4f}")

 

 

 

실제 서비스를 위해 사용자의 로그데이터를 수집해두고 쌓여야 적절한 추천시스템 학습이 진행 될 것 같은데
아직은 정확하게 어떤 데이터를 어떤 구조로 수집해야할지 고민입니다.

흔히 cold-start 문제라던가 sparse한 데이터에도 추천을 하기위해 하이브리드 모델을 처음부터 도입하고 싶은데

 

적어도 사용자의 경험에서 부정적이지는 않아야 하는데 부담이 있습니다.