Data Reduction이란 다루고자 하는 데이터 셋에 대해 마이닝 결과는 유지하면서 크기를 줄이는 방법이다. 실제 데이터 셋에는 불필요한 정보들도 많이 포함되어 있을 뿐더러, 이미 가지고 있는 값을 중복해서 가지고 있는 경우도 비일비재하다. 또한, 유사한 의미를 가지고 있어 합칠 수 있지만 원본 데이터에는 여러 개의 attribute로 나뉘어져 있는 경우도 존재한다. 물론 데이터가 많으면 많을수록 데이터 분석의 질은 향상되겠지만, 그만큼 많은 시간이 소요된다. 따라서 데이터 분석의 질은 유지하되, 어느 정도 가볍게 만들어 주는 과정이 필요하다. Data Reduction 과정은 크게 Feature Extraction과 Feature Selection 두 가지 방법으로 나뉘는데 이번 포스트에서는 'Feature Extraction' 방법에 대해 정리해보고자 한다.
❓ 참고
차원이 커질 수록 발생하는 문제는?
차원 축소를 하는 이유는?
차원의 저주(The Curse of Dimensionality)
👉 기존 특성(feature)들의 조합으로 유용한 feature들을 새롭게 생성하는 과정
👉 특성(feature)들 사이에 내재한 특성이나 관계를 분석하여 이들을 잘 표현할 수 있는 새로운 선형 혹은 비선형 결합 변수를 만들어 데이터를 줄이는 방법
👉 고차원의 원본 feature 공간을 저차원의 새로운 feature 공간으로 투영
⭐ 장점
🔥 단점
👉 가장 대표적인 차원(변수, feature) 축소 기법 중 하나
👉 고차원의 원본 데이터를 저차원의 부분 공간으로 투영하여 데이터를 축소시키는 기법
👉 기존 데이터의 분산(variance)을 최대한 보존하는 새로운 축을 찾아, 고차원 공간의 표본들을 선형 연관성이 없는 저차원 공간으로 변환하는 기법
👉 기존의 변수를 조합하여 만들어진, 서로 연관성이 없는 새로운 변수
👉 전체 데이터(독립변수들)의 분산을 가장 잘 설명하는 성분
👉 데이터를 투영하였을 때 가장 높은 분산을 가지는 데이터의 축에 해당
❗ 투영했을 때 분산이 크다는 것은 원래 데이터의 분포를 잘 설명할 수 있다는 것을 뜻하고 정보의 손실을 최소화 할 수 있다는 것을 의미
📌 왜 PCA를 사용하는가?
🧩 위 그림의 왼쪽 2차원 데이터를 오른쪽 1차원 데이터로 축소한다고 생각해보자
- 독립변수의 축으로 축소 결과, 기존 2차원일 때는 거리를 두고 위치하던 데이터들이 차원이 축소되면서 겹치게 되는 문제가 발생
- 이는 기존의 데이터가 가지고 있던 정보의 손실이 발생한 것으로 볼 수 있음
- 즉, 2차원 데이터의 특징을 모두 살리면서 1차원으로 변환이 어려움
🧩 위 그림은 PCA(주성분분석) 기법을 통해 데이터 축소를 실시한 결과
- 데이터를 하나의 독립변수의 축으로 사영하였을 때 발생했던 문제가 나타나지 않음
- 새롭게 찾은 '주성분1(PC1)' 축에 데이터를 사영시켰을 때, 데이터의 원래 분포가 잘 설명됨을 위 그림을 통해 확인 가능
- 즉, 기존 데이터의 정보 손실을 최소화하여 1차원으로의 데이터 축소가 가능
🧩 사람들의 키와 몸무게에 대한 정보가 담겨있는 아래 2차원 데이터를 1차원으로 축소한다고 생각해보자
📌 Scree Plot
- PCA 실시 후, 주성분의 수를 결정하기 위해 활용하는 Plot
- x축은 주성분, y축은 해당 주성분의 고유값(Eigenvalue)을 의미
- 일반적으로 그래프가 완만해지는 지점까지의 주성분을 활용
🧩 원리를 쉽게 이해하기 위해 2차원 데이터를 1차원으로 축소하는 과정을 예시로 들었으나 실제 고차원의 데이터를 축소하는 과정은 다음과 같음
from sklearn import datasets
from sklearn.decomposition import PCA
iris = datasets.load_iris() # 예시 데이터 셋으로 iris 사용
X = iris.data
y = iris.target
pca = PCA(n_components=4)
pca_fitted = pca.fit(X) # PCA는 Unsupervised Learning Algorithm
print(f'{pca_fitted.components_ = }') # 각 고유벡터(Eigenvector)의 x, y축 성분
print(f'{pca_fitted.explained_variance_ratio_ = }') # 각 고유 벡터가 설명할 수 있는 분산 비율(기여율)
X_pca = pca_fitted.transform(X) # 주성분 벡터로 데이터를 변환
# result
pca_fitted.components_ = array([[ 0.36138659, -0.08452251, 0.85667061, 0.3582892 ],
[ 0.65658877, 0.73016143, -0.17337266, -0.07548102],
[-0.58202985, 0.59791083, 0.07623608, 0.54583143],
[-0.31548719, 0.3197231 , 0.47983899, -0.75365743]])
pca_fitted.explained_variance_ratio_ = array([0.92461872, 0.05306648, 0.01710261, 0.00521218])
import numpy as np
import matplotlib.pyplot as plt
def scree_plot(pca):
num_components = len(pca.explained_variance_ratio_)
ind = np.arange(num_components)
vals = pca.explained_variance_ratio_
ax = plt.subplot()
cumvals = np.cumsum(vals)
ax.bar(ind, vals, color = ['g', 'y', 'm', 'b']) # Eigenvalue bar plot
ax.plot(ind, cumvals, color = 'r') # Cumulative line plot
for i in range(num_components):
ax.annotate(r"%s" % ((str(vals[i]*100)[:3])), (ind[i], vals[i]), va = "bottom", ha = "center", fontsize = 13)
ax.set_xlabel("PC")
ax.set_ylabel("Variance")
plt.title('Scree Plot')
scree_plot(pca)
# result
📌 위 Scree Plot을 토대로 차원 축소의 방향을 둘 중 하나로 결정 가능
1) 4차원에서 1차원으로 차원 축소, 기여율 92%
2) 4차원에서 2차원으로 차원 축소, 기여율 97.3%
이는 주어진 문제 상황에 따라 적절한 방법을 선택하여 실시하면 됨!
import pandas as pd
import seaborn as sns
pca_r = PCA(n_components=2)
pca_r_fitted = pca_r.fit(X)
X_pca_r = pca_r_fitted.transform(X)
df_pca_r = pd.DataFrame(X_pca_r, columns=['PC1', 'PC2'])
y = pd.Series(y).replace({0:'setosa', 1:'versicolor', 2:'virginica'})
sns.scatterplot(df_pca_r, x='PC1', y='PC2', hue=y, style=y, palette='Set1').set(title='PCA of IRIS dataset');
# result
👉 분류(Classification) 모형을 통한 차원 축소 기법
👉 클래스 내부(within-class) 분산이 최소가 되는, 클래스 중심 간(between-class) 거리가 최대가 되는 벡터를 찾아 데이터를 투영하여 차원을 축소하는 기법
👉 데이터를 특정 한 축에 사영한 후 두 클래스(범주)를 잘 구분할 수 있는 직선을 찾는 것이 목적
👉 가능한 클래스 간의 분류 정보를 최대한 유지시키면서 차원을 축소시키기 위함
🧩 왼쪽과 오른쪽 축 중에 분류가 더 잘 되었다고 판단할 수 있는 축은?
🧩 그럼 두 클래스를 잘 구분할 수 있는 직선은 어떤 성질을 가져야 할까?
선형판별분석(LDA)는 이러한 직선을 찾도록 해주는 데이터 축소 알고리즘!
import pandas as pd
import seaborn as sns
from sklearn import datasets
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
iris = datasets.load_iris()
X = iris.data
y = iris.target
lda = LinearDiscriminantAnalysis(n_components=2) # 4차원에서 2차원으로 축소
lda_fitted = lda.fit(X, y) # LDA는 Supervised Learning Algorithm
print(f'{lda_fitted.coef_=}') # LDA의 고유벡터 성분
print(f'{lda_fitted.explained_variance_ratio_=}') # LDA의 분산에 대한 설명력(기여율)
X_lda = lda_fitted.transform(X)
df_lda = pd.DataFrame(X_lda, columns=['LD1', 'LD2'])
y = pd.Series(y).replace({0:'setosa', 1:'versicolor', 2:'virginica'})
sns.scatterplot(df_lda, x='LD1', y='LD2', hue=y, style=y, palette='Set1').set(title='LDA of IRIS dataset');
# result
lda_fitted.coef_=array([[ 6.31475846, 12.13931718, -16.94642465, -20.77005459],
[ -1.53119919, -4.37604348, 4.69566531, 3.06258539],
[ -4.78355927, -7.7632737 , 12.25075935, 17.7074692 ]])
lda_fitted.explained_variance_ratio_=array([0.9912126, 0.0087874])
👉 입력 데이터 세트를 저차원 공간에 투영해 차원을 축소하는 기법
✅ 주성분 분석(PCA)
✅ 선형판별 분석(LDA)
https://backenddeveloper.tistory.com/183
https://bioinformaticsandme.tistory.com/188
https://ssungkang.tistory.com/entry/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5-PCA-1-Principle-Component-Analysis-%EB%9E%80?category=324327
https://ddongwon.tistory.com/114