[혼자 공부하는 머신러닝+딥러닝] 16강. 주성분 분석: 차원 축소 알고리즘 PCA 모델 만들기 - 차원축소 PCA를 다른 알고리즘과 함께 사용하기
https://www.youtube.com/watch?v=ePqKgBnpcw4&list=PLJN246lAkhQjoU0C4v8FgtbjOIXxSs_4Q&index=23
1. 차원 축소
- 차원의 정의
- 데이터가 가진 속성을 특성이라 하고 머신러닝에서는 이 특성을 차원이라고 부른다.
- 예를 들어 이전 강의에서 사용한 과일 사진의 경우 1개의 샘플이 가로 100, 세로 100 크기의 특성을 가지고 있었으며 하나의 특성은 0~255 사이의 값을 가지고 있었다.
- 2차원 배열은 축이 2개이고 3차원 배월은 축이 3개가 있다 한다.
- 1차원 배열은 벡터라 볼 수 있고 벡터에 있는 원소의 개수를 차원이라 한다.
- 벡터에서 차원을 이야기할 경우 벡터에 있는 원소의 개수를 의미한다.
- 2차원 배열 이상에서 차원을 이야기할 경우 축을 의미한다.
- 차원 축소
- 비지도학습으로 데이터를 가장 잘 나타내는 일부 특성을 선택하여 전체 데이터의 크기를 줄여준다.
- 다른 알고리즘과 함께 사용되어 성능을 향상하는 방법을 제공한다.
- 특성 개수가 많아지면 과대적합되는 문제가 있는데 이를 막아줄 수 있다.
- 데이터 전체 용량을 줄여주며 이로인해 시각화 하기도 쉬워진다.
- 축소된 차원의 데이터를 이용해 원본 차원으로 복원할 수 있다.
- 누락된 데이터로 인해 손실된 이미지로 복원된다. 100% 완벽히 복원되지는 않는다.
- 대표적으로 주성분 분석(Principal Component Analysis)가 있다.
2. 주성분 분석
- 첫번째 주성분
- 일반적으로 데이터의 분산이 잘 되어 있는 그래프에서 분산이 가장 큰 방향을 찾게되면 아래와 같은 선형이 그려진다.
- 데이터를 가장 많이 퍼져있는 방향이 데이터를 가장 잘 표현할 수 있는 방향이 된다.
- 이 직선의 중심을 원점으로 이동하면 벡터로 표현하기 쉬워진다.
- 평균을 빼서 두 축의 원점에 맞추고 원점에서 시작하는 벡터를 찾아서 가장 잘 표현한 퍼펙트 벡터를 찾는다. 이것을 주성분이라 한다. 이 주성분을 찾는 것이 주성분 분석이다.
- 현재 특성은 X1, X2 두개이다. 하지만 주성분을 찾음으로 (2,1)이라는 하나의 특성으로 차원축소를 했다 할 수 있다.
- 만약 퍼펙트 벡터를 찾은 데이터 분산에서 특정 데이터를 표현하기 위해서는 (x,y) 2차원으로 표현할 수 있다. 하지만 퍼펙트 벡터로부터 수직 데이터를 확인하여 1개의 1차원 데이터로 표현할 수 있다.
- 두번째 주성분
- 주성분은 원본의 특성 개수만큼 찾을 수 있다.
- 처음 찾은 주성분으로 부터 수직이고 분산이 그 다음으로 큰 방향을 찾으면 된다.
- 꼭 수직이어야 하는 이유로 수직이 아닌 방향은 첫번째 주성분의 방향으로 부터 영향을 작게라도 받는다 첫번째 주성분이 표현하지 못하는 분산의 방향을 찾는게 목적이기 때문에 수직인 방향으로 찾는다.
3. PCA 클래스
- 주성분 분석
- PCA() : 주성분 분석 클래스
- n_components : 찾을 주성분의 개수 정의
from sklearn.decomposition import PCA
pca = PCA(n_components=50)
pca.fit(fruits_2d)
- 뽑아낸 주성분(pca)는 .components_에 저장되어 있다.
- 기존 과일 데이터에서 추출한 주성분이기 때문에 10000개의 특성이 있는 데이터에서 주성분을 찾은 것이다.
print(pca.components_.shape)
(50, 10000) # 찾은 주성분의 크기는 50개의 주성분과 10000개의 원소인 것을 확인할 수 있다.
- 찾은 주성분을 이미지로 출력하자
- 원본 데이터셋에서 특정 패턴들을 기준으로 만든 이미지들로 보인다.
draw_fruits(pca.components_.reshape(-1, 100, 100))
- 찾은 주성분을 기반으로 원본 데이터의 차원(특성 개수)를 줄일 수 있다.
- .transform() : 주성분으로 차원축소를 실행
print(fruits_2d.shape) # 원본 데이터
(300, 10000)
fruits_pca = pca.transform(fruits_2d)
print(fruits_pca.shape)
(300, 50)
- 원본 데이터로 복원
- 축소된 차원의 데이터를 이용해 다시 원본 데이터로 복원할 수 있다.
- 차원 축소를 하면서 손실된 데이터는 100% 복원이 안된다 때문에 어느정도 손실된 데이터로 복원된다.
- inverse_transform() : 주성분을 바탕으로 원본 데이터를 재구성해주는 메소드
fruits_inverse = pca.inverse_transform(fruits_pca)
print(fruits_inverse.shape)
(300, 10000)
- 복원된 데이터로 이미지 그리기
fruits_reconstruct = fruits_inverse.reshape(-1, 100, 100)
for start in [0, 100, 200]:
draw_fruits(fruits_reconstruct[start:start+100])
print("\n")
- 설명된 분산(explained variance)
- 주성분이 원본 데이터의 분산을 얼마나 잘 나타내고 있는지 기록한 값을 설명된 분산(explained variance)라 한다.
- .explained_variance_ratio_ : 각 주성분의 설명된 분산에 대한 비율이 저장되어 있다.
- 이 변수에 저장된 모든 값을 더하면 주성분이 설명하는 총 분산의 비율을 얻을 수 있다.
print(np.sum(pca.explained_variance_ratio_))
0.9215225564709381
- 변수의 데이터를 그래프로 그려보면 적절한 주성분의 개수를 쉽게 찾을 수 있다.
plt.plot(pca.explained_variance_ratio_)
- 그래프를 보면 처음 10개 정도의 주성분들이 대부분의 분산을 표현하고 있는 것을 확인할 수 있다.
4. 다른 알고리즘과 함께 사용하기
- 분류 알고리즘 (로지스틱 회귀)와 함께 사용하기
- 모델을 만들고 target 값을 설정해준다 (로지스틱 회귀는 target 값을 요구한다)
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
# 지도학습이기 때문에 임의로 타깃값을 만들어준다.
target = np.array([0] * 100 + [1] * 100 + [2] * 100)
- 원본 데이터로 훈련해서 검증해보자
from sklearn.model_selection import cross_validate
scores = cross_validate(lr, fruits_2d, target)
print(np.mean(scores['test_score']))
print(np.mean(scores['fit_time']))
0.9966666666666667
0.6615097999572754
- pca 차원축소한 데이터로 확인해보자
scores = cross_validate(lr, fruits_pca, target)
print(np.mean(scores['test_score']))
print(np.mean(scores['fit_time']))
1.0
0.010721206665039062
- 설명된 분산의 양을 미리 설정할 수 있다. 목표로 하는 분산의 양을 1 이하의 값으로 정의하면 %로 인지하여 해당 목표치만큼의 설명된 분산의 양을 기준으로 주성분 개수를 자동으로 구한다.
pca = PCA(n_components=0.5)
pca.fit(fruits_2d)
print(pca.n_components_)
2 # 50%의 분산의 양을 목표로 하였을 때 2개의 주성분 개수를 구할 수 있다.
fruits_pca = pca.transform(fruits_2d) # 실재 데이터에 반영하여 차원 축소
print(fruits_pca.shape)
(300, 2)
scores = cross_validate(lr, fruits_pca, target) #교차 검정
print(np.mean(scores['test_score']))
print(np.mean(scores['fit_time']))
0.9933333333333334
0.017629432678222656
- 군집 알고리즘 (k-평균)
- 비지도 학습이므로 target 값 없이 훈련한다.
from sklearn.cluster import KMeans
km = KMeans(n_clusters=3, random_state=42)
km.fit(fruits_pca)
print(np.unique(km.labels_, return_counts=True))
(array([0, 1, 2]), array([110, 99, 91], dtype=int64))
for label in range(0, 3):
draw_fruits(fruits[km.labels_ == label])
print("\n")
- 데이터 시각화
- 데이터를 차원축소하면서 얻을 수 있는 장점으로 "시각화"가 있다.
- 3개 이하의 차원으로 특성을 줄이면 화면에 시각화하기 쉽다.
- 2개의 특성으로 줄여놓은 fruits_pca를 클러스터 별로 산점도를 그려보면 3개 과일간 구분을 쉽게 할 수 있다.
- 파인애플에 근접한 사과 데이터들이 보인다. 때문에 학습 결과 중 몇개로 사과 이미지가 보였던 것이라 판단할 수 있다.
for label in range(0, 3):
data = fruits_pca[km.labels_ == label]
plt.scatter(data[:,0], data[:,1])
plt.legend(['apple', 'banana', 'pineapple'])
plt.show()
- reference :
https://seongyun-dev.tistory.com/4
댓글