이전 글에서 KMeans 클래스를 이용하여 각 과일들을 클러스터링 했다. 또한 최적의 K를 찾는 법을 클러스터 중심과 클러스터에 속한 샘플 사이의 거리인 이너셔의 변화를 통해 찾아냈다. 그렇게 업로드된 사진을 클러스터로 분류하여 폴더별로 저장했지만, 너무 많은 사진이 등록되어 저장 공간이 부족하다. 사진의 용량을 줄이는 법은 없을까?
차원과 차원 축소
지금까지 데이터가 가진 속성을 특성이라고 했다. 과일 사진에는 가로 100, 세로 100으로 총 10,000개의 픽셀이 있기 때문에 10,000개의 특성이 있다고 할 수 있다. 머신러닝에서는 이런 특성을 차원(dimenstion)이라고도 부른다. 그렇다면 10,000개의 특성은 10,000개의 차원이라고 할 수 있다. 이 차원을 줄일 수 있다면 저장 공간을 절약할 수 있을 것이다.
1차원 배열과 2차원 배열에서의 차원이라는 용어는 조금 다르게 사용된다. 다차원 배열(2차원 배열)에서의 차원은 배열의 축의 개수를 의미하지만, 1차원 배열, 즉 벡터일 경우에는 원소의 개수를 의미한다.
저장 공간을 줄이기 위해 비지도 학습 장업 중 하나인 차원 축소(dimensionality reduction) 알고리즘에 대해 알아보자.
이전에 특성이 많으면 선형 모델의 성능이 높아지고 훈련 데이터에 과대 적합된다는 것을 배웠다. 차원 축소는 데이터를 가장 잘 나타내는 일부 특성을 선택하여 데이터 크기를 줄이고 지도 학습 모델의 성능을 향상할 수 있는 방법이다.
가장 대표적인 차원 축소 알고리즘인 주성분 분석(Principal Component Analysis, PCA)에 대해 알아보자.
주성분 분석(Principal Component Analysis)
PCA는 데이터에 있는 분산이 큰 방향을 찾는 것이다. 분산이란 데이터가 널리 퍼져있는 정도인데, 분산이 큰 방향을 데이터로 잘 표현하는 벡터로 생각하면 된다.
x와 y 2개의 특성이 있다. 가장 데이터 분포를 잘 표현하는 방향은 빨간색 화살표일 것이다. 화살표의 방향이 오른쪽 위로 향하든 왼쪽 아래로 향하든 큰 의미는 없다. 위의 화살표가 원점을 지난다면 두 원소로 이루어진 벡터로 쓸 수 있을 것이다. ex) (2, 1)
위의 그림처럼 원점을 지난다면 (2, 1)처럼 쓸 수 있다. 실제로 사이킷런의 PCA 모델을 훈련하면 자동으로 특성마다 평균값을 빼서 원점에 맞춰주기 때문에 직접 데이터를 원점에 맞출 필요가 없다.
이 벡터를 주성분(Principal Component)이라고 부른다. 이 주성분 벡터는 원본 데이터에 있는 어떤 방향이다. 따라서 주성분 벡터의 원소 개수는 원본 데이터셋에 있는 특성 개수와 같다. 원본 데이터는 주성분을 사용해서 차원을 줄일 수 있다.
위의 샘플 데이터들을 주성분에 직각으로 투영하면 1차원 데이터를 만들 수 있다.
주성분은 원본 차원과 같고 주성분으로 바꾼 데이터는 차원이 줄어든다는 점을 꼭 기억하자.
주성분이 가장 분산이 큰 방향이기 때문에 주성분에 투영하여 바꾼 데이터는 원본이 가지고 있는 특성을 가장 잘 나타내고 있을 것이다.
첫 번째 주성분을 찾은 다음 이 벡터에 수직이고 분산이 가장 큰 다음 방향을 찾는다. 이 벡터가 두 번째 주성분이다. 여기서는 2차원이기 때문에 두 주성분의 방향은 두 번째 그림에서처럼 두 개뿐이다.
PCA 클래스
과일 사진 데이터를 다운로드하자.
n_components 변수에 주성분의 개수를 지정해야한다. 또한 비지도 학습이기 때문에 fit() 메서드에 타깃 값을 제공하지 않는다.
PCA 클래스가 찾은 주성분은 components_ 속성에 저장되어 있다. 배열의 크기를 확인해보자.
n_components=50으로 지정했기 때문에 pca.components_ 배열의 첫 번째 차원이 50이다. 두 번째 차원은 항상 원본 데이터의 특성 개수와 같은 10,000이다.
K-평균 알고리즘에서 만들었던 draw_fruits 함수를 사용해서 10개씩 사진을 나열해보자.
pca.components_의 shape은 (50, 10000)인데, draw_fruits함수는 3차원 배열을 입력받아야하기 때문에 (-1,100,100)으로 reshape 하여 건네줘야 한다.
이 주성분들은 원본 데이터에서 가장 분산이 큰 방향을 순서대로 나타낸 것이다.
주성분을 찾았기 때문에 원본 데이터를 주성분에 투영하여 특성의 개수를 10,000개에서 50개로 줄일 수 있다.
원본 데이터를 각 주성분으로 분해하는 것으로 생각할 수 있다. PCA의 transform() 메서드를 사용해 원본 데이터의 차원을 50으로 줄여보자.
fruits_2d는 10,000개의 픽셀을 가진 300개의 이미지였는데, transform()으로 변환한 결과 차원이 10,000개에서 50으로 줄었다. 차원을 줄인 이미지를 다시 원상 복구할 수 있다.
원본 데이터 재구성
10,000개에서 50개로 특성을 줄인 결과 어느 정도 손실이 발생할 수밖에 없다. 하지만 최대한 분산이 큰 방향으로 데이터를 투영했기 때문에 원본 데이터를 상당 부분 재구성할 수 있다.
PCA 클래스의 inverse_transform() 메서드로 복원해보자.
데이터의 크기를 100 X 100 크기로 바꾸어 100개씩 나누어 출력해보자.
만약 주성분을 최대로 사용했다면 완벽하게 원본 데이터를 재구성할 수 있었을 것이다. 50개의 특성은 얼마나 분산을 보존하고 있는지 알아보자.
설명된 분산
주성분이 원본 데이터의 분산을 얼마나 잘 나타내는지 기록한 값을 설명된 분산(explained variance)이라고 한다. PCA 클래스의 explained_varianve_ratio_에 각 주성분의 설명된 분산 비율이 기록되어있다. 첫 번째 주성분의 설명된 분산이 가장 클 것이다. 이 분산 비율을 모두 더하면 50개의 주성분으로 표현하고 있는 총 분산 비율을 얻을 수 있다.
92%가 넘는 분산을 유지하고 있다. 설명된 분산의 비율을 그래프로 그려보면 적절한 주성분의 개수를 찾는 데 도움이 된다. 맷플롯립의 plot() 함수로 설명된 분산을 그래프로 출력해보자.
처음 10개의 주성분이 대부분의 분산을 표현하고 있다. 그다음부터는 각 주성분이 설명하고 있는 분산은 비교적 작다. PCA로 축소된 데이터를 사용해서 지도 학습 모델을 훈련해보자.
다른 알고리즘과 함께 사용하기
과일 사진 원본 데이터와 PCA로 축소한 데이터를 지도 학습에 적용해보고 어떤 차이가 있는지 알아보자.
3개의 과일 사진을 분류해야 하므로 로지스틱 회귀 모델을 사용하자.
지도 학습 모델은 비지도 학습 모델과 달리 타깃 값이 있어야 한다. 사과를 0, 파인애플을 1, 바나나를 2로 설정하자.
파이썬에서는 리스트와 정수를 곱하면 리스트 안의 원소를 정수만큼 반복한다. 이를 이용하면 100개의 0, 100개의 1, 100개의 2로 이루어진 타깃 데이터를 쉽게 만들 수 있다.
원본 데이터 fruits_2d를 사용해보자.
교차 검증의 점수가 상당히 높다. 특성이 10,000개나 되기 때문에 300개의 샘플에서는 금방 과대 적합된 모델을 만들기 쉽다. cross_validate함수가 return 하는 딕셔너리에서 'fit_time' 항목에는 각 교차 검증 폴드의 훈련 시간이 기록되어 있다. 1.702초 정도 걸린 것을 알 수 있다.
PCA로 축소한 fruits_pca를 교차 검증해보자.
50개의 특성만 사용했는데도 정확도가 100%이고 훈련 시간은 0.02초이다. PCA로 훈련 데이터의 차원을 축소하면 저장 공간뿐만 아니라 머신러닝 모델의 훈련 속도도 높일 수 있다.
PCA 클래스를 사용할 때 n_components 변수에 주성분의 개수를 지정했다.
이 대신 원하는 설명된 분산의 비율을 입력할 수도 있다. PCA 클래스는 지정된 비율에 도달할 때까지 자동으로 주성분을 찾는다. 설명된 분산의 50%에 달하는 주성분을 찾도록 PCA 모델을 만들어보자.
2개의 특성만으로 원본 데이터에 있는 분산의 50%를 표현할 수 있다는 뜻이다.
이 모델로 원본 데이터를 변환해보자.
주성분이 2개이므로 변환된 데이터의 크기는 (300,2)이다.
2개의 특성만을 사용하고도 교차 검증의 결과가 좋은지 확인해보자.
max_iter를 증가하라는 경고가 뜨지만 교차 검증의 결과가 충분히 좋기 때문에 무시해도 된다.
K-평균 알고리즘으로 클러스터를 찾아보자.
fruits_pca로 찾은 클러스터는 각각 91개, 99개, 110개의 샘플을 포함하고 있다. KMeans가 찾은 레이블을 사용해 과일 이미지를 출력해보자.
파인애플 클러스터에 사과 몇 개가 섞여있다.
훈련 데이터의 차원을 줄이면 얻을 수 있는 또 하나의 장점은 시각화이다. 3개 이하로 차원을 줄이면 화면에 출력하기 비교적 쉽다. fruits_pca 데이터는 2개의 특성이 있기 때문에 2차원으로 표현할 수 있다. 앞에서 찾은 km.labels_를 사용해 클러스터별로 나누어 산점도를 그려 보자.
산점도를 보면 사과와 파인애플 클러스터의 경계가 가깝게 붙어 있다. 그래서 사과와 파인애플이 몇개가 혼동되었던 것 같다.
'AI > 머신 러닝(ML)' 카테고리의 다른 글
K-평균 알고리즘 (0) | 2021.08.28 |
---|---|
군집 알고리즘 (Clustering) (0) | 2021.08.24 |
트리의 앙상블 (0) | 2021.08.21 |
교차 검증과 그리드 서치(Cross Validation & Grid Search) (0) | 2021.08.18 |
결정 트리 (Decision Tree) (0) | 2021.08.16 |