비지도 학습 (1) - 주성분 분석(Principal Component Analysis, PCA)
주성분 분석(Principal Component Analysis, PCA)
주성분 분석은 상관된 변수의 집합을 가능한 한 상관되지 않는 변수의 집합으로 변환하는 직교 선형 변환이다. 주성분 분석은 데이터를 한개의 축으로 사상시켰을 때 그 분산이 가장 커지는 축을 첫 번째 주성분, 두 번째로 커지는 축을 두 번째 주성분으로 놓이도록 새로운 좌표계로 데이터를 선형 변환한다. 이와 같이 표본의 차이를 가장 잘 나타내는 성분들로 분해함으로써 여러가지 응용이 가능하다. 이 변환은 첫째 주성분이 가장 큰 분산을 가지고, 이후의 주성분들은 이전의 주성분들과 직교한다는 제약 아래에 가장 큰 분산을 갖고 있다는 식으로 정의되어있다. 중요한 성분들은 공분산 행렬의 고유 벡터이기 때문에 직교하게 된다.
기계학습에서 PCA는 가능한 한 분산을 그대로 유지하며 고차원에서 자차원으로 축소할 수 있도록 한다. 변환하는데 목적범주가 필요하지 않고 학습 속성의 값만 의존하기 때문에 비지도 학습이다. 시각화와 속성 선택에 유용하다.
본 포스팅에서 작업할 예제는 각 인스턴스가 64개의 속성으로 구성된 8*8 픽셀 매트릭스로 디지털화된 손글씨 숫자 데이터셋이다. 한 번에 64차원을 가시화하는 것은 불가능하다. 그래서 PCA를 통해서 인스턴스를 2차원으로 줄이고 산점도로 분포를 시각화한다.
먼저 데이터를 로드한다.
1 2 3 | from sklearn.datasets import load_digits digits = load_digits() X_digits, y_digits = digits.data, digits.target | cs |
digits 속성 이름을 출력한다.
1 2 3 | >>> print digits.keys() ['images', 'data', 'target_names', 'DESCR', 'target'] |
인스턴스에 해당하는 숫자번호인 target 벡터와 64개의 속성의 인스턴스를 포함한 data 매트릭스를 사용한다. digits 출력을 통해 인스턴스가 나타나는 모습을 살펴보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | >>> %matplotlib inline >>> >>> import matplotlib.pyplot as plt >>> n_row, n_col = 2, 5 >>> >>> def print_digits(images, y, max_n=10): >>> fig = plt.figure(figsize=(2. * n_col, 2.26 * n_row)) >>> i=0 >>> while i < max_n and i < images.shape[0]: >>> p = fig.add_subplot(n_row, n_col, i + 1, xticks=[], yticks=[]) >>> p.imshow(images[i], cmap=plt.cm.bone, interpolation='nearest') >>> p.text(0, -1, str(y[i])) >>> i = i + 1 >>> >>> print_digits(digits.images, digits.target, max_n=10) | cs |
- figsize : 폭과 너비의 튜플로 단위는 인치이다.
add_subplot() : 예를 들어, add_subplot(2, 3, 4)는 2행 3열의 그리드에서 4번째 subplot 이라는 의미다.
imshow(interpolation='nearest') : interpolation 메소드 중의 하나로 라는 것은 화면의 해상도가 이미지의 해상도와 일치하지 않을 때 처리 방식에 대한 것이다. 메소드별 차이는 아래 링크 참조.
smoothing between pixels of imagesc\imshow in matlab like the matplotlib imshow http://stackoverflow.com/questions/14722540/smoothing-between-pixels-of-imagesc-imshow-in-matlab-like-the-matplotlib-imshow
c13 = plt.scatter(theta, r, c=colors, s=area, cmap=plt.cm.bone)
text(x, y, s, fontsize=12) : 축을 중심으로 텍스트를 넣는다. 0, 0 은 하단 좌측, 그리고 1, 1은 상단 우측을 나타낸다.
matplotlib basic text commands http://matplotlib.org/users/text_intro.html
Putting text in top left corner of matplotlib plot http://stackoverflow.com/questions/8482588/putting-text-in-top-left-corner-of-matplotlib-plot
출력 결과는 다음과 같다.
PCA 변환으로 얻어진 2차원 점을 산점도에 그리는 함수를 정의한다. 데이터점은 범주에 따라 색이 다르며 목적 범주까지는 반환하지 않는다. PCA 실행 후 분포는 다른 범주의 분포를 드러내며 범주가 선명하게 분리되길 바란다. 0부터 9까지의 숫자는 10개 색을 사용한다. 변환기는 fit 메소드를 통해 요소의 개수로 학습하고, 요소 위에 투사해 만든 새로운 데이터를 사용할 수 있다. scikit-learn에는 ProbabilisticPCA, RandomizedPCA, KernelPCA 와 같은 PCA 분해의 여러 종류를 구현한 클래스가 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | >>> %matplotlib inline >>> >>> from sklearn.decomposition import PCA >>> estimator = PCA(n_components=10) >>> X_pca = estimator.fit_transform(X_digits) >>> >>> def plot_pca_scatter(): >>> colors = ['black', 'blue', 'purple', 'yellow', 'white', 'red', 'lime', 'cyan', 'orange', 'gray'] >>> for i in xrange(len(colors)): >>> px = X_pca[:, 0][y_digits == i] >>> py = X_pca[:, 1][y_digits == i] >>> plt.scatter(px, py, c=colors[i]) >>> plt.legend(digits.target_names) >>> plt.xlabel('First Principal Component') >>> plt.ylabel('Second Principal Component') >>> >>> plot_pca_scatter() | cs |
n_components : 인스턴스의 속성 개수를 명시한다. 예제에서는 64개 속성의 인스턴스를 10개 속성의 인스턴스로 변환하고자 한다. 그래서 n_components 를 10으로 설정한다.
fit_transform(X, y=None) : X에 대해 지정하면, X의 차원을 줄여준다.
1 2 3 4 | for i in xrange(10): print i, X_pca[:, 0][y_digits==i], X_pca[:, 1][y_digits==i] >>> 0 [ -1.25949927e+00 1.12150947e+01 ... 6.43540563e+00 2.40942423e-01] [ 21.27494749 16.91977015 ... 19.47706123 26.59297862] | cs |
결과는 아래와 같다.
마지막으로 주성분 변환에 대해 살펴본다. components 속성을 통해 에스터메이터의 주성분에 접근할 수 있다. 매트릭스의 각 주성분은 본래 공간에서 변환 공간으로 벡터를 변환하는 데 사용한다. 이전에 그린 산점도에서 첫 두 주성분으로 살펴보자. 본래 데이터처럼 같은 크기의 모든 주성분을 그린다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> %matplotlib inline >>> >>> def print_pca_components(images, n_col, n_row): >>> plt.figure(figsize=(2. * n_col, 2.26 * n_row)) >>> for i, comp in enumerate(images): >>> plt.subplot(n_row, n_col, i + 1) >>> plt.imshow(comp.reshape((8, 8)), interpolation='nearest') >>> plt.text(0, -1, str(i + 1) + '-component') >>> plt.xticks(()) >>> plt.yticks(()) >>> >>> n_components = n_row * n_col >>> print_pca_components(estimator.components_[:n_components], n_col, n_row) | cs |
추가적인 주성분을 사용한다면 범주를 새로운 차원으로 구별할 수 있는 특징을 더 얻는다. 예를 들어 세 번째 주성분을 추가하고 3차원 산점도에 인스턴스를 그릴 수도 있다.
'프로그래밍 Programming' 카테고리의 다른 글
우분투에 엘라스틱서치 설치하기 How To Install and Configure Elasticsearch on Ubuntu 14.04 (0) | 2016.12.06 |
---|---|
비지도 학습 (2) - k평균으로 손글씨 숫자 군집화 (0) | 2016.12.03 |
결정트리와 타이타닉 가설 설명 (3) - 회귀를 이용한 예측 (0) | 2016.11.25 |
결정트리와 타이타닉 가설 설명 (2) - 결정트리 분류기 훈련 (0) | 2016.11.24 |
list object has no attribute write_png (0) | 2016.11.22 |