뮤지컬 추천 사이트10(FINAL PROJECT)

ppippi·2023년 11월 15일
0

뮤지컬 추천 사이트

목록 보기
10/10
post-thumbnail

KNN(K-Nearest Neighbors)

지도 학습 알고리즘 중 하나로, 데이터 간의 거리를 기반으로 예측을 수행하는 알고리즘입니다.
주어진 데이터 포인트의 최근접 이웃들을 찾아 해당 이웃들의 레이블을 기반으로 예측을 수행합니다. 이 알고리즘은 분류(classification)와 회귀(regression) 모두에 사용될 수 있습니다.

KNN의 작동원리

  1. 거리측정 : 주어진 데이터 포인트와 다른 모든 데이터 포인트 간의 거리를 측정합니다.
    => 일반적으로 유클리드 거리(Euclidean distance)나 맨해튼 거리(Manhattan distance) 등을 사용
    => 필자는 유클리드 거리(Euclidean distance)를 사용하였다.
    why?
    유클리드 거리측정 방식이 Knn에서 가장 많이 사용되는 방법이기도 하며 두 점 간의 거리를 측정하는데 효과적인 방법으로 알려져 있기 때문이다.
  2. 이웃선택 : 거리가 가장 가까운 K개의 이웃을 선택합니다.
    => K는 사용자가 정의한 하이퍼파라미터로, 일반적으로 홀수로 선택하여 다수결 원칙을 적용
  3. 투표 또는 평균 : 분류 문제의 경우, K개의 이웃 중 다수결 투표를 통해 주어진 데이터 포인트의 클래스를 할당합니다. 회귀 문제의 경우, K개의 이웃의 평균 값을 예측값으로 사용합니다.

KNN의 장점 및 단점

장점
1. 간단하며 훈련 과정이 빠릅니다.

단점
1. 예측을 수행할 때마다 모든 데이터 포인트 간의 거리를 계산해야 하므로 예측 시간이 오래 걸릴 수 있습니다.
2. 특성의 스케일에 민감하게 반응하고, 많은 데이터에 대해서는 계산 비용이 높아질 수 있습니다.

KNN을 추천 시스템에서 사용하는 이유

다른 일부 모델들은 특정한 가정에 기반한 선형 모델이기 때문에 복잡한 비선형 관계를 캡처하는 데 어려움이 있을 수 있습니다. 그러나 KNN은 비선형 관계를 잘 다루어 사용자들의 복잡한 취향을 모델링하는 데 유용하며, 간단하면서도 사용자와 유사한 이웃을 찾아 개인화된 비선형 추천을 제공하여 데이터가 제한된 상황이나 다양한 형태의 아이템에 유용하게 활용될 수 있기 때문입니다.

KNN 모델링 적용

  • 과거 데이터 로드
  • 과거 데이터의 synopsis_numpy_scale열 값인 리스트가 문자열형태로 되어있어서 이것을 파이썬의 리스트로 변환
# past_data['synopsis_numpy_scale']는 데이터프레임 열 중 하나로, 각 행에는 Python의 리스트 형태로 저장되어 있음
# 데이터프레임에서 synopsis_numpy_scale 열의 값을 파싱하여 리스트로 변환
# ast.literal_eval 함수는 문자열을 파이썬의 리터럴 구문으로
# "[1, 2, 3]"로 저장되어 있다면, ast.literal_eval을 적용하면 이 문자열이 파이썬의 리스트 [1, 2, 3]로 변환
past_data['synopsis_numpy_scale'] = past_data['synopsis_numpy_scale'].apply(ast.literal_eval)
  • KNN 모델 초기화 및 모델학습

  • 현재 데이터 로드
  • 현재 데이터의 synopsis_numpy_scale열 값인 리스트가 문자열형태로 되어있어서 이것을 파이썬의 리스트로 변환
# 데이터프레임에서 synopsis_numpy_scale 열의 값을 파싱하여 리스트로 변환
present_data['synopsis_numpy_scale'] = present_data['synopsis_numpy_scale'].apply(ast.literal_eval)
  • KNN 모델 초기화 및 모델학습

  • past작품과 유사한 present작품 상위 6개 추천 + 유클리디안 거리 계산

