https://colab.research.google.com/drive/1G1jMN8tJ01jNVXtIO8czPbXICL7cX01G?usp=sharing
https://colab.research.google.com/drive/1W1zZHWxPY8iQnKqc-0ic-J75l5caXflV?usp=sharing
https://colab.research.google.com/drive/190Y0a1PPXvW8xx8LFBJROJmP6XKB9kZe?usp=sharing
특히 3차원 이하로 축소하면 시각화를 통한 데이터 분포 파악이 용이하다.
차원 축소는 크게 피처 선택(feature selection)과 피처 추출(feature extraction)로 나뉜다.
피처 선택은
불필요하거나 종속성이 강한 피처를 제거
데이터의 대표적인 주요 피처만 선택
피처 추출은
기존 피처를 압축하여 더 의미 있는 새로운 피처로 변환
원래의 피처와는 완전히 다른 형태의 데이터로 변형됨
피처 추출은 단순한 압축이 아니라 데이터를 더 잘 설명할 수 있는 공간으로 매핑하는 과정이다.
예시:
학생 데이터를 성적, 활동 등 여러 요소로 구성 → 이를 학업 성취도, 문제 해결력 등과 같은 잠재적 특성(Latent Factor)으로 변환할 수 있다.
차원 축소는 단순한 데이터 압축이 아닌 데이터의 잠재적인 의미(요소)를 추출하는 것이 핵심이다.
PCA, SVD, NMF는 대표적인 차원 축소 알고리즘으로, 이미지와 텍스트 분야에서 활용도가 높다.
이미지 분야:
수많은 픽셀로 구성된 이미지를 더 적은 수의 피처로 압축 가능.
함축된 이미지 표현은 과적합 위험을 줄이고 예측 성능을 향상시킬 수 있다.
텍스트 분야:
문서는 수많은 단어(피처)로 구성되며, 이는 고차원 데이터를 형성.
차원 축소 알고리즘은 단어 구성에서 숨겨진 의미(Semantic)나 주제(Topic)를 추출.
특히 SVD와 NMF는 시맨틱 토픽 모델링에서 자주 사용됨.
PCA(Principal Component Analysis)는 가장 대표적인 차원 축소 기법
PCA는 여러 변수 간에 존재하는 상관관계를 이용해 이를 대표하는 주성분(Principal Component)을 추출해 차원을 축소하는 기법입니다.
PCA로 차원을 축소할 때는 기존 데이터의 정보 유실이 최소화되는 것이 당연합니다.
이를 위해서 PCA는 가장 높은 분산을 가지는 데이터의 축을 찾아 이 축으로 차원을 축소하는데, 이것이 PCA의 주성분이 됩니다(즉, 분산이 데이터의 특성을 가장 잘 나타내는 것으로 간주합니다).
키와 몸무게 2개의 피처를 가지고 있는 데이터 세트가 다음과 같이 구성돼 있다고 가정해 보겠습니다.

이 2 개의 피처를 한 개의 주성분을 가진 데이터 세트로 차원 축소를 할 수 있습니다. 데이터 변동성이
가장 큰 방향으로 축을 생성하고 , 새롭게 생성된 축으로 데이터를 투영하는 방식입니다.

PCA는 가장 큰 데이터 변동성(Variance)을 기반으로 첫 번째 벡터 축을 생성합니다.
두 번째 축은 첫 번째 벡터 축에 직각이 되는 직교 벡터로 설정합니다.
세 번째 축은 두 번째 축과 직각이 되도록 생성합니다.
이렇게 생성된 축들에 원본 데이터를 투영함으로써, 벡터 축의 개수만큼의 차원으로 원본 데이터가 축소됩니다.

PCA는 원본 데이터의 피처 개수에 비해 매우 작은 주성분으로 원본 데이터의 총 변동성을 대부분 설명할 수 있는 분석법이다.
PCA는 입력 데이터의 공분산 행렬을 고유값 분해하고, 고유벡터에 입력 데이터를 선형 변환한다.
고유벡터는 PCA의 주성분 벡터이며, 입력 데이터의 분산이 큰 방향을 나타낸다.
고윳값은 고유벡터의 크기를 나타내며, 입력 데이터의 분산을 의미한다.
선형 변환은 특정 벡터에 행렬 A를 곱해 새로운 벡터로 변환하는 것으로, 공간을 바꾸는 개념이다.
분산은 한 변수의 변동을 의미하고, 공분산은 두 변수 간의 변동 관계를 의미한다.
공분산 행렬은 여러 변수 간의 공분산을 포함하는 정방형 행렬이다.

