본문 바로가기
파이썬/Pandas & Numpy

2.1) Numpy로 공부하는 선형대수

by Bentist 2020. 3. 5.

* 김도형의 데이터사이언스 스쿨(수학편)을 토대로 작성했으며, 책에서 설명이 부족한 부분은 따로 보충했습니다.

 

선형대수의 데이터 유형: 스칼라, 벡터, 행렬, 텐서

 

스칼라: 숫자 하나만으로 이루어진 데이터

벡터: 여러 숫자가 특정한 순서대로 모여 있는 것, 한 송이의 붗꽃에서 나온 4가지 특징 데이터의 묶음

특징 벡터: 데이터 벡터가 예측 문제에서 입력 데이터로 사용되면 특징 벡터라고 한다.

 

[numpy를 사용한 벡터 표현]

1) 넘파이를 사용하여 벡터를 표현할 때는 2차원 배열 객체로 표현한다.

대괄호 2개를 이용하여 행렬의 형태로 만드는 것이다.

데이터는 항상 (n_samples, n_features) 의 구조를 가진 2D 배열. 아래 코드는 (4, 1) 행렬 

* 벡터는 열의 수가 1인 행렬이라고 볼 수 있으며, 벡터를 다른 말로 열벡터라고도 한다.

x1 = np.array([[5.1], [3.5], [2], [1.7]])

2)  아래 코드처럼 1개의 대괄호로 표현된 배열은 1차원 배열 객체이다.

넘파이는 1차원 배열 객체도 벡터로 인정한다. 그러나 이때는 벡터가 마치 하나의 행처럼 보여도 실제로는 열이다. 

x1 = np.array([5.1, 3.5, 2, 1.7])

 

다음은 사이킷런 패키지에서 제공하는 숫자 데이터셋으로 어떤 숫자인지 나타내보는 실습을 진행한다.

이미지는 기본적으로 2차원 데이터(2차원 배열)이다.

import numpy as np
import matplotlib.pylab as plt
from sklearn.datasets import load_digits

# 사이킷런의 숫자 데이터셋 로드
digits = load_digits()

# 임의로 선택한 이미지 번호들
samples = [0, 10, 20, 30, 1, 11, 21, 31]

d = []
# 번호들을 2차원 데이터 형태로 d 리스트에 각각 저장
for i in range(8):
    d.append(digits.images[samples[i]])

digits.images[0]의 구조를 보면, (8, 8)의 2차원 배열 형태로 되어있다.

array([[ 0.,  0.,  5., 13.,  9.,  1.,  0.,  0.],
       [ 0.,  0., 13., 15., 10., 15.,  5.,  0.],
       [ 0.,  3., 15.,  2.,  0., 11.,  8.,  0.],
       [ 0.,  4., 12.,  0.,  0.,  8.,  8.,  0.],
       [ 0.,  5.,  8.,  0.,  0.,  9.,  8.,  0.],
       [ 0.,  4., 11.,  0.,  1., 12.,  7.,  0.],
       [ 0.,  2., 14.,  5., 10., 12.,  0.,  0.],
       [ 0.,  0.,  6., 13., 10.,  0.,  0.,  0.]])
# matplotlib 사용한 시각화 과정

# (가로 8, 세로 2)인치의 액자 만들기
plt.figure(figsize=(8,2))

for i in range(8):
    # subplot(1, 8, 1)부터 subplot(1, 8, 8)까지 출력
    plt.subplot(1,8,i+1)

 

 

plt.subplot(1, 8, 1)은 가로 1칸(행 개수), 세로 8칸(열 개수)의 액자를 만들라는 뜻이고, 마지막 인수인 1은 인덱스를 나타낸다.

plt.subplot(1, 8, 1)은 콤마없이 plt.subplot(181)로 쓸 수 있다.

 

세번째 인자가 있을 경우, 해당 인덱스를 지정하는 것이므로 subplot 한 개를 불러오게 되고

