주제

1. 추천 시스템
2. 컨텐츠 기반 필터링
3. 협업 필터링
4. 휴대폰 추천 시스템 실습

 

1. 추천 시스템

  • 사용자가 관심을 가질 만한 정보(상품, 서비스 등)를 필터링해서 제공하는 기법
  • 사용자의 선호도 및 과거 행동을 기반으로 함
  • 이를 통해 사용자 만족감을 높이고, 서비스 사용 시간 및 매출 증대의 효과를 기대할 수 있음
  • 추천 시스템의 특징 :
    • 정보 과부하 문제 해결
      • 수많은 옵션 중 가장 관련도 높은 항목을 선택
    • 맞춤형 경험
      • 사용자 기호 반영
      • 사용자의 충성도와 만족도를 증가
    • 비즈니스 가치
      • 구매 유도 및 사용자 참여도 증가
      • 데이터 확보
  • 추천 시스템의 기본 원리 :
    1. 콘텐츠 기반 필터링(Content-based Filtering)
    2. 협업 필터링(Collaborative Filtering)
    3. 하이브리드 추천 시스템
  • 활용 사례 :
    • 유튜브 영상 추천
    • 맞춤형 건강 검진 항목 추천
    • 음식 배달 서비스 추천

 

2. 컨텐츠 기반 필터링

  • 내가 좋았던 것을 기반으로 추천
  • 사용자가 관심을 보였던 아이템의 특성을 분석하여 이와 유사한 특성을 갖고 있는 다른 아이템을 추천

1. 아이템 프로파일을 구성

  • 프로파일 : 아이템을 설명할 특성의 모음집
  • 특성은 서로 다른 이종 데잉터의 집합도 가능함
  • 예. 유튜브 영상이라면 영상의 주제, 조회수, 좋아요, 인기 프레임 등

2. 각 특성 당 정보 추출

  • 특성은 사람이 지정하기 때문에 추천 과정에서 필요한 계산이 불가능
  • 프로파일을 구성하는 특성을 숫자의 형태로 변경
  • 각 특성 데이터에 적합한 embedding을 진행
    • 텍스트라면 NLP, 이미지라면 Image 처리, 숫자라면 범주형 혹은 그대로 사용 등
  • 이 과정은 모든 아이템에 동일하게 적용되어야 함

3. 아이템들의 프로파일을 생성

  • 사용자가 사용한 아이템의 프로파일과 사용하지 않은 아이템의 프로파일을 생성하는 과정
  • 동일한 임베딩 과정을 거쳐야 함

4. 유사도 계산 및 추천

  • 사용자 프로파일과 아이템 프로파일 간의 유사도(임베딩 값의 유사도)를 계산
  • 코사인 유사도, 유클리드 거리, 피어슨 상관계수 등을 사용
  • 만약 사용자가 갖고 있는 아이템이 다수라면 단순 평균, 사용자가 남긴 다른 메타 정보로 가중합을 구하여
  • 사용자의 최종 임베딩 값 도출
  • 유사도를 기반으로 상위 N개를 추천
  • 아직 경험하지 않은 아이템 중 유사도가 높은 아이템을 추천

 

3. 협업 필터링

  • 사용자들의 사이의 상호작용 데이터 혹은 선호도 패턴 데이터를 기반으로 추천을 수행
  • 사용자 기반(User-based) :
    • 사용자들의 아이템 선호 데이터를 활용
    • 비슷한 선호도 또는 행동 패턴을 보이는 사용자의 선호를 추천
  • 아이템 기반(Item-based) :
    • 사용자들이 아이템을 평가한 데이터를 활용
    • 특정 사용자가 사용한 아이템의 평가와 비슷한 아이템을 추천

3.1 사용자 기반 협업 필터링

1. 상호 작용 데이터 준비

  • 사용자로부터 얻은 데이터 활용
  • 기존 데이터가 없다면 사용할 수 없음 : 콜드 스타트(Cold start)

2. 사용자(행) - 아이템(열) 상호 작용 테이블 생성

  • 상호 작용이 없는 경우 누락값으로 표시

3. 사용자 간 유사도 추출

  • 유사도란 사용자들이 아이템에 대해 얼마나 비슷한 반응을 보였는지를 의미
  • 코사인 유사도, 피어슨 상관계수 등이 활용

4. 유사도 기반 아이템 추천

  • 유사도를 기반으로 "이웃"을 선정
  • 이웃이 높게 평가한 아이템을 추천

 