예를 들어 과거 데이터에서 작품을 선택 (musical_id가 3885인 작품) 후 유클리디안 거리계산을 사용하여 유사한 작품을 찾음

# 선택한 작품과 유사한 작품 찾기
distances, indices = knn_model_present.kneighbors([past_data_scaled[selected_work_index_past]]) # 내주적으로 유클리디안 거리가 계산됨

# 최대 거리와 최소 거리 계산
max_distance = distances.max()
min_distance = distances.min()

# 정규화된 유사도 계산
normalized_distances = 100 * (1 - (distances - min_distance) / (max_distance - min_distance))

# 유사한 작품 출력
print("선택한 작품:")
print(past_data.iloc[selected_work_index_past]['title'])
print("")
print("유사한 작품들:")
for i in range(1, len(indices.flatten())):
    index = indices.flatten()[i]
    normalized_distance = normalized_distances.flatten()[i]
    title = past_data.iloc[index]['title']
    print(f"유사한 작품: {title}, 정규화된 유사도: {normalized_distance}%")


해당 코드는 branch 0.1.2/FAST - model_test/Knn_musical_v1.ipynb확인하실 수 있습니다.


SVD(Singular Value Decomposition, 특이값 분해)

행렬을 세 개의 행렬의 곱으로 분해하는 기법입니다.

SVD 작동원리

  1. 원본 행렬 분해 : 주어진 m × n 행렬 A를 U, Σ, V^T 세 행렬의 곱으로 분해합니다. 여기서 U는 m × m 크기의 직교 행렬, Σ는 m × n 크기의 대각 행렬이며, V^T는 n × n 크기의 전치된 직교 행렬인 것입니다.

  2. 특이값 대각행렬 축소 : Σ 행렬에서 대각 원소 중 0이 아닌 값만 남기고 나머지는 0으로 만듭니다. 이러한 과정을 통해 행렬 A의 중요한 특성을 포착하는데 사용되는 특이값(singular value)이 도출되는 것입니다.

  3. 거리 측정 방법 : 특이값 분해(Singular Value Decomposition, SVD) 자체는 거리 측정 방법을 직접적으로 사용하지 않습니다. SVD는 행렬을 세 부분으로 분해하여 잠재적인 특성을 추출하는 방법입니다. 그러나 SVD를 사용하는 추천 시스템에서는 주로 유사도 측정을 위해 거리 측정 방법을 활용할 수 있습니다.
    => 코사인 유사도(Cosine Similarity)나 피어슨 상관계수(Pearson Correlation Coefficient)와 같은 거리 측정 방법을 사용

SVD 장점 및 단점

장점

  1. 차원 축소와 노이즈 제거: SVD는 주로 차원 축소의 목적으로 사용되며, 특이값 중에서 작은 값들을 제거하여 노이즈를 줄일 수 있습니다.

  2. 데이터 압축: 특이값 중 상대적으로 작은 값들을 버리면서 행렬을 더 작은 형태로 압축할 수 있습니다.

  3. 데이터 이해와 시각화: 특이값 분해를 통해 얻은 잠재적인 특성들을 사용하여 데이터를 더 잘 이해하고 시각화할 수 있습니다.

  4. 추천 시스템에 활용: SVD는 추천 시스템에서 사용자와 아이템 간의 상호 작용을 잘 모델링할 수 있는 강력한 도구로 활용됩니다.

