Processing math: 100%

인공지능/그래프

[그래프 ML] 행렬 분해(Matrix Factorization) - 비음수 행렬 분해(NMF), 특이값 분해(SVD), 주성분 분석(PCA)

백관구 2024. 3. 22. 17:45
반응형

 

※ 출처 : 그래프 머신러닝 (클라우디오 스타밀레 외, 김기성·장기식 옮김)

 

1. 행렬 분해(Matrix Factorization)란

1.1. 개념

XS×A

    대규모 행렬 데이터를 두 개 이상의 작은 행렬들의 곱으로 나타내는 것을 말합니다. 일반적으로 원본 행렬 X를 원천 행렬(source matrix) S와 기여도 행렬(abundance matrix) A의 곱으로 근사합니다. 여기서 S는 데이터를 구성하는 기본 요소들을, A는 각 요소가 원본 데이터에 기여하는 정도를 의미합니다.

 

1.2. 활용

    고차원 데이터의 잠재적인 패턴과 구조를 발견하고, 저차원 표현으로 압축하며, 노이즈를 제거하는 등의 목적으로 사용됩니다.

* 대표적인 활용 분야
  - 추천 시스템의 협업 필터링
  - 신호 처리
  - 텍스트 마이닝과 토픽 모델링
  - 생체 정보 분석
  - 예시
    . 영화 평점 데이터에서 사용자-영화 행렬을 분해하면 사용자 취향과 영화 장르 정보를 추출 가능

 

2. 행렬 분해의 수학적 배경

    행렬 분해는 주어진 m×n 차원의 행렬 X를 원천 행렬 SRm×d와 기여도 행렬 ARd×n의 곱으로 나타내는 것입니다. 여기서 d는 잠재 차원의 개수를 가리킵니다. 목표는 XS×A의 차이를 최소화하는 행렬 S, A를 찾는 것입니다. 이를 수식으로 표현하면:

minXS×A2F

* F : 프로브니우스 노름(Frobenius norm)

※ 프로브니우스 노름(Frobenius Norm)
* 행렬의 노름(norm) 중 하나로, 행렬의 모든 원소 값에 대한 제곱 합의 제곱근
  - 유클리드 노름이 벡터의 크기를 나타내듯, 프로브니우스 노름은 행렬의 크기를 나타내는 스칼라 값임
* m×n 행렬 A=(aij)에 대해,
AF=i,ja2ij
* 연산이 간단하고 미분이 용이하여 최적화 문제에 적합

 

2.1. 원천 행렬(Source Matrix)와 기여도 행렬(Abundance Matrix)

* 원천 행렬(Source Matrix) S
  - 데이터 X를 구성하는 기본 요소나 패턴
  - 각 열 벡터는 하나의 기본 패턴을 의미

* 기여도 행렬(Abundance Matrix) A
  - 각 기본 패턴이 원본 데이터 X에 기여하는 정도
  - 원소 Aij : j번째 패턴이 i번째 데이터 포인트에 기여하는 정도

* 예시
  - 텍스트 데이터 X가 문서-단어 행렬일 때,
    . S : 단어 m, 토픽 d 행렬
    . A : 토픽 d, 문서 n 행렬로, 각 문서가 토픽을 포함하는 정도

 

3. 대표적인 행렬 분해 기법

3.1. 비음수 행렬 분해(NMF; Non-negative Matrix Factorization)

XW×H

* 행렬 XRm×n를 두 개의 비음수 행렬 기저 행렬 WRm×d0, 계수 행렬 HRd×n0의 곱으로 분해
* 비음수 제약 조건으로 인해 부분적으로 가산적인 구조를 가지므로 해석이 용이
* 텍스트 마이닝, 음성 처리, 이미지 처리에 활용

※ 비음수 제약 조건
* 분해된 행렬 W, H의 모든 원소가 0 이상의 값을 갖는 조건
  - 이 제약 조건으로 인해 데이터 XWH의 곱으로 표현될 때, 부분적으로 합쳐지는 구조를 가짐

 

