Python으로 추천 엔진 구축하기
머신러닝의 힘을 활용하기: Python으로 개인화 추천 만들기
이 글은 AI로 번역되었습니다. 오역 가능성이 있다면 댓글로 알려주세요.
Created on September 15|Last edited on September 15
Comment
추천 엔진은 개인화된 디지털 경험을 가능하게 하는 비밀 무기입니다. Netflix가 다음으로 몰입해 볼 만한 시리즈를 추천하고, Amazon이 쇼핑 목록을 큐레이션하며, Spotify가 당신만을 위한 플레이리스트를 만드는 것까지—추천 엔진은 우리가 기술과 상호작용하는 방식을 바꿉니다. 이러한 시스템은 AI를 활용해 사용자 선호를 예측하고 참여도를 높입니다.
이 가이드에서는 추천 엔진이 무엇인지, 이를 구동하는 모델의 유형, 그리고 Python으로 영화 추천 엔진을 만드는 방법을 살펴봅니다. 마지막에는 자체 추천 엔진을 구축하고 Weights & Biases로 실험을 추적할 수 있는 탄탄한 기반을 갖추게 될 것입니다.

목차
추천 엔진이란 무엇일까요?추천 엔진이 중요한 이유는 무엇일까요?추천 엔진은 어떻게 작동할까?추천 엔진 모델협업 필터링콘텐츠 기반 필터링하이브리드 모델Python 튜토리얼: 간단한 추천 엔진 만들기라이브러리 가져오기데이터셋 다운로드 및 압축 해제실험 추적을 위한 Weights & Biases 설정협업 필터링콘텐츠 기반 필터링결론
추천 엔진이란 무엇일까요?
추천 엔진은 데이터와 머신러닝 알고리즘을 활용해 사용자가 좋아하거나 필요로 할 가능성이 높은 항목을 예측하는 시스템입니다. 사용자 행동, 선호도, 그리고 유사한 사용자의 패턴을 분석하여 개인화된 추천을 제공함으로써 참여도를 높이고 비즈니스 성과를 향상시킵니다.
추천 엔진은 방대한 사용자 데이터—예를 들어 검색 및 탐색 기록, 구매 이력, 콘텐츠 상호작용—를 분석해 트렌드를 파악하고 예측을 수행합니다. 이들은 가상의 비서처럼 작동하여 사용자에게는 의사결정을 쉽게 만들어 주고, 기업에는 가치를 극대화해 줍니다.
예시는 다음과 같습니다:
- 시청 기록과 별점에 기반해 콘텐츠를 추천하는 Netflix 같은 스트리밍 플랫폼.Amazon 같은 전자상거래 웹사이트가 함께 자주 구매되는 상품이나 보완 제품을 추천하는 경우.Spotify 같은 음악 앱이 청취 습관에 맞춘 맞춤형 플레이리스트를 선별해 제공하는 경우.
추천 엔진이 중요한 이유는 무엇일까요?
인기 항목의 정적 목록과 달리, 추천 엔진은 사용자 행동에 따라 동적으로 적응합니다. 또한 실시간으로 수백만 명의 사용자와 항목을 분석하도록 확장되어 다음과 같은 이점을 제공합니다:
- 개인화: 추천이 개인의 취향에 맞게 맞춤화되도록 보장합니다.
- 효율성: 사용자가 관련성 높은 콘텐츠나 제품을 더 빠르게 찾아볼 수 있도록 돕습니다.
- 지속적 학습: 더 많은 데이터가 수집될수록 정확도가 향상됩니다.
개인화된 실행 가능한 제안을 제공하는 추천 엔진은 엔터테인먼트부터 헬스케어에 이르기까지 맞춤형 경험이 성공의 핵심인 현대 애플리케이션에서 없어서는 안 될 존재입니다. 소규모 앱이든 글로벌 플랫폼이든, 추천 엔진의 동작 원리를 이해하는 것이 의미 있는 사용자 상호작용을 만드는 기반입니다.
추천 엔진은 어떻게 작동할까?
추천 엔진의 워크플로우는 다섯 가지 핵심 단계로 나눌 수 있습니다:
- 데이터 수집: 브라우징 기록, 평점, 구매 내역 등과 같은 사용자 데이터를 수집합니다.
- 데이터 처리: 데이터의 품질을 보장하기 위해 정제와 전처리를 수행하고, 필요에 따라 결측값을 처리하며 데이터를 정규화합니다.
- 알고리즘 선택: 적절한 모델을 선택하세요—협업 필터링, 콘텐츠 기반 필터링, 또는 하이브리드 접근 방식.
- 추천 생성: 모델을 사용해 사용자 선호도에 따라 아이템을 예측하고 순위를 매기세요.
- 피드백 루프: 클릭, 평점, 구매와 같은 사용자 피드백을 반영해 시스템을 지속적으로 개선합니다.

