행렬 분해(Matrix Factorization)

HanJu Han·2024년 11월 28일
0

추천 시스템

목록 보기
18/49

1. 실제 데이터 예시

다음과 같은 3명의 사용자와 4개의 영화에 대한 평점 데이터가 있다고 가정하겠습니다:

실제 평점 행렬 R (1-5점 척도):
           어벤져스  타이타닉  인셉션  노트북
사용자A      5         3        4      2
사용자B      ?         4        3      5
사용자C      4         ?        5      1

3x4 행렬

2. 목표

  • 평점 행렬 R을 두 개의 행렬 P(사용자 특성)와 Q(영화 특성)로 분해
  • 잠재 요인의 수를 k=2로 설정 (예: 액션 선호도, 로맨스 선호도)

3. 학습 과정 상세 설명

Step 1: 초기화

먼저 P와 Q 행렬을 작은 난수로 초기화합니다.

P (사용자 특성 행렬, 3×2):
사용자A: [0.1, 0.2]
사용자B: [0.2, 0.1]
사용자C: [0.1, 0.1]

Q (영화 특성 행렬, 4×2):
어벤져스: [0.2, 0.1]
타이타닉: [0.1, 0.2]
인셉션:   [0.2, 0.2]
노트북:   [0.1, 0.3]

(3x2) x (2x4) = 3x4 행렬

Step 2: 예측과 오차 계산

예측값은 P와 Q의 내적으로 계산됩니다. (matrix 계산)
예를 들어, 사용자A의 어벤져스 예측 평점:

예측값 = (0.1 × 0.2) + (0.2 × 0.1) = 0.04

실제값 = 5
오차 = 5 - 0.04 = 4.96

Step 3: 경사하강법을 통한 업데이트

각 요소를 다음 공식으로 업데이트합니다:

예)
학습률 α = 0.01
정규화 계수 λ = 0.02

For each observed rating rui:
eui = rui - pui  (실제값 - 예측값)

업데이트 공식:
P[u] = P[u] + α × (eui × Q[i] - λ × P[u])
Q[i] = Q[i] + α × (eui × P[u] - λ × Q[i])

예를 들어, 사용자A의 첫 번째 특성 업데이트:

e = 4.96
P[A,1]new = 0.1 + 0.01 × (4.96 × 0.2 - 0.02 × 0.1)
          = 0.1 + 0.01 × (0.992 - 0.002)
          = 0.1 + 0.0099
          = 0.1099

*아래 자세한 내용 참고

Step 4: 반복 학습

이 과정을 모든 관찰된 평점에 대해 반복합니다. 예를 들어 20회 반복 후:

P (사용자 특성):
사용자A: [0.8, 0.3]  # 액션 선호도 높음
사용자B: [0.3, 0.9]  # 로맨스 선호도 높음
사용자C: [0.9, 0.2]  # 액션 선호도 매우 높음

Q (영화 특성):
어벤져스: [0.9, 0.2]  # 강한 액션 특성
타이타닉: [0.4, 0.8]  # 강한 로맨스 특성
인셉션:   [0.7, 0.5]  # 액션과 로맨스 혼합
노트북:   [0.2, 0.9]  # 매우 강한 로맨스 특성

4. 수렴 조건

다음 중 하나를 만족할 때 학습을 종료합니다:
1. 전체 오차(RMSE)가 임계값(예: 0.001) 이하
2. 지정된 반복 횟수 도달
3. 오차 감소량이 매우 작아짐

5. 최종 예측

학습이 완료된 후, 빈 값 예측:

사용자B의 어벤져스 평점 예측:
= [0.3, 0.9] · [0.9, 0.2]
= (0.3 × 0.9) + (0.9 × 0.2)
= 0.27 + 0.18
= 0.45
이를 1-5 척도로 변환하면 약 3.5점

이러한 과정을 통해 행렬 분해는 사용자와 아이템의 잠재적 특성을 학습하고, 이를 바탕으로 누락된 평점을 예측할 수 있게 됩니다.


Step 3: 경사하강법을 통한 업데이트

1. 목적 함수(Loss Function) 정의

먼저 우리가 최소화하려는 목적 함수를 정의합니다:

J = Σ(rui - p̂ui)² + λ(||P||² + ||Q||²)

여기서:
- rui: 사용자 u의 아이템 i에 대한 실제 평점
- p̂ui: 예측 평점 (P[u]와 Q[i]의 내적)
- λ: 정규화 계수 (과적합 방지)
- ||P||², ||Q||²: P와 Q 행렬의 프로베니우스 놈(L2 정규화)

2. 편미분(Partial Derivatives) 계산

목적 함수를 P와 Q의 각 요소에 대해 편미분합니다:

∂J/∂puk = -2Σ(rui - p̂ui)qik + 2λpuk
∂J/∂qik = -2Σ(rui - p̂ui)puk + 2λqik

여기서:
- puk: 사용자 u의 k번째 잠재 요인
- qik: 아이템 i의 k번째 잠재 요인

3. 실제 업데이트 과정 예시

앞서 든 예시를 더 자세히 살펴보겠습니다:

초기값:
사용자A의 특성 벡터 P[A] = [0.1, 0.2]
어벤져스의 특성 벡터 Q[어벤져스] = [0.2, 0.1]
실제 평점 r = 5
학습률 α = 0.01
정규화 계수 λ = 0.02