* 파이썬 예제
  ① 예제 그래프 생성

import networkx as nx

G = nx.karate_club_graph()  # 예제 그래프
nx.draw(G)  # 그래프 시각화

예제 그래프 생성

 

  ② 그래프 인접 행렬 추출

A = nx.to_numpy_array(G)  # 그래프 인접 행렬
print("인접 행렬 크기:", A.shape)
print("인접 행렬:\n", A)
인접 행렬 크기: (34, 34)
인접 행렬:
[[0. 4. 5. ... 2. 0. 0.]
 [4. 0. 6. ... 0. 0. 0.]
 [5. 6. 0. ... 0. 2. 0.]
...
 [2. 0. 0. ... 0. 4. 4.]
 [0. 0. 2. ... 4. 0. 5.]
 [0. 0. 0. ... 4. 5. 0.]]

 

  ③ NMF 모델 학습 및 실행

from sklearn.decomposition import NMF

# NMF 모델 학습
nmf = NMF(n_components=5,  # 분해할 성분 개수
          init="nndsvd",  # 초기화 방법
          max_iter=200)  # 최대 반복 횟수
W = nmf.fit_transform(A)  # 기저 행렬(W)
H = nmf.components_  # 계수 행렬(H)
print("기저 행렬(W) 크기:", W.shape)
print("계수 행렬(H) 크기:", H.shape)
기저 행렬(W) 크기: (34, 5)
계수 행렬(H) 크기: (5, 34)

 

  ④ NMF 결과 시각화

import matplotlib.pyplot as plt

fig, subs = plt.subplots(ncols=2, figsize=(10, 5))
# 기저 행렬(W) 시각화
subs[0].imshow(W, cmap="Reds")
subs[0].set_title("W")
# 계수 행렬(H) 시각화
subs[1].imshow(H, cmap="Reds")
subs[1].set_title("H")

plt.show()

NMF 결과. (왼쪽) 기저 행렬, (오른쪽) 계수 행렬

 

3.2. 특이값 분해(SVD; Singular Value Decomposition)

X=UΣVT

* 행렬 X를 직교 행렬 U, VT와 대각 행렬 Σ 세 개의 행렬 곱으로 분해
* 데이터의 랭크와 고유값, 고유벡터를 계산할 수 있음

* 활용
  - 차원 축소 및 데이터 압축
    . Σ의 큰 특이값에 대응하는 U, V의 열 벡터만 선택하여 압축
    . 데이터 차원을 축소하고 노이즈를 제거
  - 노드 임베딩 및 시각화
    . U, V의 열 벡터를 노드 임베딩 벡터로 활용
    . 상위 k개의 열 벡터를 선택하여 k차원 공간에 노드를 임베딩하고 시각화
  - 그래프 클러스터링
    . U, VT의 열 벡터를 기반으로 노드 클러스터링 수행
  - 신호 분석 및 주파수 영역 변환
    . Σ의 특이값은 그래프 신호의 주파수 성분을 나타냄
    . 주파수 영역에서 분석하거나 필터링을 수행할 수 있음

* 파이썬 예제
  ① SVD 실행

import numpy as np

U, Sigma, Vt = np.linalg.svd(A, full_matrices=False)  # SVD
Sigma_matrix = np.diag(Sigma)

print("U 크기:", U.shape)
print("Sigma 크기:", Sigma_matrix.shape)
print("Vt 크기:", Vt.shape)
U 크기: (34, 34)
Sigma 크기: (34, 34)
Vt 크기: (34, 34)

 

  ② SVD 결과 시각화

fig, subs = plt.subplots(ncols=3, figsize=(15, 5))
# U 시각화
subs[0].imshow(U, cmap="Reds")
subs[0].set_title("U")
# Sigma 시각화
subs[1].imshow(Sigma_matrix, cmap="Reds")
subs[1].set_title("Sigma")
# V 시각화
subs[2].imshow(Vt, cmap="Reds")
subs[2].set_title("Vt")