예시)

  • 영화A ~ 영화E, 사용자 a ~ f에 대한 사용자 협업 필터링 예시
  • 영화를 보고 난 후의 평점(1~5) 데이터를 활용
  • a가 본 영화가 아닌 것 중 이웃이 높게 평가한 영화 : 영화E

왼 : 사용자의 평가, 오른쪽 사용자끼리의 유사도

 

3.2 아이템 기반 협업 필터링

  • 아이템 간의 유사성을 분석해 추천을 수행하는 방법

1. 상호 작용 데이터 준비

2. 아이템 간 유사도 계산

  • 수집된 상호 작용 데이터를 기반으로 아이템 유사도를 계산
  • 코사인 유사도, 피어슨 상관계수 등

3. 추천 점수 계산

  • 아이템 유사도와 사용자 상호 작용 데이터를 조합해 추천 점수 계산
  • 사용자가 평가한 아이템과 유사한 아이템들의 대해 가중 평균을 냄
  • (사용자의 평가(가중치) * 아이템 유사도)를 모두 더한 값을 사용

4. 최종 아이템 추천

  • 추천 점수를 기반으로 추천 진행

 

동일한 예시)

  • 사용자 a가 아직 시청하지 않은 영화 : D, E
  • D의 추천 점수 : 4x0.0507 + 4x0.0514 + 4x0.4105 = 0.0504
  • E의 추천 점수 : 동일한 방법으로 = 6.1684
  • 결론 : 사용자 a에게 영화 E를 추천! (영화E를 더 높게 평가할 확률이 높다)

왼 : 사용자의 평가, 오 : 영화끼리의 유사도

 

4. 휴대폰 추천 시스템 실습

  • 사용할 데이터 : 케글의 2022년 미국에서 가장 인기있었던 휴대폰 데이터(링크)
  • 휴대폰 데이터, 사용자 평가 데이터를 이용하여 추천 시스템 구현이 목표

4.1 컨텐츠 기반 필터링 적용

  • 13개의 세부 정부 중 분석에 사용할 특성 선택
  • 브랜드, 모델, OS, 메모리, 램, 가격으로 프로파일 구성
  • 임베딩 :
    • 브랜드, 모델, OS : 텍스트 → TF-IDF 점수 적용
    • 메모리, 램, 가격 : 숫자 → MinMax Scaling 적용
# 프로파일 구성을 위한 특성 선택
# 선택한 특성: 'brand', 'model', 'operating system', 'internal memory', 'RAM', 'price'

# 'brand', 'model', 'operating system'을 기반으로 문자열 생성 : TF-IDF에 입력으로 들어갈 예정
data_df['feat_text'] = data_df[['brand', 'model', 'operating system']].astype(str).agg(' '.join, axis=1)
# 'internal memory', 'RAM', 'price'은 숫자형 특성 : MinMax Scailing에 활용 예정
data_df['feat_num_IM'] = data_df['internal memory']
data_df['feat_num_RAM'] = data_df['RAM']
data_df['feat_num_PRC'] = data_df['price']
# Embedding으로 특성 표현
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.preprocessing import MinMaxScaler

# TF-IDF Vectorizer를 사용하여 특성 문자열을 벡터로 변환
tfidf_vectorizer = TfidfVectorizer()
tfidf_matrix = tfidf_vectorizer.fit_transform(data_df['feat_text'])

# MinMaxScaler를 활용해 수치형 데이터를 정규화
scaler = MinMaxScaler()
scaled_features = scaler.fit_transform(data_df[['feat_num_IM', 'feat_num_RAM', 'feat_num_PRC']])
  • tifidf_matrix를 dense 형태로 변환 후 stacking하여 TF-IDF 벡터와 스케일링된 수치형 결합
# tfidf_matrix를 dense 형태로 변환하고, 처음 5개 행을 확인
tfidf_matrix_dense = tfidf_matrix.toarray()

# TF-IDF 벡터와 스케일링된 수치형 특성을 결합
import numpy as np
combined_features = np.hstack((tfidf_matrix.toarray(), scaled_features))

 

유사도 계산 및 추천

  • 코사인 유사도를 사용하여 항목 간 유사도 계산
  • 두 핸드폰 쌍의 유사도를 미리 구하여 Matrix 형태로 출력
  • 정사각 행렬(num_cellphone x num_cellphone)