세번째 인자가 없을 경우, plt.subplots(1, 8) 형태로 's'를 붙여줘야 에러 없이 모든 액자 출력이 가능하다.

 

ex) 2개 행, 4개의 열로 2*4 subplots 만들기

 

 

# matplotlib 사용한 시각화 과정

# (가로 8, 세로 2)인치의 액자 만들기
plt.figure(figsize=(8,2))

for i in range(8):
    # subplot(1, 8, 1)부터 subplot(1, 8, 8)까지 출력
    plt.subplot(1,8,i+1)
    # imshow()는 행렬 형태의 2차원 데이터를 색깔로 표시해줌
    plt.imshow(d[i], interpolation='nearest', cmap=plt.cm.bone_r)

plt.imshow() 함수는 2차원 배열 객체를 색깔로 표시해주는 함수이다. 구조는 plt.imshow( 2차원 데이터,  ... )  

interpolation은 보간법을 뜻하며, 픽셀들의 축 위치 간격을 보정하여 이미지가 자연스러운 모양으로 보일 수 있게 하는 방법이다. imshow()에서는 16가지 보간법이 있고, 'nearest'는 가장 고해상도인 보간법이다.

 

코드를 부연 설명하면 for i in range(8)에서 i = 0이 실행될 때,

plt.subplot(1,8,1)로 1*8의 액자를 만든 다음, 첫번째 액자를 지정하여 색깔로 변환된 imshow(d[1])의 이미지를 넣어준다.

 

만약 plt.subplots(1,8)로 인덱스를 지정하지 않을 경우, plt.imshow(d[i])가 액자에 스스로 들어가지 않는다.

다음과 같이 해당 인덱스를 인식하지 못하고 이미지가 밖에서 따로 놀게 된다.

 

 

아래 그림은 interpolation의 보간법 중에서 'nearest'와 'bilinear'의 대략적인 차이이다.

interpolation 코드를 작성할 필요가 있나? 해서 비교해본건데 'nearest'가 더 잘 보인다.

 

 

데이터 수치를 색으로 바꾸는 함수는 칼라맵(color map)이라고 한다.

사용 방법: cmap=plt.cm.원하는 색깔

칼라맵에 대한 자세한 내용은 다음 웹사이트를 참조

 

 

# matplotlib 사용한 시각화 과정

# (가로 8, 세로 2)인치의 액자 만들기
plt.figure(figsize=(8,2))

for i in range(8):
    # subplot(1, 8, 1)부터 subplot(1, 8, 8)까지 출력
    plt.subplot(1,8,i+1)
    
    # imshow()는 행렬 형태의 2차원 데이터를 색깔로 표시해줌
    plt.imshow(d[i], interpolation='nearest', cmap=plt.cm.bone_r)
   
    # 틱(눈금) 없애기(틱이 기본적으로 약간의 텍스트 공백을 차지하기 때문에 제거)
    plt.xticks([]) 
    plt.yticks([])

# 제목 타이틀
plt.suptitle('숫자 0과 1 이미지')

# 현재 figure상에서 배치되어 있는 액자 사이의 공백을 적당하게 주는 코드
plt.tight_layout()
plt.show()

 

이제 이 2차원 이미지를 64-크기의 1차원 벡터로 펼쳐보자.

 

 

v = []
for i in range(8):
    v.append(d[i].reshape(64,1))

plt.figure(figsize=(8,3))
for i in range(8):
    plt.subplot(1,8,i+1)
    # aspect = 이미지의 폭(값이 작을수록 두터워짐)
    plt.imshow(v[i], interpolation='nearest', aspect=0.3, cmap= plt.cm.bone_r)
    plt.xticks([]); plt.yticks([])
plt.suptitle('백터화된 이미지', y=1.05) # y = 이미지와의 간격
plt.tight_layout()
plt.show()

 

 

같은 숫자에 대한 벡터가 서로 닮았다는 것을 알 수 있다.

댓글