이미지 데이터 digits, 주성분 분석으로 3차원의 가시화를 해본다

소개



scikit learn에는 digits라고 하는 0~9까지의 숫자의 필기 이미지 데이터가 포함되어 있습니다. 이것을 다변량 분석의 일종인 주성분 분석(PCA)을 이용해 가시화한다는 사례는 다수 소개되고 있습니다. 예를 들면 Scikit-learn으로 PCA 등. 그러나, 시각화는 대부분 제2 주성분까지의 2차원 데이터인 예가 대부분이었습니다. 여기에서는 제3주성분까지 어떻게든 가시화시켜 보고 싶습니다(네타). 또한 주성분 분석에 관해서는 의미를 알 수 있는 주성분 분석이 알기 쉬웠다고 생각합니다.

디지털 데이터의 시각화



라이브러리 가져오기부터 이미지 데이터 시각화까지 수행합니다.
# -*- coding: utf-8 -*-
import numpy as np
from sklearn import datasets
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

#digitsのデータをダウンロード
data = digits["data"]
target = digits["target"]
target_name = digits["target_names"]
images = digits["images"]

#matplotlibでdigitsのデータの可視化
for i in range(9):    
    plt.subplot(3,3,1+i)
    plt.imshow(images[i,:,:])
    plt.gray()
plt.show()

digits는 8 × 8의 64 픽셀 데이터가 1797 이미지 제공됩니다. 전부 가시화하면 힘들기 때문에 처음 9개 정도를 그립니다.

덧붙여서digits["data"]에서는 배열이(1797,64)로 되어 있고, 기계 학습에 그대로 적용하기 쉬운 데이터가 되고 있어,digits["images"]에서는(1797,8,8)의 배열로 matplotlib로 그리기 쉬운 형식으로되어 있습니다.

기여율 계산 및 2차원 플롯



주성분 분석을 수행하여 성분별 기여율을 계산합니다. 이번 예에 한하지 않고 주성분 분석을 사용할 때에는 반드시 기여율은 보고 싶은 것입니다.
data /=16.
#principal component analysis
pca = PCA()
pca.fit(data)
data = pca.transform(data)

#pcaの寄与率計算
contribution = pca.explained_variance_ratio_
#寄与率を累積和に変更
contribution = np.cumsum(contribution)
#最初に0を追加
contribution = np.append(0,contribution)

#寄与率の描画
plt.plot(contribution,marker="o")
plt.xlim(0,65)
plt.ylim(0,1.1)
plt.show()

#第2成分までscatter
for i in target_name:
    index =np.where(target==i)
    plt.scatter(data[index,0],data[index,1],label=str(i),alpha=0.5,s=20)
plt.legend(loc=3)
plt.xlabel("First Component")
plt.ylabel("Second Component")
plt.xlim(-3,3)
plt.ylim(-2,2)
plt.show()


기여율은 다음 그래프와 같습니다.

세로축이 기여율의 누적 합이 됩니다. 제1주성분에서는 15%, 제2주성분까지는 28%, 제3주성분까지는 40% 정도의 기여율이 됩니다.
제2주성분까지를 플롯하면


실제로 2차원 플롯해 보면 대부분의 숫자의 경계를 시인할 수 있습니다만, 8의 숫자와 9의 숫자는 영역이 불명료한 느낌은 합니다. 역시 2차원의 플롯으로는 부족하네요.
30차원 정도를 직감적으로 가시화하는 수단이 있으면 됩니다만, 유석에 무리이므로 3차원으로 참습니다.

3차원 플롯



matplotlib로 3차원 그래프를 만들어 보겠습니다. 단순히 만드는 것만으로는 재미없기 때문에 3D를 그리는 각도를 angle의 변수로 1°씩 변경한 그래프를 만듭니다. 다음에 그래프를 저장해 두고, 마지막으로 파라파라 만화의 요령으로 조금씩 각도가 변화하는 동영상을 편집합니다. matplotlib에서도 동영상을 만들 수 있는 것 같습니다만, 이번은 OpenCV를 사용해 동영상을 작성합니다(단순히 OpenCV의 사용법에 익숙하고 있을 뿐).

우선은 3차원 화상의 생성, 보존까지.
for angle in range(0, 180):
    fig = plt.figure()
    ax = fig.add_subplot(111, projection="3d")
    ax.view_init(30, angle)      
    for i in target_name:
        index =np.where(target==i)
        ax.scatter(data[index,0], data[index,1], data[index,2],alpha=0.4)
    #保存する名前を指定
    name = str(angle)+".jpeg"
  #画像の保存
    plt.savefig(name)
    plt.show()

0°의 경우

10°의 경우


글쎄, 3차원처럼 보인다.
그런 다음 OpenCV를 사용하여 저장한 0~180°까지의 이미지 순서로 호출하여 동영상을 만듭니다.
# -*- coding: utf-8 -*-
import cv2
import numpy as np
#動画のフレームレートの解像度を指定
fps = 10
size = (432,288)

fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter("sample.avi",fourcc, fps, size)

for i in range(180):
    name = str(i)+".jpeg"
    #画像の読込
    frame = cv2.imread(name)
    out.write(frame)
out.release()

만든 동영상
글쎄, 3 차원으로 보이는 동영상이되었습니다. 실용성은 전무합니다만.

1차원의 경우



덤, 첫 번째 주성분 만 Hist를 사용하여 그린 경우
for n in target_name:
    #target_nameと同じ名前を持つtargetデータのインデックスを作成
    index =np.where(target==n)
    plt.hist(data[index,0].T,
             range=(-2,2),
             bins=40,
             histtype="stepfilled",
             label=str(n),
             alpha=0.3)
plt.xlim(-3,2.5)
plt.legend(loc=3)
plt.show()


1차원으로 여기까지 알 수 있을까 하는 느낌이지만, 실용적으로는 유석에 차원 압축이 너무 힘들다.

화상의 판별의 전처리에 주성분 분석을 사용하는 일도 있고, 화상을 취급하는 사람도 주성분 분석의 거동은 유지해 두고 싶은 것입니다.

좋은 웹페이지 즐겨찾기