# 유사도 계산
from sklearn.metrics.pairwise import cosine_similarity

# 코사인 유사도를 사용하여 항목 간 유사도 계산
cosine_sim = cosine_similarity(combined_features, combined_features)

1은 자기 자신과의 유사도

  • 추천 함수 구현
    1. 비교 대상이 되는 핸드폰을 선택
    2. 유사도 행렬에서 다른 핸드폰과의 유사도를 가져옴
    3. 유사도를 기반으로 상위 N개의 핸드폰을 선택함
    4. 선택된 핸드폰의 정보를 출력
# 추천 생성 예시
# 특정 휴대폰과 비슷한 휴대폰을 번환하기 위한 함수 구현
def get_content_based_recommendations(cellphone_index, cosine_sim=cosine_sim, data_df=data_df):
    sim_scores = list(enumerate(cosine_sim[cellphone_index]))
    sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)
    sim_scores = sim_scores[1:6]  # 가장 유사한 상위 5개 항목 선택, 0: 자기 자신
    cellphone_indices = [i[0] for i in sim_scores]
    return data_df.iloc[cellphone_indices][['brand', 'model', 'operating system', 'internal memory', 'RAM', 'price']]
  • 존재하지 않는 아이디가 있기 때문에 랜덤하게 N번째 휴대폰에 대한 추천 생성 예시 실행
# 원하는 N 번째의 휴대폰에 대한 추천 생성 예시 실행
from IPython.display import display

N = 4
print('선택한 휴대폰 : ')
display(data_df.iloc[N:N+1][['brand', 'model', 'operating system', 'internal memory', 'RAM', 'price']])

example_recommendations = get_content_based_recommendations(N)
print('\n추천된 비슷한 휴대폰 : ')
display(example_recommendations)

선택된 모델과 추천된 모델의 목록 확인

 

4.2 사용자 기반 협업 필터링

  • 사용자 - 핸드폰 상호 작용 데이터 준비
  • 사용자 평가 데이터를 이용하여 전체 33개의 핸드폰 중 10개를 제시(없는 부분은 0으로 채워넣기)
  • 행에는 사용자 정보, 열에는 핸드폰 정보가 있는 matrix 생성
  • 같은 사용자 ID를 기준으로 rating column의 값을 집계
# 사용자 기반 협업 필터링을 위한 사용자-항목 평가 행렬 생성
# 평가 점수가 없는 항목은 0으로 채워 넣기!
user_item_matrix = user_item_df.pivot_table(index='user_id', columns='cellphone_id', values='rating').fillna(0)
user_item_matrix

사용자 - 핸드폰 평가 행렬

 

사용자 간 유사도 추출

  • 마찬가지로 코사인 유사도 계산
  • 유사도 행렬을 데이터 프레임으로 변환
  • 사용자 기반으로 추천을 진행하기 위해서는 "이웃"을 생성해야하기 때문!
# 코사인 유사도 계산
user_similarity = cosine_similarity(user_item_matrix)
print('user_similarity matrix 크기 : ', user_similarity.shape)

# 유사도 행렬을 DataFrame으로 변환
user_similarity = pd.DataFrame(user_similarity, index=user_item_matrix.index, columns=user_item_matrix.index)
display(user_similarity)

사용자 간 유사도 행렬

 

유사도 기반 아이템 추천

  • 현재 사용자와 다른 사용자 간의 유사도를 이용하여 현재 사용자가 사용해보지 않은 핸드폰 중 유사한 사용자들이 높게 평가한 항목을 추천하는 함수 구현
def recommend_for_user(user_id, user_similarity, user_item_matrix, top_n=5):
    # 현재 사용자와 다른 사용자 간의 유사도 가져오기
    user_similarities = user_similarity.loc[user_id]

    # 가장 유사한 사용자들 찾기
    similar_users = user_similarities.sort_values(ascending=False)[1:].index

    # 유사한 사용자들이 높게 평가한 항목 추천
    recommended_items = pd.Series(dtype='float64')
    for similar_user in similar_users:
        # 유사한 사용자의 평가 가져오기
        user_ratings = user_item_matrix.loc[similar_user]

        # 현재 사용자가 평가하지 않은 항목만 선택
        user_ratings = user_ratings[user_ratings.index.isin(user_item_matrix.loc[user_id][user_item_matrix.loc[user_id] == 0].index)]

        # 추천 목록에 추가
        recommended_items = recommended_items.add(user_ratings, fill_value=0)

    # 가중치가 높은 순으로 항목 정렬 및 상위 N개 추천
    recommended_items = recommended_items.sort_values(ascending=False)[:top_n]

    return recommended_items.index.tolist()
  • 추천 확인해보기