추천 엔진 모델
추천 엔진 모델은 작동 방식에 따라 세 가지 범주로 나눌 수 있습니다.
협업 필터링
협업 필터링 비슷한 취향을 가진 친구에게 추천을 부탁하는 것에 비유할 수 있습니다. 당신과 같은 영화나 책을 즐긴 친구의 추천을 신뢰하듯, 협업 필터링은 다수 사용자의 선호와 행동을 바탕으로 개인화된 제안을 제공합니다. 협업 필터링은 두 가지 하위 범주로 나뉩니다:
- 사용자 기반 필터링: 비슷한 취향을 가진 사용자들을 비교합니다. 예: 사용자 A와 사용자 B가 모두 액션 영화를 좋아한다면, 사용자 B가 최근에 좋아한 작품이 사용자 A에게 추천될 수 있습니다.
- 아이템 기반 필터링: 아이템 간 유사성에 초점을 둡니다. 예: “The Da Vinci Code”를 구매한 사람들은 “Angels & Demons”도 함께 구매했습니다.
콘텐츠 기반 필터링
콘텐츠 기반 필터링 당신만의 개인 에코 챔버입니다. 마치 당신의 취향과 식이 제한을 정확히 아는 전담 셰프를 두는 것과 같습니다. 이 셰프는 다른 사람들이 무엇을 먹는지는 굳이 고려하지 않고, 오직 당신의 고유한 선호와 비선호에만 집중합니다.
예를 들어, 이탈리안 요리와 채식 요리를 선호한다고 밝혀왔다면, 다른 사람들이 무엇을 먹는지와 상관없이 셰프는 채식 라자냐나 버섯 리소토 같은 메뉴를 추천할 것입니다. 이 방식은 콘텐츠에 대한 정확하고 상세한 정보가 제공되고, 사용자의 선호가 분명하고 일관될 때 특히 유용합니다.
하이브리드 모델
하이브리드 추천 시스템은 잘 아는 친구와 유능한 개인 비서를 모두에게 조언을 구하는 결합형 접근과 비슷합니다. 그 친구는 당신의 과거 선택과 비슷한 사람들의 선호를 바탕으로 당신의 취향을 파악하고 있으며(협업 필터링처럼), 개인 비서는 당신이 좋아했던 아이템의 속성에 기반해 당신의 구체적인 취향과 요구 사항을 이해하고 있습니다(콘텐츠 기반 필터링처럼).
이 둘을 결합하면, 당신의 취향에 맞춤화되면서도 다른 사용자들의 전반적인 경향과 유사성을 반영한 추천을 제공할 수 있습니다.
추천 엔진 모델을 간단한 표로 정리해 봅시다:

