본문 바로가기
Data Science/Pandas, Numpy

[ Numpy ] 넘파이 배열 , axis, 차원 축소/확장 정리

by Queen2 2022. 10. 19.
728x90
반응형

✨ 넘파이 차원, Axis 개념 및 응용 설명

오늘은 넘파이의 기본인 넘파이 array의 axis에 대해 알아보려 합니다.

 

우선 넘파이의 axis는 파이썬의 index가 0부터 시작하는 것처럼 0부터 시작합니다.

https://predictivehacks.com/tips-about-numpy-arrays/

 

위의 그림을 머리속에 넣어두면 좋은데요

일반적으로 1D array라고 하면 aixs0만 있는 행만 하나 있는 상태를 의미합니다.

 

여기서 우리가 그래프를 그릴 때 x축 y축이 필요한 것처럼 축을 하나 추가하면 2D array 마치 행렬같은 모습이 나옵니다

 

여기서 제일 헷갈렸던 부분은 Numpy에서의 '차원'은 선형대수에서 애기하는 차원과는 다르다는 점입니다.

넘파이에서 차원은 이 axis의 개수를 의미합니다

 

아래 스택오버플로우에서도 이런 의문들이 많이 제시되어 있는데요 

(https://stackoverflow.com/questions/19389910/in-python-numpy-what-is-a-dimension-and-axis)

코드를 보면서 넘파이의 차원을 이해하고 넘어갑시다

 

In [262]: a = np.arange(8)

In [263]: a
Out[263]: array([0, 1, 2, 3, 4, 5, 6, 7])

In [264]: a.ndim    # a의 차원은 1차원
Out[264]: 1

In [265]: a.shape   #위의 그림처럼 행만 있는 형태의 모형
Out[265]: (8,)

In [266]: b = np.array([[0,0,0],[1,2,3],[2,2,2],[9,9,0]])
#괄호가 2개로 표현

In [267]: b
Out[267]: 
array([[0, 0, 0],
       [1, 2, 3],
       [2, 2, 2],
       [9, 9, 0]])

In [268]: b.ndim  #2차원
Out[268]: 2

In [269]: b.shape
Out[269]: (4, 3)

 

이처럼 넘파이에서 몇차원인지 구분하는 기준은 [[  ]] 이런 대괄호의 개수로 판별할 수 있습니다.

https://sebastianraschka.com/blog/2020/numpy-intro.html

 

위에 예시를 보면서 개념을 다시 정리해보겠습니다.

만약, np.sum(array,axis=0)이라고 하면 보통 axis=0은 행을 의미하므로 가로로 덧셈을 해야한다고 생각하지만

넘파이에서 2d array의 axis=0은 세로축의 관점을 의미하기 때문에 덧셈이 세로축을 기준으로 오게 됩니다.

 


넘파이 차원의 개념을 익혔으니 넘파이 차원을 증가/감소 시키는 방법을 보겠습니다

 

 

✨ 넘파이 차원 확장 방법

  • 1차원에서 2차원 변형 방법

1)  arr1D.reshape(-1 ,1)

 

넘파이의 reshape은 array의 모양을 변형시켜주는 기능을합니다.

여기서 -1 은 무슨 값이 올지 모르겠다 알아서 변형시켜 달라는 것을 의미합니다.

반대로 1은 행은 어떤 모양일지 모르겠지만 1열의 형태로 해달라는 의미입니다.

 

 reshape의 가장 큰 특징은 이미 가지고 있는 모양만 활용할 수 있다는 건데요

가령 (4,) 형태의 모양이 있으면 (,4) (2,2) 이런식으로 곱셈 조합의 형태로 바꿀 수 있다는 의미입니다

 

a = np.arange(6).reshape((3, 2))
a
array([[0, 1],
       [2, 3],
       [4, 5]])

 

그렇다면 여기서 1차원에서 2차원으로 만드는 reshape(-1,1) 은 뭘 의미할까요?

위쪽 그림에서 기본  1차원 넘파이 배열은 (숫자,) 의 형태를 가진다고 했었죠, 그렇다면 2차원은 콤마 다음의 axis=1이

필요하기 때문에 우측에 1을 넣어주고 -1에 2차원 변형을 위한 적합한 변형을 해달라고 하는 것이죠.

 

 

2)  np.reshape(arr1D, ( -1, 1))

 

이 방법은 1번 방법과 의미와 적용 방식은 같지만 표현 방식의 차이만 있습니다

 

 

3)  np.expand_dims(arr1D, axis=1)

 

이 방법은 좀 더 직관적인 방법인데요 넘파이 1차원 -> 넘파이 2차원으로 가기 위한 axis=1을 추가해달라는 것을

넘파이의 expand_dims를 사용했습니다.

 

4)  arr1D[: , np.newaxis]

     arr1D[ np.newaxis, :]

 