# 베이스 사용자가 평가한 핸드폰과 해당 점수를 보여주는 코드
base_user_ratings = user_item_df[user_item_df['user_id'] == base_user_idx]

# 베이스 사용자가 평가한 핸드폰의 상세 정보를 가져오기. 원본 핸드폰 데이터와 병합
base_user_rated_phones = pd.merge(base_user_ratings, data_df, left_on='cellphone_id', right_on='cellphone_id', how='left')

# 베이스 사용자가 평가한 핸드폰 및 점수 출력
print(f"베이스 사용자({base_user_idx})가 평가한 핸드폰과 점수:")
display(base_user_rated_phones[['brand', 'model', 'operating system', 'internal memory', 'RAM', 'price', 'rating']])

# 추천 결과로 나온 핸드폰의 스팩 보여주기
# 추천된 핸드폰 ID 리스트를 기반으로 원본 핸드폰 데이터에서 해당 핸드폰의 상세 정보를 가져옴
recommended_phones_info = data_df[data_df['cellphone_id'].isin(recommendations_for_user)]

# 등수 정보를 포함
rankings = [rank + 1 for rank, _ in enumerate(recommendations_for_user)]

# 추천된 핸드폰 ID와 등수를 DataFrame으로 변환
recommended_phones_with_rank = pd.DataFrame({
    'cellphone_id': recommendations_for_user,
    'rank': rankings
})

# 추천된 핸드폰의 상세 정보와 등수 정보를 병합
recommended_phones_info = pd.merge(recommended_phones_info, recommended_phones_with_rank, on='cellphone_id')


# 추천된 핸드폰의 상세 정보 출력
print("\n추천된 핸드폰의 상세 정보:")
display(recommended_phones_info[['cellphone_id', 'brand', 'model', 'operating system', 'internal memory', 'RAM', 'price', 'rank']])

사용자 기반 추천 결과

 

4.3 아이템 기반 협업 필터링

  • 과정은 거의 동일
  • 이번에는 아이템 간 유사도를 계산한 행렬을 준비
# 아이템-사용자 평가 행렬 생성
item_user_matrix = user_item_matrix.T

# 코사인 유사도 계산
item_similarity = cosine_similarity(item_user_matrix)

# 유사도 행렬을 DataFrame으로 변환
item_similarity_df = pd.DataFrame(item_similarity, index=item_user_matrix.index, columns=item_user_matrix.index)
  • 추천 함수 구현
# 사용자가 평가하지 않은 항목에 대해 추천 점수를 계산하는 함수
def calculate_recommendation_scores(user_id, item_similarity_df, user_item_matrix, topn=5):
    # 사용자가 평가한 항목 확인
    user_ratings = user_item_matrix.loc[user_id]
    rated_items = user_ratings[user_ratings > 0].index

    # 사용자가 평가하지 않은 항목 확인
    unrated_items = user_ratings[user_ratings == 0].index

    # 추천 점수를 저장할 빈 Series 생성
    recommendation_scores = pd.Series(index=unrated_items, dtype=np.float64)

    # 사용자가 평가하지 않은 각 항목에 대해 추천 점수 계산
    for item in unrated_items:
        # 현재 항목과 사용자가 평가한 항목들 간의 유사도
        item_similarities = item_similarity_df.loc[item, rated_items]

        # 유사도와 사용자의 평가 점수의 가중합 계산
        weighted_scores = item_similarities * user_ratings[rated_items]

        # 가중합의 총합을 추천 점수로 사용
        recommendation_scores[item] = weighted_scores.sum() / item_similarities.sum()

    # NaN 값을 제거하고 점수가 높은 순으로 정렬
    recommendation_scores = recommendation_scores.dropna().sort_values(ascending=False)

    return recommendation_scores[:topn]

추천 결과 확인

 

 

 


느낀점

추천 시스템을 만드는 것에 관심이 있었는데 오늘 처음으로 어떻게 만들어지는지 배우고, 실습도 해볼 수 있어서 너무 좋았다. 추천 시스템 프로젝트를 많이 봤었는데 나도 기회가 된다면 꼭 해보고 싶다는 생각이 들었다.

+ Recent posts