Python 튜토리얼: 간단한 추천 엔진 만들기
소매를 걷어 올리세요. 이제 Python으로 직접 추천 엔진을 만들어 볼 시간입니다. 협업 필터링과 콘텐츠 기반 필터링 두 가지 구현을 살펴보겠습니다. 또한 실험 추적을 위해 Weights & Biases도 사용할 것입니다. 실험 추적자, 두 방법 모두에 적용되는 기초 설정부터 들어가 봅시다.
라이브러리 가져오기
이 셀은 프로젝트 전반에서 사용할 라이브러리를 가져옵니다. 다음과 같은 라이브러리들은 pandas 그리고 numpy 데이터 조작에 도움이 되며, scipy 특잇값 분해(SVD)와 같은 도구를 제공합니다. wandb 실험을 추적하고 기록할 수 있게 해줍니다.
import requestsimport zipfileimport pandas as pdimport numpy as npfrom scipy.sparse import csr_matrixfrom scipy.sparse.linalg import svdsfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import mean_squared_errorfrom math import sqrtimport pandas as pdimport numpy as npfrom sklearn.feature_extraction.text import TfidfVectorizerfrom sklearn.metrics.pairwise import cosine_similarity!pip install wandb!wandb loginimport wandb
데이터셋 다운로드 및 압축 해제
여기에서는 다운로드합니다 MovieLens 100K 데이터셋영화에 대한 사용자 평점을 포함합니다. 데이터셋을 압축 해제한 후, 처리를 시작하기 위해 평점을 DataFrame으로 로드합니다.
# Download the dataseturl = 'http://files.grouplens.org/datasets/movielens/ml-100k.zip'r = requests.get(url, allow_redirects=True)open('ml-100k.zip', 'wb').write(r.content)# Extract the datasetwith zipfile.ZipFile('ml-100k.zip', 'r') as zip_ref:zip_ref.extractall('ml-100k')# Load the datasetsdf_ratings = pd.read_csv('ml-100k/ml-100k/u.data', sep='\t', names=['user id', 'movie id', 'rating', 'timestamp'], header=None)
실험 추적을 위한 Weights & Biases 설정
엔진이 생성한 추천과 평균제곱근오차(RMSE)와 같은 핵심 지표를 기록하기 위해 Weights & Biases 프로젝트를 초기화합니다.
# Initialize a new wandb runwandb.init(project='movie_recommendation_system', name='Content_Based_Filtering')
협업 필터링
이제 협업 필터링 구현을 시작해 봅시다.
데이터 전처리
이 단계에서는 로드를 수행합니다 movid_id 및 movie_title 열입니다. 목표는 각 행이 하나의 user_id, 각 열은 movie_id이며, 행렬의 값은 사용자의 평점으로 구성되어 영화 제목 추천에 도움이 됩니다.
# Read the dataset, specify column names for movie attributes and use '|' as the delimiter to address the dataset's format and character encoding (Latin-1). The usecols parameter limits the imported columns to just movie IDs and titles.df_movies = pd.read_csv('ml-100k/ml-100k/u.item', sep='|', encoding='latin-1', header=None,names=['movie id', 'movie_title', 'release_date', 'video_release_date','IMDb_URL', 'unknown', 'Action', 'Adventure', 'Animation','Children', 'Comedy', 'Crime', 'Documentary', 'Drama', 'Fantasy','Film-Noir', 'Horror', 'Musical', 'Mystery', 'Romance', 'Sci-Fi','Thriller', 'War', 'Western'], usecols=[0, 1]
데이터 분할 및 행렬 생성
전체 데이터는 학습용 80%와 테스트용 20%로 분할됩니다. 이러한 분할을 통해, 보지 못한 영화에 대한 사용자 선호도를 예측하는 것을 목표로 하는 현실적인 시나리오에서 모델을 평가할 수 있습니다.
# Split the data into training and testing setstrain_data, test_data = train_test_split(df_ratings, test_size=0.2, random_state=42)
그다음 각 행이 사용자에, 각 열이 영화에 대응하는 행렬을 생성합니다.
# Reshaping the training and test setstest_matrix = test_data.pivot_table(index='user id', columns='movie id', values='rating', fill_value=0)train_matrix = train_data.pivot_table(index='user id', columns='movie id', values='rating', fill_value=0)# Convert the matrices to sparse matricestrain_matrix_sparse = csr_matrix(train_matrix, dtype=np.float32)test_matrix_sparse = csr_matrix(test_matrix, dtype=np.flo
학습 행렬에 SVD를 수행하기
특이값 분해(SVD)는 사용자–아이템 행렬의 차원을 축소하여, 사용자 평점의 패턴을 설명하는 잠재 요인을 식별합니다. 이러한 요인은 보지 못한 아이템에 대한 평점을 예측하는 데 도움이 됩니다.
number_of_factors = 50 # Placeholder for the number of latent factorsregularization_strength = 0.1 # Placeholder for regularization strength# Perform SVD on the training matrixU, sigma, Vt = svds(train_matrix_sparse, k=number_of_factors)sigma = np.diag(sigma)# Log SVD model parameters and hyperparameterswandb.config.update({"number_of_factors": number_of_factors,"regularization_strength": regularization_strength})# Add user mean back to get actual rating prediction for training setuser_ratings_mean_train = np.array(train_matrix.mean(axis=1))predicted_ratings_train = np.dot(np.dot(U, sigma), Vt) + user_ratings_mean_train.reshape(-1, 1)
평균제곱근오차 (RMSE)
RMSE는 정량 데이터를 예측하는 모델의 오차를 측정하는 표준 지표입니다. 이 문맥에서 RMSE는 사용자가 부여한 평점을 기준으로 모델의 예측 정확도를 수치화합니다. RMSE 값이 낮을수록 모델 성능이 더 우수함을 의미합니다.
#Function to calculate the rmse between prediction and ground_truth.def rmse(prediction, ground_truth):#Filters and reshape the prediction array by selecting only those predictions where the corresponding ground_truth rating exists (is non-zero). flatten() then converts the array into a one-dimensional array.prediction = prediction[ground_truth.nonzero()].flatten()#Similar to the prediction array, this line filters the ground_truth array for non-zero values.ground_truth = ground_truth[ground_truth.nonzero()].flatten()#Compute the mean squared error between the filtered prediction and ground_truth arrays. The sqrt (square root) function is then applied to this value to obtain the RMSE.return sqrt(mean_squared_error(prediction, ground_truth))# Calculate RMSE for train datatrain_rmse = rmse(predicted_ratings_train, train_matrix.to_numpy())# Calculate RMSE for test datatest_rmse = rmse(predicted_ratings_train, test_matrix.to_numpy())#log the RMSEwandb.log({"RMSE Train": train_rmse,"RMSE Test": test_rmse})print('User-based Train CF RMSE: ' + str(train_rmse))print('User-based Test CF RMSE: ' + str(test_rmse))
추천 받기
이 함수는 예측된 평점을 정렬하고 사용자가 이미 평점을 매긴 영화는 제외하여 특정 사용자에게 상위 영화 추천을 예측합니다.
# Function to recommend movies for the test datasetdef recommend_movies_test(user_id, num_recommendations=3):user_row_number = user_id - 1#Sorting predicted ratings for the usersorted_user_predictions = pd.Series(predicted_ratings_train[user_row_number]).sort_values(ascending=False)#Filtering previously user's rated moviesuser_data = test_data[test_data['user id'] == user_id]user_full = (user_data.merge(df_movies, how='left', left_on='movie id', right_on='movie id').sort_values(['rating'], ascending=False))#Generating recommendationsrecommendations = (df_movies[~df_movies['movie id'].isin(user_full['movie id'])].#Selecting top recommendations: merge(pd.DataFrame(sorted_user_predictions).reset_index(), how='left',left_on='movie id',right_on='index').rename(columns={0: 'Predictions'}).sort_values('Predictions', ascending=False).iloc[:num_recommendations, :-1])return user_full, recommendations
샘플 추천 항목 기록하기
특정 사용자의 추천 결과를 분석 및 평가를 위해 Weights & Biases에 기록합니다.
# Get recommendations for a specific useruser_id = 5 # Change the user_id to the desired useractual_movies, recommended_movies = recommend_movies_test(user_id, num_recommendations=3)print("\nMovies watched by user:")print(actual_movies)print("\nRecommended movies:")print(recommended_movies)#log the user and movie meticswandb.log({"user_id": user_id,"watched_movies": actual_movies['movie_title'].tolist(),"recommended_movies": recommended_movies['movie_title'].tolist()})# Finish the runwandb.finish()
평가
아래 표는 세 명의 사용자에 대해 협업 필터링을 적용한 실행 결과를 보여줍니다. 각 사용자에게 추천된 상위 세 편의 영화와 함께, 해당 사용자가 이전에 시청한 영화도 함께 표시됩니다.