공분산 행렬에서 대각선 원소는 각 변수 (X, Y, 2) 의 분산을 의미함
= 고유벡터는 행렬 A 를 곱하더라도 방향이 변하지 않고 그 크기만 변하는 벡터를 지칭함
(A 는 행렬 , x 는 고유벡터 , a 는 스칼라값 )
고유벡터는 여러 개가 존재
정방 행렬은 최대 그 차원 수만큼의 고유벡터를 가질 수 있음
예를 들어 2x2 행렬은 두 개의 고유벡터를 , 3x3 행렬은 3 개의 고유벡터를 가질 수 있음
이렇게 고유벡터는 행렬이 작용하는 힘의 방향과 관계가 있어서 행렬을 분해하는 데 사용됨
정방행렬 (Square Matrix)
정방행렬은 열과 행이 같은 행렬을 지칭하는데 , 정방행렬 중에서 대각 원소를 중심으로 원소 값이 대칭되는 행렬 , 즉 인 행렬을 대칭행렬이라고 부름
대칭행렬 (Symmetric Matrix)
입력 데이터의 공분산 행렬을 C 라고 하면 공분산 행렬의 특성으로 인해 다음과 같이 분해할 수 있음
위 식은 고유벡터 행렬과 고
유값 행렬로 다음과 같이 대응됨

공분산 C 는 고유벡터 직교 행렬 고유값 정방 행렬 고유벡터 직교 행렬의 전치 행렬로 분해됨
는 i 번째 고유벡터를 , 는 i 번째 고유벡터의 크기를 의미 는 가장 분산이 큰 방향을 가진고유벡터이며 , 는 에 수직이면서 다음으로 가장 분산이 큰 방향을 가진 고유벡터임
선 형대수식까지 써가면서 강조하고 싶었던 것은 입력 데이터의 공분산 행렬이 고유벡터와 고유값으로 분
해될 수 있으며 , 이렇게 분해된 고유벡터를 이용해 입력 데이터를 선형 변환하는 방식이 PCA 라고 함
PCA 수행 과정
from sklearn.datasets import load_iris
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
iris = load_iris()
# 넘파이 데이터 세트를 판다스 Dataframe으로 변환
columns = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
irisDF = pd.DataFrame(iris.data, columns=columns)
irisDF[ 'target' ]=iris.target
irisDF.head (3)

각 품종에 따라 원본 붓꽃 데이터 세트가 어떻게 분포돼 있는지 2 차원으로 시각화해 보겠습니다.
#setosa 는 세모 , versicolor는 네모 , virginica는 동그라미로 표현
markers=['^', 's' , 'o']
#setosa 의 target 값은 0, versicolor 는 1, virginica는 2. 각 target 별로 다른 모양으로 산점도로 표시
for i, marker in enumerate(markers):
x_axis_data = irisDF[irisDF['target']==i]['sepal_length']
y_axis_data = irisDF[irisD['target']==i]['sepal_width']
plt.scatter(x_axis_data, y_axis_data, marker=marker, label=iris. target_names[i])
plt.legend()
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.show()

Setosa 품종은 sepal width > 3.0 그리고 sepal length ≤ 6.0 조건에서 일정하게 분포
Versicolor, Virginica는 단순한 sepal 조건만으로는 분류 어려움
PCA를 통해 4개의 속성을 2개로 축소해 2차원 시각화 진행
PCA 적용 전 모든 속성은 스케일링 필요
사이킷런의 StandardScaler를 이
용해 평균이 0, 분산이 1 인 표준 정규 분포로 iris 데이터 세트의 속성값들을 변환 예졔
from sklearn.preprocessing import StandardScaler
# Target 값을 제외한 모든 속성 값을 StandardScaler를 이용해 표준 정규 분포를 가지는 값들로 변환
iris_scaled = StandardScaler().fit_transform(irisDF.iloc[:, :-1])
from sklearn. decomposition import PCA
pca = PCA(n_components=2)
# fit()과 transform()을 호출해 PCA 변환 데이터 반환
pca. fit(iris_scaled)
iris_pca = pca. transform(iris_scaled)
print(iris_pca. shape)

# PCA 변환된 데이터의 칼럼명을 각각 pca_component_1, pca_component_2 로 명명
pca_columns=[ 'pca_component_1', 'pca_component_2' ]
irisDF_pca = pd.DataFrame(iris_pca, columns=pca_columns)
irisDF_pca['target']=iris.target
irisDF_pca.head (3)