Step 3.1: 현재 예측값 계산

p̂ = P[A] · Q[어벤져스]
  = (0.1 × 0.2) + (0.2 × 0.1)
  = 0.02 + 0.02
  = 0.04

Step 3.2: 오차(error) 계산

e = r - p̂
  = 5 - 0.04
  = 4.96

Step 3.3: 각 잠재 요인별 업데이트

사용자A의 첫 번째 잠재 요인(p₁) 업데이트:

기울기 = -(r - p̂)q₁ + λp₁
      = -(4.96 × 0.2) + 0.02 × 0.1
      = -0.992 + 0.002
      = -0.99

새로운 p₁ = 0.1 + α × (-기울기)
          = 0.1 + 0.01 × 0.99
          = 0.1099

사용자A의 두 번째 잠재 요인(p₂) 업데이트:

기울기 = -(4.96 × 0.1) + 0.02 × 0.2
      = -0.496 + 0.004
      = -0.492

새로운 p₂ = 0.2 + 0.01 × 0.492
          = 0.2049

어벤져스의 잠재 요인들도 같은 방식으로 업데이트:

새로운 q₁ = 0.2 + 0.01 × (4.96 × 0.1 - 0.02 × 0.2)
          = 0.2 + 0.01 × (0.496 - 0.004)
          = 0.2049

새로운 q₂ = 0.1 + 0.01 × (4.96 × 0.2 - 0.02 × 0.1)
          = 0.1 + 0.01 × (0.992 - 0.002)
          = 0.1099

Step 3.4: 정규화의 영향

위 계산에서 정규화 항(λ)의 역할:
1. 과적합 방지: 너무 큰 값들이 나오는 것을 막음
2. 수치 안정성: 발산하는 것을 방지
3. 일반화 성능 향상: 보지 않은 데이터에 대한 예측 성능 개선

예를 들어, 정규화가 없다면(λ=0):

p₁의 업데이트 = 0.1 + 0.01 × (4.96 × 0.2)
               = 0.1 + 0.00992
               = 0.10992  // 더 큰 변화

정규화가 있을 때(λ=0.02):

p₁의 업데이트 = 0.1 + 0.01 × (4.96 × 0.2 - 0.02 × 0.1)
               = 0.1 + 0.01 × (0.992 - 0.002)
               = 0.1099   // 약간 더 작은 변화

4. 최적의 하이퍼파라미터 선택

학습률(α)과 정규화 계수(λ)의 선택이 중요합니다:

  1. 학습률이 너무 크면:
α = 0.1 일 때
새로운 p₁ = 0.1 + 0.1 × 0.99 = 0.199
// 한 번에 너무 큰 변화 → 발산 위험
  1. 학습률이 너무 작으면:
α = 0.001 일 때
새로운 p₁ = 0.1 + 0.001 × 0.99 = 0.10099
// 수렴이 너무 느림
  1. 정규화 계수가 너무 크면:
λ = 0.2 일 때
기울기 = -(4.96 × 0.2) + 0.2 × 0.1 = -0.992 + 0.02 = -0.972
// 업데이트가 너무 제한됨

이러한 세부적인 업데이트 과정이 모든 관찰된 평점에 대해 반복되며, 전체 시스템이 수렴할 때까지 계속됩니다.


행렬 분해 추천의 장점

  1. 잠재 요인 파악 능력

Netflix를 예로 들어보겠습니다. 사용자 A가 로맨틱 코미디를 좋아하는데, 반드시 "로맨틱 코미디"라는 장르 태그가 있어서가 아닐 수 있습니다.

  • 밝은 분위기
  • 해피엔딩
  • 가벼운 스토리
    이런 잠재적 특성들을 행렬 분해가 자동으로 찾아냅니다.
  1. 데이터 희소성 문제 해결

실제 사례로, 온라인 서점을 봅시다. 100만 권의 책이 있고 사용자는 평균적으로 10권 정도만 읽었다고 하면:

  • 기존 방식: 99.999%의 데이터가 비어있어 추천이 어려움
  • 행렬 분해: 50개 정도의 잠재 요인으로 압축하여 비어있는 평점을 효과적으로 예측
  1. 계산 효율성

음악 스트리밍 서비스를 예로 들어보겠습니다:

  • 1000만 사용자 × 5000만 곡 = 500조 개의 관계
  • 행렬 분해로 100개 차원 사용 시 = (1000만 + 5000만) × 100 = 6억 개로 축소
    → 계산량이 극적으로 감소
  1. 새로운 아이템 추천 가능

온라인 패션몰 예시:

  • 새로 입고된 청바지의 경우, 아직 구매 데이터가 없어도
  • 다른 청바지들의 잠재 요인(스타일, 핏, 가격대 등)을 기반으로
  • 어떤 고객이 이 청바지를 좋아할지 예측 가능
  1. 개인화된 설명 가능

영화 추천의 예:
"당신이 좋아했던 인셉션과 비슷하게 이 영화도 복잡한 플롯과 SF적 요소가 있습니다."

  • 단순히 장르가 같아서가 아닌
  • 실제 사용자들의 선호도 패턴에서 발견된 깊은 연관성을 설명 가능

다만, 이런 장점들을 최대한 활용하려면 적절한 양의 초기 데이터가 필요하며, 하이퍼파라미터 튜닝이 중요합니다.

profile
시리즈를 기반으로 작성하였습니다.

0개의 댓글