각 실행에 대해 테스트 및 학습 RMSE가 아래와 같이 Weights & Biases에 기록됩니다. 하이퍼파라미터 SVD 실행에서 모니터링된 항목, 즉 잠재 특성 수와 정규화 강도입니다. x축은 실행 횟수를, y축은 RMSE를 나타냅니다.

아래 그래프는 테스트 RMSE가 가장 낮을 때의 지점과, 함께 모니터링된 다른 하이퍼파라미터 값들을 강조하여 보여줍니다. 결과를 Weights & Biases에 기록하면 모델 통계를 효율적으로 모니터링할 수 있어, 궁극적으로 더 나은 최적화와 분석에 도움이 됩니다.

콘텐츠 기반 필터링
필요한 라이브러리를 임포트하고 Weights & Biases를 설정한 후, 콘텐츠 기반 필터링을 계속 진행하겠습니다:
추천을 위한 데이터를 가져오는 함수를 정의하기
먼저 영화 제목을 가져오는 함수를 초기화하고 movie_id.
# Function to get the title from the movie iddef get_title_from_index(index):return df_movies[df_movies.index == index]["movie_title"].values[0]# Function to get index from the movie iddef get_index_from_movie_id(movie_id):matches = df_movies[df_movies['movie id'] == movie_id].index.valuesreturn matches[0] if len(matches) > 0 else None
아래 코드는 사용자가 이전에 시청한 특정 영화 하나를 기준으로 영화를 추천하는 함수를 보여줍니다. TF-IDF(단어 빈도–역문서 빈도) 행렬 사이의 코사인 유사도를 계산하여, 사용자가 이미 본 영화와 유사한 상위 세 편의 영화를 반환합니다.
def recommend_movies_based_on_one_movie(user_id, num_recommendations=3):# Find the highest-rated movie by the useruser_movies = df_ratings[df_ratings['user id'] == user_id]highest_rated_movie_row = user_movies.sort_values(by='rating', ascending=False).iloc[0]highest_rated_movie_id = highest_rated_movie_row['movie id']# Find the index and title of this movie in df_moviesmovie_index = get_index_from_movie_id(highest_rated_movie_id)if movie_index is None:return "No movies found for the given user.", Nonemovie_title_based_on = get_title_from_index(movie_index)# Calculate the cosine similarities with other moviescosine_similarities = cosine_similarity(tfidf_matrix[movie_index], tfidf_matrix).flatten()similar_movies = list(enumerate(cosine_similarities))sorted_similar_movies = sorted(similar_movies, key=lambda x: x[1], reverse=True)[1:]# Get the recommended moviesrecommended_movies = []for i in range(num_recommendations):index = sorted_similar_movies[i][0]movie_title = get_title_from_index(index)recommended_movies.append(movie_title)return movie_title_based_on, recommended_movies
데이터 전처리
콘텐츠 기반 필터링을 위해, 각 영화의 장르를 하나의 문자열로 합쳐 특징으로 사용합니다.
# Read the dataset, specify column names for movie attributes and use '|' as the delimiter to address the dataset's format and character encoding (Latin-1).df_movies = pd.read_csv('ml-100k/ml-100k/u.item', sep='|', encoding='latin-1', header=None,names=['movie id', 'movie_title', 'release_date', 'video_release_date','IMDb_URL', 'unknown', 'Action', 'Adventure', 'Animation','Children', 'Comedy', 'Crime', 'Documentary', 'Drama', 'Fantasy','Film-Noir', 'Horror', 'Musical', 'Mystery', 'Romance', 'Sci-Fi','Thriller', 'War', 'Western'])# Combine movie genres into a single string for each moviegenre_columns = ['Action', 'Adventure', 'Animation', 'Children', 'Comedy', 'Crime','Documentary', 'Drama', 'Fantasy', 'Film-Noir', 'Horror', 'Musical','Mystery', 'Romance', 'Sci-Fi', 'Thriller', 'War', 'Western']df_movies['combined_features'] = df_movies[genre_columns].apply(lambda x: ' '.join(x.index[x == 1]), axis=1)
데이터 벡터화
텍스트 기반 특징을 유사도 계산에 사용할 수 있도록 TF-IDF로 수치 행렬로 변환합니다.
# Creating a TF-IDF Vectorizer to convert genres to a matrix of TF-IDF featurestfidf_vectorizer = TfidfVectorizer()tfidf_matrix = tfidf_vectorizer.fit_transform(df_movies['combined_features'])
추천 받기
앞서 초기화한 영화 추천 함수는 다음 단계에서 호출되어, 특정 사용자(여기서는 20번)가 시청한 영화 하나를 기준으로 추천을 가져옵니다.
# Get recommendations based on one movie for a specific useruser_id = 20 # Change the user_id to the desired userbased_on_movie, recommended_movies = recommend_movies_based_on_one_movie(user_id)5)5
추천 샘플 로그 기록
시스템이 생성한 추천 결과는 효율적인 비교를 위해 Weights & Biases에 기록되며, 마지막으로 wandb 실행이 완료되었습니다.
# Log sample recommendationswandb.log({"user_id": user_id,"based_on_movie": based_on_movie,"recommended_movies": recommended_movies})# Finish the runwandb.finish()
평가
아래 표는 세 명의 사용자에 대해 콘텐츠 기반 필터링으로 수행된 실행 결과를 보여줍니다. 추천의 기준이 된 영화와 함께 상위 세 편의 추천 영화가 함께 표시됩니다.