pca_component_1 속성을 X 축으로 , pca_component_2 속성을 Y 축으로 해서 붓꽃 품종이 어떻게 분포되는지 확인# setosa 를 세모 , versicolor를 네모 , virginica를 동그라미로 표시
markers=['^', 's', 'o']
# pca_component_1올 x 축 , pc_component_2 를 y 축으로 scatter plot 수행
for i, marker in enumerate(markers):
x_axis_data = irisDF_pca[irisDF_pca['target']==i]['pca_component_1']
y_axis_data = irisDF_pca[irisDF_pca['target']==i]['pca_component_2']
plt.scatter(x_axis_data, y_axis_data, marker=marker, label=iris.target_names[i])
plt.legend
plt.xlabel('pca_component_1')
plt.ylabel('pca_component_2' )
plt. show()

explained_variance_ratio_ 속성은 전체print(pca.explained_variance_ratio_)

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
import numpy as np
rcf = RandomForestClassifier (random_state=156)
scores = cross_val_score(rcf, iris.data, iris.target, scoring='accuracy' ,cv=3)
print('원본 데이터 교차 검증 개별 정확도 :', scores)
print('원본 데이터 평균 정확도 :', np.mean(scores))

기존 4 차원 데이터를 2 차원으로 PCA 변환한 데이터 세트에 랜덤 포레스트를 적용
pca_X = irisDF_pca[[ 'pca_component_1', 'pca_component_2']]
scores_pca = cross_val_score(rcf, pca_X, iris.target, scoring='accuracy', cv=3 )
print('PCA 변환 데이터 교차 검증 개별 정확도 :', scores_pca)
print('PCA 변환 데이터 평균 정확도 :', np.mean(scores_pca) )

더 많은 피처를 가진 데이터 세트를 적은 PCA 컴포넌트 기반으로 변환한 뒤 , 예측 영향
도가 어떻게 되는지 변환된 PCA 데이터 세트에 기반해서 비교해 보겠습니다.
# header 로 의미 없는 첫 행 제거 , 110c 로 기존 1d 제거
import pandas as pd
df = pd.read_excel('/content/sample_data/default of credit card clients.xls', header=1, sheet_name='Data').iloc[0:, 1:]
print(df.shape)
df.head(3)

-- 신용카드 데이터 세트: 30,000개 레코드, 24개 속성
df.rename(columns={'PAY_0':'PAY_1', 'default payment next month': 'default'}, inplace=True)
y_target = df['default']
X_features = df.drop('default', axis=1)
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
corr = X_features.corr()
plt.figure(figsize=(14, 14))
sns.heatmap(corr, annot=True, fmt=' .1g')

from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
#BILL_ANT1 ~ BILL_AMT6 까지 6 개의 속성명 생성
cols_bill = ['BILL_AMT'+str(i) for i in range(1, 7)]
print('대상 속성명 :', cols_bill)
# 2 개의 PCA 속성을 가진 PCA 객체 생성하고 , explained_variance_ratio_ 계산을 위해 fit( ) 호출
scaler = StandardScaler()
df_cols_scaled = scaler. fit_transform(X_features[cols_bill])
pca = PCA(n_components=2)
pca.fit(df_cols_scaled)
print('PCA Component 별 변동성 :', pca.explained_variance_ratio_)

import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
rcf = RandomForestClassifier(n_estimators=300, random_state=156)
scores = cross_val_score(rcf, X_features, y_target, scoring='accuracy', cv=3 )
print('CV=3 인 경우의 개별 Fold 세트별 정확도 :', scores)
print('평균 정확도:{0:.4f}'.format(np.mean(scores)))

from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df_scaled = scaler.fit_transform(X_features)
pca = PCA(n_components=6)
df_pca = pca.fit_transform(df_scaled)
scores_pca = cross_val_score(rcf, df_pca, y_target, scoring='accuracy', cv=3)
print('CV=3 인 경우의 PCA 변환된 개별 Fold 세트별 정확도 :', scores_pca)
print('PCA 변환 데이터 세트 평균 정확도 : {:.4f}'.format(np.mean(scores_pca)))



from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import load_iris
iris = load_iris()
iris_scaled = StandardScaler().fit_transform(iris.data)
lda = LinearDiscriminantAnalysis(n_components=2)
lda.fit(iris_scaled, iris.target)
iris_lda = lda.transform(iris_scaled)
print(iris_lda.shape)