plt.show()

SVD 결과. (왼쪽) U, (중앙) Sigma, (오른쪽) Vt

 

3.3. 주성분 분석(PCA; Principal Component Analysis)

Xu+zipi

* 데이터 X를 평균 벡터 u와 주성분 벡터 pi, 주성분 벡터에 투영된 X의 값인 zi의 선형조합으로 나타냄
* 고차원 데이터의 차원을 낮추면서 가능한 많은 변동성을 보존하는 기법
* 차원 축소, 데이터 시각화, 노이즈 제거에 활용

* 파이썬 예제
  ① PCA 실행

from sklearn.decomposition import PCA

pca = PCA(n_components=5)  # PCA 모델 생성
zi = pca.fit_transform(A)  # PCA 모델 학습 및 변환
u = pca.mean_  # 평균 벡터(u)
pi = pca.components_  # 주성분 벡터(pi)

print("투영 벡터(zi) 크기:", zi.shape)
print("평균 벡터(u) 크기:", u.shape)
print("주성분 벡터(pi) 크기:", pi.shape)
투영 벡터(zi) 크기: (34, 5)
평균 벡터(u) 크기: (34,)
주성분 벡터(pi) 크기: (5, 34)

 

  ② PCA 결과 시각화

fig, subs = plt.subplots(ncols=2, figsize=(10, 5))
# 투영 벡터(zi) 시각화
subs[0].imshow(zi, cmap="Reds")
subs[0].set_title("zi")
# 계수 행렬(H) 시각화
subs[1].imshow(pi, cmap="Reds")
subs[1].set_title("pi")

plt.show()

PCA 결과. (왼쪽) 투영 벡터, (오른쪽) 주성분 벡터

 

4. 행렬 분해의 활용 사례

* 그래프 데이터에서 노드 간 링크 존재 여부를 예측하는 문제
  - (소셜 네트워크) 친구 관계 예측
  - (생물학 네트워크) 단백질 간 상호작용 예측

 

4.2. 노드 임베딩(Node Embedding)

* 그래프 데이터의 노드를 낮은 차원의 밀집 벡터로 변환하는 작업
  - DeepWalk, Node2Vec 기법

 

4.3. 그래프 신호 처리(Graph Signal Processing)

* 그래프 신호(Graph Signal)
  - 그래프 구조의 각 노드에 스칼라 값이 할당된 형태
  - 예시
    . (교통 네트워크) 각 도로 구간의 혼잡도
    . (센서 네트워크) 각 센서의 측정값
    . (소셜 네트워크) 각 사용자의 특성값
    . (분자 구조) 각 원자의 전하량

* 그래프 신호의 필터링, 압축, 보간에 이용
  - 그래프 신호를 푸리에 기저(Fourier basis)로 분해

※ 그래프 푸리에 기저(Graph Fourier Basis)
* 그래프 라플라시안 행렬(Graph Laplacian Matrix)의 고유벡터(eigenvectors)로 구성되며, 이 고유벡터들은 그래프 구조를 반영하는 기저 함수 역할을 함
  - 그래프 신호를 그래프 라플라시안의 고유벡터들의 선형 조합으로 표현할 수 있음
f=αiϕi
  - f : 그래프 신호, ϕi : 그래프 푸리에 기저(고유벡터), αi : 계수

※ 그래프 라플라시안 행렬(Graph Laplacian Matrix)
* 그래프의 구조적 특성을 포착하는 행렬
L=DA
  - D : 차수 행렬(Degree matrix)
    . 대각 행렬로 D(i,i)i번째 노드의 차수
  - A : 인접 행렬(Adjacency matrix)
* 주요 특성
  - 대칭 행렬
  - 고유값은 0 이상
  - 고유벡터들은 그래프 푸리에 기저를 형성

 

4.4. 그래프 클러스터링(Graph Clustering)

* 그래프의 구조적 유사성을 포착
  - 커뮤니티 탐지

 

반응형