이로써 추천 시스템을 처음부터 구축하는 가이드를 마칩니다. 우리가 살펴본 각 모델—협업 필터링과 콘텐츠 기반 필터링—은 근본적으로 다른 방법론에 기반하기 때문에 서로 다른 고유한 결과를 제공합니다. 어떤 필터링 알고리즘을 선택할지는 과제의 구체적인 요구 사항과 데이터셋의 특성에 맞아야 하며, 각 접근법은 조건에 따라 강점을 발휘합니다.
결론
추천 엔진은 현대적 개인화 경험의 핵심 인프라로, 스트리밍 플랫폼과 전자상거래를 비롯한 다양한 산업 전반에서 사용자가 콘텐츠와 상호작용하는 방식을 바꾸고 있습니다. 헬스케어 그리고 교육 분야까지. 데이터와 머신러닝을 활용함으로써, 이러한 시스템은 사용자 만족도를 높일 뿐만 아니라 참여와 유지율을 향상시켜 비즈니스 성장을 견인합니다.
이 가이드에서는 두 가지 근본적인 접근 방식을 살펴보았습니다: 협업 필터링과 콘텐츠 기반 필터링. 각 방법은 고유한 강점과 한계를 지니므로, 두 방식 중 어느 것을 선택할지는 구체적인 사용 사례와 가용 데이터의 특성에 크게 좌우됩니다. 다만 두 접근을 결합한 하이브리드 추천 시스템을 구축하면, 개인화와 확장성의 균형을 최적화하면서 더 정확하고 견고한 결과를 얻는 경우가 많습니다.
AI와 머신러닝 기술이 지속해서 발전함에 따라 추천 엔진의 잠재력은 더욱 커질 것입니다. 실시간 맞춤형 제안을 제공하고 일상생활의 다양한 영역에 자연스럽게 통합되는 것까지, 이러한 시스템은 사용자가 콘텐츠, 제품, 서비스를 발견하는 방식을 새롭게 바꾸고 있습니다. 몰아보기에 적합한 시리즈부터 생명을 구할 수 있는 치료 계획, 완벽하게 큐레이션된 플레이리스트에 이르기까지, 추천 엔진은 디지털 시대에 사용자 만족도를 높이고 비즈니스 성공을 이끌어 가는 핵심적인 역할을 하게 될 것입니다.
이 단계별 가이드는 추천 시스템을 구축하고 실험할 수 있는 기초를 제공합니다. Weights & Biases와 같은 강력한 추적 도구를 최첨단 머신러닝 기법과 결합하면, 사용자에게 의미 있는 맞춤형 경험을 제공하는 시스템을 개발하고 정교화할 수 있습니다. 추천 엔진의 미래는 혁신과 무한한 가능성의 영역입니다—이 가능성을 어디로 이끌어 갈 것인가요?
Add a comment