단점

  1. 데이터 희소성 문제: 실제 데이터는 대부분이 희소한 형태를 가지는데, SVD는 대부분의 값이 채워져 있어야 잘 작동합니다. 희소한 데이터에 대한 적용이 어려울 수 있습니다.

  2. 계산 비용: SVD는 계산 비용이 큽니다. 큰 행렬이나 데이터셋에 대한 특이값 분해는 많은 계산 자원을 필요로 합니다.

  3. 유연성 부족: 데이터의 변화에 따라 모델을 즉시 업데이트하기 어렵습니다. 새로운 데이터가 추가되거나 변경되면 전체 행렬을 다시 계산해야 합니다.

  4. 데이터 해석의 어려움: SVD를 통해 얻은 특이벡터나 특이값은 각각의 의미를 해석하기 어려울 수 있습니다. 특히, 특이값이 크게 떨어지는 경우 해석이 어려워집니다.

  5. Cold Start 문제: SVD 기반의 추천 시스템에서는 새로운 사용자나 아이템에 대한 예측이 어려울 수 있습니다. 이를 Cold Start 문제라고 합니다.

SVD를 추천 시스템에서 사용하는 이유

SVD는 사용자-아이템 평가 행렬을 잠재 요인을 기반으로 분해하여 사용자와 아이템 간의 상호 작용을 효과적으로 모델링하고 사용자와 아이템은 잠재적인 특성 벡터로 표현하기 때문에 이를 기반으로 유사도를 계산하고, 사용자들에게 유사한 취향을 가진 아이템을 추천을 사용자 개개인의 특성, 취향, 행동을 고려하여 서비스나 제품을 제공하도록 개인화합니다. 또한 특이값 중에서 작은 값들을 제거함으로써 차원을 축소하고 노이즈를 제거할 수 있습니다. 그리고 기존 사용자-아이템 상호 작용 데이터를 기반으로 모델을 학습하기 때문에, 새로운 사용자나 아이템에 대한 예측이 가능해지므로 Cold Start 문제 대응할 수 있기 때문에 추천 시스템에서 사용합니다.

SVD 모델링 적용

  • 과거 데이터 로드

  • 과거 데이터의 synopsis_numpy_scale열 값인 리스트가 문자열형태로 되어있어서 이것을 파이썬의 리스트로 변환

# 데이터프레임에서 synopsis_numpy_scale 열의 값을 파싱하여 리스트로 변환
past_data['synopsis_numpy_scale'] = past_data['synopsis_numpy_scale'].apply(ast.literal_eval)
  • SVD 모델 초기화 및 모델학습
from sklearn.decomposition import TruncatedSVD

# SVD 모델 초기화 및 훈련
svd = TruncatedSVD(n_components=10)  # 적절한 주성분 개수 선택
transformed_past_data = svd.fit_transform(past_data_scaled)
  • 현재 데이터 로드

  • 현재 데이터의 synopsis_numpy_scale열 값인 리스트가 문자열형태로 되어있어서 이것을 파이썬의 리스트로 변환

# 데이터프레임에서 synopsis_numpy_scale 열의 값을 파싱하여 리스트로 변환
present_data['synopsis_numpy_scale'] = present_data['synopsis_numpy_scale'].apply(ast.literal_eval)
  • SVD 모델 초기화 및 모델학습
# SVD 모델 초기화 및 훈련
svd = TruncatedSVD(n_components=10)  # 적절한 주성분 개수 선택
transformed_present_data = svd.fit_transform(present_data_scaled)
  • past 작품과 유사한 present 작품 상위 5개 추천 결과 + 코사인 유사도 계산
print("선택한 작품:")
print(past_data.loc[selected_work_index_past, 'title'])
print(f"Musical ID: {past_data.loc[selected_work_index_past, 'musical_id']}")
print("")

# 유사도가 높은 순서대로 정렬하여 유사한 작품 인덱스를 찾습니다.
similar_work_indices = similarities.argsort(axis=0)[::-1].flatten()
top_n = 5

for i in range(1, top_n + 1):
    index = similar_work_indices[i]
    similarity = similarities[index]
    title = present_data.loc[index, 'title']
    musical_id = present_data.loc[index, 'musical_id']
    print(f"유사한 작품: {title}, Musical ID: {musical_id}, 정규화된 유사도: {similarity}")


해당 코드는 branch 0.1.3/model_test - model_test/SVD_musical.ipynb확인하실 수 있습니다.


프로젝트 관련 코드는 아래의 주소에서 확인할 수 있습니다
i-Five

0개의 댓글