np.newaxis 는 직관적이면서 사용하기가 편리한 방법인데요

단, np.newaxis를 한번 사용했다 --> 차원을 1개 올린다고 볼 수 있습니다.

(np.newaxis 표현이 길거나 잘 안 외워진다 싶으면 None을 사용할 수도 있습니다.None으로 표현 대체 가능)

 

stackoverflow에서 이해가 잘되는 그림을 가지고 왔습니다. np.newaixs는 좀 더 명시적으로 행벡터나 열벡터에

차원을 추가하겠다는걸 보여줄 수 있다는 장점을 가지고 있습니다.

 

 

stackoverflow(https://stackoverflow.com/questions/29241056/how-do-i-use-np-newaxis)

 

np.newaxis는 넘파이 broadcasting을 통한 계산을 할 때 유용하게 사용됩니다.

broadcasting은 서로 모양이 다른 array를 자동으로 값을 채워줘서 연산이 가능하도록 하는 방법을 의미하는데요

 

https://numpy.org/doc/stable/user/basics.broadcasting.html

 

이 그림처럼 a와 b의 연산을 위해 a의 크기만큼 b의 값을 복제하는 것이죠

여기서 broadcasting은 우리가 행렬의 곱셈을 할 때처럼 broadcasting가능한 모양을 가져야 하는데요

 

https://numpy.org/doc/stable/user/basics.broadcasting.html

이렇게 b는 아무리 복제를 해도 a의 모양이 될 수 없죠? 

이때 broadcasting 모양을 맞춰주기 위해 사용하는게 new axis입니다

 

 x1 = np.array([1, 2, 3, 4, 5])
 x2 = np.array([5, 4, 3])
 
 x1 = x1[:,np.newaxis]
# array([[1],
#        [2],
#        [3],
#        [4],
#        [5]])

x1 + x2
array([[ 6,  5,  4],
       [ 7,  6,  5],
       [ 8,  7,  6],
       [ 9,  8,  7],
       [10,  9,  8]])

 

  •      arr1D[ np.newaxis, :] 와 동일한 expand_dims 표현
y = np.expand_dims(x, axis=0)
>>> y
array([[1, 2]])
>>> y.shape
(1, 2)

 

  •      arr1D[:,np.newaxis] 와 동일한 expand_dims 표현
y = np.expand_dims(x, axis=1)
>>> y
array([[1],
       [2]])
>>> y.shape
(2, 1)

 

 

✨ 넘파이 차원 축소 방법

numpy.sqeeze(array, axis = )

sqeeze는 1차원인 axis를 제거해주는 역할을 합니다

 

x = np.array([[[0], [1], [2]]])
#3차원으로 1,3,1의 모양을 가집니다
x.shape
(1, 3, 1)
np.squeeze(x).shape
(3,)
#1인 차원을 모두 없애줌

np.squeeze(x, axis=0).shape
(3, 1)
#1인 첫번째 axis를 없애줌

np.squeeze(x, axis=2).shape
(1, 3)
#1인 세번째 axis를 없애줌

 

array.flatten()   -> 1D array로 바꾸기

이 방법은 flatten , 기존 array를 납작하게 1D array로 바꾸기 위해 사용합니다.

옵션을 통해 1d array의 기준을 설정할 수도 있는데요, 행을 기준으로는 'C', 열기준은 'F' 을 사용할 수 있습니다

 

a = np.array([[1,2], [3,4]])
a.flatten()
array([1, 2, 3, 4])
a.flatten('F')
array([1, 3, 2, 4])

 

numpy.ravel(array,order=옵션)   -> 1D array로 바꾸기

 

응용 방식은 flatten 과 동일해서 이해가 잘됩니다

x = np.array([[1, 2, 3], [4, 5, 6]])
>>> np.ravel(x)
array([1, 2, 3, 4, 5, 6])

input으로 넣은 array를 쭉 1차원 배열로 펴주는 역할을 하는 거죠

 

>>> x.reshape(-1)
array([1, 2, 3, 4, 5, 6])
>>> np.ravel(x, order='F')
array([1, 4, 2, 5, 3, 6])

reshape(-1)으로 사용할 수 도 있으며, flatten처럼 옵션 지정도 가능합니다

 

 

 

‼ Numpy Ravel과 flatten의 차이

Numpy.ravel() flatten()
원본 배열의 참조/view 만 하는 얕은 복사 반환 원본 배열의 본사본 반환
array 변환시 원본 배열도 변경됨 원본 값에 영향이 없음
메모리 할당이 안돼서 flatten 보다 빠름 ravel보다 더 느림
numpy 라이브러리 기능임 ndarray 객체의 메소드에 해당함

Source: https://www.geeksforgeeks.org/differences-flatten-ravel-numpy

source: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.flatten.html

728x90
반응형

댓글