import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
lda_columns=['lda_component_1' , 'lda_component_2']
irisDF_lda = pd.DataFrame(iris_lda, columns=lda_columns)
irisDF_lda['target']=iris.target
#setosa는 세모 , versicolor는 네모 , virginica는 동그라미로 표현
markers=['^', 's', 'o']
#setosa 의 target 값은 0 , versicolor는 1, virginica는 2. 각 target 별로 다른 모양으로 산정도로 표시
for i, marker in enumerate (markers):
x_axis_data = irisDF_lda[irisDF_lda['target']==i]['lda_component_1']
y_axis_data = irisDF_lda[irisDF_lda['target']==i]['lda_component_2']
plt.scatter(x_axis_data, y_axis_data, marker=marker, label=iris.target_names[i])
plt.legend(loc='upper right')
plt.xlabel('lda_component_1')
plt.ylabel('lda_component_2')
plt.show()



import numpy as np
from numpy.linalg import svd
np.random.seed(121)
a = np.random.randn(4, 4)
print(np.round (a, 3))

- SVD 분해는 numpy.linalg.svd 에 파라미터로 원본 행렬을 입력하면 U 행렬 , Sigma 행렬 , V 전치 행렬을 반환
- Σ 행렬은 일반적으로 대각에만 값이 있고 나머지는 0이므로, 효율을 위해 1차원으로만 표현합니다.
U, Sigma, Vt = svd(a)
print(U.shape, Sigma.shape, Vt.shape)
print('U matrix:\n', np.round(U, 3))
print('Sigma Value: \n', np.round (Sigma, 3))
print('V transpose matrix: \n', np.round(Vt, 3))

- U 행렬이 4 X 4, Vt 행렬이 4 X 4 로 반환됐고 , Sigma 의 경우는 1 차원 행렬인 (4, ) 로 반환
- 분해된 이 U, Sigma, Vr 를 이용해 다시 원본 행렬로 정확히 복원되는지 확인해 보겠습니다.
- 원본 행렬로의 복원은 이 U, Sigma, Vr 를 내적하면 됩니다. 한 가지 유의할 것은 Sigma 의 경우 0 이 아닌 값만 1 차원으로 추출했으므로 다시 0 을 포함한 대칭행렬로 변환한 뒤에 내적을 수행해야 한다는 점임
Sigmamat = np.diag(Sigma)
a = np.dot(np.dot(U, Sigmamat), Vt)
print(np.round(a, 3))
- a 행렬의 3번째 행을 '1행 + 2행'으로, 4번째 행을 1행과 같게 설정
- 로우 간 의존성 부여
- SVD 수행 시 Sigma 값 중 일부가 0 또는 0에 가까운 값으로 변함 --> 축소 가능
a[2] = a[0] + a[1]
a[3] = a[0]
print(np.round(a, 3))

- 이제 a 행렬은 이전과 다르게 로우 간 관계가 매우 높아졌습니다. 이 데이터를 SVD 로 다시 분해해 보
겠습니다.
U, Sigma, Vt = svd (a)
print(U.shape, Sigma.shape, Vt.shape)
print('Sigma Value: \n', np.round (Sigma, 3))

- 행렬의 Sigma 값 중 2개가 0으로 변함 → 행렬의 랭크(Rank)는 2
- 선형 독립인 행 벡터는 2개만 있음
- 복원 시 Sigma의 0이 아닌 앞의 2개 요소만 사용
- U 행렬은 선행 2개 열만, Vt 행렬은 선행 2개 행만 사용
- 이렇게 부분적으로 복원해도 원본과 유사한 행렬 생성 가능
#U 행렬의 경우는 Sigma 와 내적을 수행하므로 Sigma 의 앞 2 행에 대응되는 앞 2 열만 추출
U= U[:, :2]
Sigma = np.diag(Sigma[:2])
#V 전치 행렬의 경우는 앞 2 행만 추출
Vt = Vt[:2]
print(U. shape, Sigma.shape, Vt.shape)
a = np .dot(np.dot(U, Sigma), Vt)
print(np.round (a_, 3))

