차원축소
차원축소란 고차원의 데이터를 포함하는 핵심 정보와 패턴을 유지하면서 더 낮은 차원의 공간으로 표현하는 과정입니다.
이는 데이터 분석, 시각화 및 모델링을 용이하게 하며, 특히 고차원 데이터셋에서는 계산 효율성을 높이고, 과적합을 방지하는 데 도움이 됩니다.
또한, 차원 축소는 데이터의 중요한 특성을 보다 명확하게 드러내어, 더 효과적인 인사이트와 결론 도출에 기여합니다.
PCA(주성분 분석)는 고차원 데이터를 저차원으로 축소하여 데이터의 핵심 구조를 파악하고, 과적합을 방지하는 동시에 계산 효율성을 높이는 기법입니다.
이 방법은 데이터의 복잡성을 줄이고, 중요한 정보를 유지하는 데 도움을 줍니다.
1. 데이터 준비
import pandas as pd
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')
submission = pd.read_csv('sample_submission.csv')
# PCA를 수행할 때 ID와 타겟의 정보는 불필요하므로 제거
train = train.drop(['ID', 'Outcome'], axis = 1)
test = test.drop(['ID'], axis = 1)
display(train.head())
# 예시 이미지 파일을 넘파이 배열로 변환
original_image = Image.open('car.jpg')
image_array = np.array(original_image)
# 원본 이미지 확인
plt.figure(figsize=(8, 4))
plt.imshow(image_array)
plt.axis('off')
plt.show()
2. 이미지 차원 축소
1) 주어진 이미지 배열에서 R(빨간색), G(녹색), B(파란색) 채널을 분리합니다.
2) 분리된 각 채널(R, G, B)에 대해 주성분 분석(PCA)을 수행합니다.
3) PCA를 통해 변환된 각 채널 데이터를 원래의 데이터로 복원합니다.
4) 복원된 R, G, B 채널을 np.stack 함수를 사용해 하나의 이미지로 결합합니다.
5) 원본 이미지와 PCA를 통해 복원된 이미지를 시각화하여 비교합니다.
# RGB 채널 분리
r = image_array[:,:,0]
g = image_array[:,:,1]
b = image_array[:,:,2]
# 각 채널에 대해 PCA 수행
pca_R = PCA(n_components=0.8, svd_solver='full')
pca_G = PCA(n_components=0.8, svd_solver='full')
pca_B = PCA(n_components=0.8, svd_solver='full')
pca_R.fit(r)
pca_G.fit(g)
pca_B.fit(b)
R_transformed = pca_R.transform(r)
G_transformed = pca_G.transform(g)
B_transformed = pca_B.transform(b)
# 변환된 데이터로부터 각 채널 복원
R_restored = pca_R.inverse_transform(R_transformed)
G_restored = pca_G.inverse_transform(G_transformed)
B_restored = pca_B.inverse_transform(B_transformed)
# 복원된 채널을 결합하여 최종 이미지 생성
image_restored = np.stack((R_restored, G_restored, B_restored), axis=-1)
# 원본 이미지와 복원된 이미지 시각화 및 저장
fig, ax = plt.subplots(1, 2, figsize=(12, 6))
ax[0].imshow(image_array)
ax[0].set_title('Original Image')
ax[0].axis('off')
ax[1].imshow(image_restored.astype('uint8'))
ax[1].set_title('Restored Image')
ax[1].axis('off')
plt.show()
3. 데이터 전처리
PCA(주성분 분석) 는 고차원의 데이터를 저차원으로 축소하는 통계적 기법입니다.
이 방법은 데이터의 분산을 최대화하는 방향으로 새로운 축을 찾아, 데이터를 이 축에 투영합니다.
2차원일 때는 그림과 같이 첫 번째 주성분은 데이터가 가장 넓게 퍼져 있는 방향을 나타내며,
두 번째 주성분은 첫 번째 주성분에 직교하는 방향으로 설정됩니다.
3차원 이상일 때, 첫 번째 주성분은 여전히 가장 큰 분산을 나타내고,
두 번째 주성분은 첫 번째 주성분에 직교하는 방향 중 가장 큰 분산을 설명합니다.
추가적으로, 세 번째 주성분은 이전 두 주성분에 모두 직교하며 남은 분산을 포착합니다.
이렇게 함으로써 데이터의 주요 특성을 유지하면서 차원을 줄일 수 있고,
데이터의 복잡성을 감소시켜 계산 효율을 높입니다.
1) 장점
- 데이터의 중요한 특성을 유지하며 차원을 줄이고, 데이터셋의 복잡성을 감소시킵니다.
- 불필요한 변동성을 제거함으로써 데이터의 핵심 특성을 더 명확하게 드러냅니다.
- 저차원으로 변환된 데이터는 시각화와 해석이 용이합니다.
- 차원이 축소되면 데이터 처리와 분석이 더 빠르고 효율적으로 이루어질 수 있습니다.
2) 단점
- 주성분은 원본 변수들의 선형 결합으로 구성되므로 이들이 무엇을 의미하는지 해석하기 어려울 수 있습니다.
- 차원을 줄이는 과정에서 일부 정보가 손실될 수 있습니다.
- 모든 변수가 동일한 중요도를 가지고 있다고 가정하므로, 어떤 변수가 더 중요한지 구별하기 어렵습니다.
결측치가 있는 경우, 데이터의 분산을 올바르게 파악할 수 없습니다.
결측치가 포함된 데이터를 사용하여 PCA를 수행하면, 주성분이 잘못 계산될 수 있습니다.
또한, PCA를 수행할 때 데이터의 각 특성이 서로 다른 스케일을 가질 경우, 스케일이 큰 특성이 결과에 더 큰 영향을 미치게 됩니다.
예를 들어, 한 특성의 값이 수천 단위이고 다른 특성의 값이 소수점 단위인 경우, 전자의 특성이 주성분을 결정하는 데 지나치게 큰 영향을 미칠 수 있습니다.
PCA 전에 스케일링을 수행하는 것은 또 다른 중요한 이점을 가집니다.
스케일링 과정에서 각 특성의 평균을 0으로 조정하기 때문에,
PCA를 수행할 때 별도로 전체 데이터에서 평균을 빼는 과정을 거치지 않아도 됩니다.
일반적으로 PCA를 수행하기 전에는 데이터를 중심화하기 위해 각 특성에서 평균을 빼는 단계가 필요하지만,
스케일링 과정에서 이미 이 작업이 수행되기 때문에 추가적인 중심화 과정이 필요 없게 됩니다.
결론적으로, PCA 전에 결측치 처리와 스케일링을 수행함으로써 더 정확한 주성분 분석 결과를 얻을 수 있고,
평균을 빼는 단계를 생략할 수 있습니다.
PCA 적용 전 데이터 전처리 : 아래코드에서는 0의 값을 결측값으로 간주하고, 각 열의 평균값(0이 아닌 값들의 평균)으로 대체합니다.
from sklearn.preprocessing import StandardScaler
columns_to_replace = ['Pregnancies', 'Glucose', 'BloodPressure',
'SkinThickness', 'Insulin', 'BMI']
for col in columns_to_replace:
mean_val = train[col].replace(0, np.nan).mean()
train[col] = train[col].replace(0, mean_val)
test[col] = test[col].replace(0, mean_val)
# 데이터에 대한 표준화 : 평균을 0, 표준편차를 1로 조정
scaler = StandardScaler()
scaled_train = scaler.fit_transform(train)
scaled_test = scaler.transform(test)
4. PCA 구현 (1) : 특잇값 분해
PCA를 수행하는 데에는 주로 두 가지 방법이 있습니다.
고유값 및 고유벡터를 사용하는 방법과 Singular Value Decomposition(SVD)을 사용하는 방법입니다.
여기서 SVD 방법을 선택하여 PCA를 구현하는데, 이유는 다음과 같습니다.
- SVD는 고유값 분해에 비해 수치적으로 더 안정적입니다.
특히 고차원 데이터나 특이값이 매우 작은 경우에 이점이 있습니다. - SVD는 고차원 데이터에 대해서도 효율적으로 작동하며,
분산이 낮은 주성분을 빠르게 제거할 수 있습니다.
위의 수식에서 A는 우리가 분해하고자 하는 원본 데이터를 나타내는 행렬입니다.
이 행렬은 분석하고자 하는 실제 데이터를 수학적 형태로 표현한 것으로,
이번에는 scaled_train 데이터에 해당합니다.
SVD를 사용한 PCA에서는 Vt 만 주성분 분석에 사용됩니다.
Vt의 경우 원본 데이터의 특성(열)에 대한 정보를 담고 있는 오른쪽 특이 벡터들의 전치 행렬입니다.
각 행은 원본 데이터의 특성들의 선형 결합으로 이루어진 새로운 축(주성분)을 나타내며, 이는 데이터의 중요한 변동성을 포착합니다.
U와 S는 PCA에서 주성분을 추출하는 데 직접적으로 사용되지 않습니다.
U는 데이터의 행과 관련된 변환을 나타내고, S는 분산의 크기를 나타내지만, 주성분을 결정하는 데에는 Vt가 핵심적인 역할을 합니다.
따라서 Vt 만이 주성분 분석에 사용됩니다.
U, S, Vt = np.linalg.svd(scaled_train, full_matrices=False)
print(f'Vt의 shape는 {Vt.shape} 입니다.')
Vt
Vt의 shape는 (8, 8) 입니다.
array([[ 0.33763674, 0.40915059, 0.38147446, 0.39324298, 0.31804902,
0.39927867, 0.12933795, 0.37566938],
[-0.52360341, 0.17892869, -0.2300383 , 0.26500951, 0.32538613,
0.33972527, 0.30146 , -0.50843761],
[ 0.01783315, 0.40369853, -0.24133254, -0.43622946, 0.48870984,
-0.45355327, 0.31911012, 0.20443287],
[-0.18513954, 0.29224054, 0.08055414, -0.05062238, 0.3258857 ,
-0.04822905, -0.86678028, -0.10691885],
[ 0.38040207, -0.16856318, -0.77365708, 0.38780891, 0.17548477,
0.01733519, -0.18205751, 0.11704418],
[-0.4352109 , 0.41732565, -0.15311242, 0.40878414, -0.4655017 ,
-0.29600482, -0.00938464, 0.37614377],
[-0.35115769, -0.57628036, 0.24129275, 0.30758684, 0.44765247,
-0.30576803, 0.03210187, 0.31119127],
[-0.34615062, -0.13240085, -0.23794614, -0.41250607, -0.0071003 ,
0.57940765, -0.07064489, 0.54324561]])
5. PCA 구현 (2) : 주성분 선택
Vt는 SVD(특잇값 분해)를 통해 얻은 오른쪽 특이 벡터들의 전치 행렬로,
원본 데이터의 특성(열)에 대한 정보를 담고 있습니다.
이 행렬의 각 행은 원본 데이터의 특성들을 새로운 축(주성분)으로 변환하는 역할을 합니다.
코드에서는 데이터의 가장 중요한 정보를 포착하는 상위 3개의 주성분을 선택하고 있습니다.
이 주성분들은 데이터의 분산을 최대화하는 방향으로 정렬되어 있으며,
이를 통해 데이터의 차원을 축소하면서도 중요한 정보를 유지할 수 있습니다.
선택된 주성분(components_train)은 이후 데이터를 이 새로운 축에 투영하는 데 사용됩니다.
이는 고차원 데이터를 저차원으로 효과적으로 축소하면서도 데이터의 핵심적인 변동성을 유지할 수 있게 해줍니다.
주성분 분석(PCA)을 통해 차원 축소를 수행할 때, VT 행렬의 크기를 확인한 결과 (8,8)임을 확인했습니다.
이 중에서 차원을 축소하기 위해 주성분의 개수(n_components)를 3으로 설정했고,
결과적으로, 선택된 주성분을 나타내는 components_train의 크기는 (3,8)이 되었습니다.
이는 원본 VT 행렬에서 가장 중요한 세 개의 주성분을 추출한 것입니다.
# 주성분 개수 설정
n_components = 3
# n_components에 해당하는 주성분만 선택
components_train = Vt[:n_components]
components_train.shape
(3, 8)
6. PCA 구현 (3) : 데이터 투영
이 코드는 주성분 분석(PCA)의 핵심 단계인 데이터의 주성분 투영을 다룹니다.
여기서는 표준화된 학습 데이터(scaled_train)와 테스트 데이터(scaled_test)를 앞서 선택한 주성분(components_train)에 투영합니다.
scaled_train은 표준화된 학습 데이터를 나타내며, components_train.T는 선택된 주성분의 전치 행렬을 의미합니다.
데이터를 주성분에 투영하기 위해, 각 데이터 포인트를 주성분의 방향으로 투영합니다.
이는 데이터의 차원을 축소하고, 주성분이 포착하는 변동성을 기반으로 데이터를 재구성합니다.
이 과정에서 데이터의 shape는 주성분의 개수(n_components)만큼의 새로운 차원으로 변형됩니다.
scaled_train이 652개의 샘플과 8개의 특성을 가진 데이터이므로,
pca_train은 652개의 샘플과 3개의 새로운 주성분 특성을 가진 데이터가 됩니다.
이는 PCA를 통해 원본 데이터셋의 8개 특성이 주성분 분석을 거쳐 3개의 주요 차원으로 변환되었음을 나타냅니다.
이렇게 차원이 축소된 데이터셋은 원본 데이터의 중요한 정보를 보존하면서도 훨씬 적은 수의 특성으로 표현됩니다.
이는 데이터 분석 및 모델 학습에서 계산 효율성을 높이고, 고차원 데이터셋의 복잡성을 줄이는 데 도움이 됩니다.
# 학습 데이터를 주성분에 투영
pca_train = np.dot(scaled_train, components_train.T)
# 테스트 데이터를 주성분에 투영
pca_test = np.dot(scaled_test, components_train.T)
print(f'pca가 완료된 train 데이터의 shape는 {pca_train.shape} 입니다.')
pca가 완료된 train 데이터의 shape는 (652, 3) 입니다.
7. 사이킷런을 활용한 정형데이터 PCA
사이킷런의 PCA 클래스는 데이터의 차원 축소 과정을 간편하고 효율적으로 수행할 수 있게 해줍니다.
이 도구를 사용함으로써 복잡한 계산 없이도 주성분 분석을 쉽게 구현할 수 있습니다.
이 과정의 결과로, 원본 데이터셋의 핵심 정보는 유지되면서도 데이터는 더 낮은 차원의 형태로 축소됩니다.
이렇게 축소된 데이터는 원본 데이터의 중요한 변동성을 포착하면서도, 더 간결하고 관리하기 쉬운 형태로 변환됩니다.
직접 구현한 PCA와 유사한 결과를 제공하면서도,
사용의 용이성 측면에서 더욱 효과적인 접근법입니다.
from sklearn.decomposition import PCA
pca = PCA(n_components = 3)
'''n_components: 유지하려는 주성분의 수나 유지하려는 분산의 비율을 지정합니다.
0.8과 같은 실수로 설정할 경우 데이터의 80%를 설명하는 개수를 자동으로 지정하며,
3과 같은 정수로 설정할 경우 전체 주성분중 3개를 가져옵니다.'''
pca.fit(scaled_train)
train_pca = pca.transform(scaled_train)
test_pca = pca.transform(scaled_test)
display(pd.DataFrame(train_pca))
print(f'각 주성분의 설명 비율은 {pca.explained_variance_ratio_} 입니다.')
'머신러닝 > 머신러닝: 심화 내용' 카테고리의 다른 글
피처 생성(Feature Generation) 1 : Binning 기법 (0) | 2024.12.23 |
---|---|
분류 모델 하이퍼파라미터 튜닝 (0) | 2024.12.22 |
회귀 모델 하이퍼파라미터 튜닝 (0) | 2024.12.20 |
교차검증 (1) | 2024.12.19 |
차원 축소 기법 : LDA (1) | 2024.12.18 |