- Truncated SVD는 특이값(Sigma)의 상위 일부만 추출해 행렬을 저차원으로 분해
- 원본 행렬을 정확히 복원할 수는 없지만, 높은 수준의 근사 가능
- 차원이 원래 차원에 가까울수록 복원 정확도 향상
- Truncated SVD는 scipy의 scipy.sparse.linalg.svds에서 지원
- 일반 SVD는 scipy.linalg.svd 사용 가능
- Truncated SVD는 주로 희소 행렬(sparse matrix)에 적용됨
임의의 원본 행렬 6 X 6 을 Normal SVD 로 분해해 분해된 행렬의 차원과 Sigma 행렬 내의 특이값을 확인한 뒤 다시 Truncated SVD 로 분해해 분해된 행렬의 차원 , Sigma 행렬 내의 특이값 , 그리고 Truncated SVD 로 분해된 행렬의 내적을 계산하여 다시 복원된 데이터와 원본 데이터를 비교해 보겠습니다.
import numpy as np
from scipy.sparse.linalg import svds
from scipy.linalg import svd
np.random.seed(121)
matrix = np.random.random((6, 6))
print('원본 행렬:\n', matrix)
U, Sigma, Vt = svd(matrix, full_matrices=False)
print('\n분해 행렬 차원 :', U.shape, Sigma.shape, Vt.shape)
print('\nsigma값 행 렬 :', Sigma)
num_components = 4
U_tr, Sigma_tr, Vt_tr = svds(matrix, k=num_components)
print('\n Truncate SVD분해 행렬 차원', U_tr.shape, Sigma_tr.shape, Vt_tr.shape)
print('\nTruncated SVD Sigma값 행렬:' , Sigma_tr)
matrix_tr = np.dot(np.dot(U_tr, np.diag(Sigma_tr)), Vt_tr) # output of TruncatedSVD
print('\nTruncated SVD 로 분해 후 복원 행렬 :\n', matrix_tr)

- 6 X 6 행렬을 SVD 분해하면 U, Sigma, Vt 가 각각 (6, 6) (6,) (6, 6) 차원이지만, - Truncated SVD 의 n_components 를 4 로 설정해 U, Sigma, Vt 를 (6, 4) (4,) (4, 6) 로 각각 분해했음
- Truncated SVD 로 분해된 행렬로 다시 복원할 경우 완벽하게 복원되지 않고 근사적으로 복원됨
## 사이킷런 TruncatedSVD 클래스를 이용한 변환
- 사이킷런의 TruncatedSVD 클래스는 PCA와 유사하게 작동
- fit()과 transform()을 사용해 원본 데이터를 저차원 주요 컴포넌트로 변환
- Truncated SVD 연산을 통해 U × Sigma 형태로 선형 변환
- 사이파이 svds처럼 U, Sigma, Vt 행렬을 직접 반환하지 않음
- 주로 차원 축소 및 희소 행렬 처리에 사용됨
from sklearn. decomposition import TruncatedSVD, PCA
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
%matplotlib inline
iris = load_iris()
iris_ftrs = iris.data
tsvd = TruncatedSVD(n_components=2)
tsvd.fit(iris_ftrs)
iris_tsvd = tsvd.transform(iris_ftrs)
plt.scatter(x=iris_tsvd[:, 0], y= iris_tsvd[:, 1], c= iris.target)
plt.xlabel ('TruncatedSVD Component 1')
plt.ylabel('TruncatedSVD Component 2')

- 왼쪽 그림: TruncatedSVD로 변환된 붓꽃 데이터 세트
- 오른쪽 그림: PCA로 변환된 데이터 세트
- TruncatedSVD도 PCA처럼 차원 축소 후 품종별 클러스터링이 가능함
- 변환된 속성들이 높은 분류 고유성을 유지함
사이킷런의 TruncatedSVD와 PCA 클래스 구현을 조금 더 자세히 들여다보면 두 개 클래스 모두 SVD 를 이용해 행렬을 분해합니다.
붓꽃 데이터를 스케일링으로 변환한 뒤에 TruncatedSVD와 PCA 클래스 변환을 해보면 두 개가 거의 동일함
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
iris_scaled = scaler.fit_transform(iris_ftrs)
tsvd = TruncatedSVD(n_components=2)
tsvd.fit(iris_scaled)
iris_tsvd = tsvd. transform(iris_scaled)
pca = PCA(n_components=2)
pca.fit(iris_scaled)
iris_pca = pca. transform(iris_scaled)
fig, (ax1, ax2) = plt.subplots(figsize=(9, 4), ncols=2)
ax1.scatter(x=iris_tsvd[:, 0], y= iris_tsvd[:, 1], c= iris.target)
ax2.scatter(x=iris_pca[:, 0], y= iris_pca[:, 1], c= iris. target)
ax1.set_title('Truncated SVD Transformed')
ax2.set_title('PCA Transformed')

- 두 개의 변환 행렬 값과 원복 속성별 컴포넌트 비율값을 실제로 서로 비교해 보면 거의 똑같음
print((irispca - iris_tsvd).mean())
print((pca.components-tsvd.components_).mean())
- 모든 변환 결과 값이 0에 가까워 PCA와 SVD가 동일한 변환을 수행함
- 이는 PCA가 SVD 알고리즘을 기반으로 구현되었음을 의미
- 단, PCA는 밀집 행렬만 처리 가능 / SVD는 희소 행렬도 처리 가능
- SVD는 이미지 압축, 신호 처리, 패턴 인식 등 컴퓨터 비전 분야에서 활용
- 또한 SVD는 LSA (Latent Semantic Analysis) 기반 알고리즘으로 텍스트 토픽 모델링에 사용됨
# 5. NMF(Non-Negative Matrix Factorization)
## NMF 개요
- NMF 는 Truncated SVD 와 같이 낮은 랭크를 통한 행렬 근사(Low-Rank Approximation) 방식의 변형
- NMF 는 원본 행렬 내의 모든 원소 값이 모두 양수 (0 이상 ) 라는 게 보장되면 다음과 같이 좀 더 간단하게 두 개의 기반 양수 행렬로 분해될 수 있는 기법을 지칭

- 4 X 6 원본 행렬 V 는 4 X 2 행렬 W 와 2 X 6 행렬 H 로 근사해 분해될 수 있습니다.
= 행렬 분해 (Matrix Factorization) 는 일반적으로 SVD 와 같은 행렬 분해 기법을 통칭하는 것입니다.
- 이처럼 행렬 분해를 하게 되면 W 행렬과 H 행렬은 일반적으로 길고 가는 행렬 W(즉 , 원본 행렬의 행 크기와 같고 열 크기보다 작은 행렬) 와 작고 넓은 행렬 H(원본 행렬의 행 크기보다 작고 열 크기와 같은 행렬) 로 분해됩니다.
- 이렇게 분해된 행렬은 잠재 요소를 특성으로 가지게 됩니다.
- 분해 행렬 W 는 원본 행에 대해서 이
잠재 요소의 값이 얼마나 되는지에 대응하며 , 분해 행렬 H 는 이 잠재 요소가 원본 열 ( 즉 , 원본 속성)로 어떻게 구성됐는지를 나타내는 행렬입니다.

- NMF 는 SVD 와 유사하게 차원 축소를 통한 잠재 요소 도출로 이미지 변환 및 압축 , 텍스트의 토픽 도술 등의 영역에서 사용되고 있습니다.
- 사이킷런에서 NMF 는 NMF 클래스를 이용해 지원됩니다.
- 붓꽃 데이터를 NMF 를 이용해 2 개의 컴포넌트로 변환하고 시각화해 보겠습니다.
- NMF 도 SVD 와 유사하게 이미지 압축을 통한 패턴 인식 , 텍스트의 토픽 모델링 기법 , 문서 유사도 및 클러스터링에 잘 사용됨
- 또한 영화 추천과 같은 추천 (Recommendations) 영역에 활발하게 적용
됩니다.
- 사용자의 상품 ( 예 : 영화 ) 평가 데이터 세트인 사용자-평가 순위(user-Rating) 데이터 세트를
행렬 분해 기법을 통해 분해하면서 사용자가 평가하지 않은 상품에 대한 잠재적인 요소를 추출해 이를
통해 평가 순위 (Rating) 를 예측하고 , 높은 순위로 예측된 상품을 추천해주는 방식입니다 ( 이를 잠재 요소 (Latent Factoring) 기반의 추천 방식이라고 합니다).
# 6. 정리
- PCA, LDA, SVD, NMF는 대표적인 차원 축소 알고리즘이다.
- 차원 축소의 목적은 단순히 피처 수를 줄이는 것뿐 아니라, 데이터를 설명하는 잠재 요인 추출이다.
- 고차원 이미지나 텍스트 데이터를 이해하고 시각화하는 데 매우 유용하다.
**각 기법의 특징:**
- PCA: 데이터의 분산이 가장 큰 축을 기준으로 직각 축을 찾아 데이터를 투영함 (공분산 행렬 → 고유벡터 사용).
- LDA: 데이터의 클래스 간 분리를 극대화하는 축을 찾는 방식 (PCA와 유사하지만 목적이 다름).
- SVD: 고차원 행렬을 두 개의 저차원 행렬로 분해하는 방식, 잠재 요인 추출에 효과적.
- NMF: 음수가 아닌 행렬 분해 방식으로, 특히 추천 시스템과 토픽 모델링에서 활용됨.