본문 바로가기
머신러닝/Numpy

[Numpy] #13 차원 조작(추가, 제거, 변경, 이동) / np.reshape(), np.squeeze(), np.swapaxes(), np.moveaxis(), np.transpose() 등 기본문법 공부하기 13

by doyou1 2021. 10. 13.
반응형

오늘은 Numpy에서 차원을 조작하는 메소드에 대해서 공부해보겠다.

미니 프로젝트를 한두 개 진행해보며 느낀 점은 수학적 개념을 코드로 구현하려면, 데이터 분석도 중요하지만 데이터를 전처리하는 과정도 중요하다. 그 데이터 전처리 중 배열의 차원을 바꿔 좀 더 직관적으로, 좀 더 코드를 간편하게 만들 수 있다. 이에 차원과 관련한 메소드를 공부해보겠다.

 

- np.reshape()

먼저 np.reshape()이다. 말 그대로 "모양을 바꾼다"라는 의미의 메소드이다. 차원과 관련해서 가장 많이 사용되는 메소드이다. 이곳저곳 활용도가 높다.

import numpy as np

a = np.arange(9)

print(a.shape)  # (9,)


b = a.reshape((3, 3))
c = a.reshape((-1, 3))
d = a.reshape((-1, ))
e = a.reshape((1, -1))

print(b.shape)  # (3, 3)
print(c.shape)  # (3, 3)
print(d.shape)  # (9,)
print(e.shape)  # (1, 9)

위의 코드는 np.reshape()의 가장 기본적인 활용법이다.

추가적으로 작성할만한 부분은 "-1"이다. 앞선 포스팅에서도 설명했지만, "-1"을 사용하면 남은 차원을 맞춰준다는 개념으로 이해하면 좋을듯하다. 외부 데이터나 프로그램 중간에 있는 데이터라 shape을 정확하게 알 수 없을 경우, 효과적으로 사용하기 좋은 트릭이다.

 

import numpy as np

a = np.arange(8).reshape((2, 4))

b = a.reshape((*a.shape, 1))
c = a.reshape((1, *a.shape))

print(b.shape)  # (2, 4, 1)
print(c.shape)  # (1, 2, 4)

print(*a.shape) # 2 4
print(*b.shape) # 2 4 1
print(*c.shape) # 1 2 4

# list = list(*a.shape)   # err
list = list([*a.shape])

for data in list:
    print(data)   
    # 2
    # 4

d = a.reshape((list[::-1]))
print(d.shape)  # (4, 2)

다음은 ndarray.shape을 unpacking 하는 "*ndarray.shape"을 이용한 np.reshape() 활용법이다.  

 

import numpy as np

a = np.arange(8).reshape((2, 4))

print(type(a.shape))    # <class 'tuple'>

ndarray.shape의 자료형은 'tuple'이다. 그래서 python에서 제공하는 packing, unpacking 기능을 사용할 수 있다.

관련해 추가적인 정보를 확인하고 싶으면, 아래 참조한 페이지를 확인하기 바란다.

 

https://wikidocs.net/16042

 

16. tuple(튜플)

## 1. tuple(튜플) - tuple(튜플)은 불변한 순서가 있는 객체의 집합입니다. - list형과 비슷하지만 한 번 생성되면 값을 변경할 수 없습니다. - REP ...

wikidocs.net

 

https://wikidocs.net/22801

 

3) packing, unpacking

`print`함수는 출력하고자하는 객체가 몇개던지, 즉 몇개의 인자를 받던지 상관하지 않고 출력해줍니다. ``` print(

wikidocs.net

 

- np.newaxis

np.newaxis는 ndarray의 slicing에 활용할 수 있는 속성이다. 다른 효과적인 메소드들이 많아 자주 사용되진 않지만, 이런 게 있구나 하는 정도로 살펴보고 넘어가겠다.

 

import numpy as np

a = np.arange(9)

b = a[np.newaxis, :]
c = a[:, np.newaxis]

print(b.shape)  # (1, 9)
print(c.shape)  # (9, 1)


d = a[np.newaxis, np.newaxis, :]
e = a[np.newaxis, : , np.newaxis]
f = a[ : , np.newaxis, np.newaxis]

print(d.shape)  # (1, 1, 9)
print(e.shape)  # (1, 9, 1)
print(f.shape)  # (9, 1, 1)

g = a[np.newaxis]

print(g.shape)  # (1, 9)

newaxis라는 말 뜻 그대로 "새로운 축"을 추가된다는 개념으로 받아들이자!

 

import numpy as np

a = np.arange(9)

b = a[np.newaxis, :]
c = a[None, :]

print(b.shape)  # (1, 9)
print(c.shape)  # (1, 9)

d = a[None, :, None]
e = a[np.newaxis, :, np.newaxis]

print(d.shape)  # (1, 9, 1)
print(e.shape)  # (1, 9, 1)

명확한 이유를 설명하지 못하기 때문에 넣을까 말까 고민했는데, None도 np.newaxis와 같이 활용될 수 있다.

 

- np.expand_dims()

np.expand_dims()는 말 그대로 차원을 추가하는 메소드이다.

 

import numpy as np

a = np.arange(2*3*4).reshape((2,3,4))

b = np.expand_dims(a, axis=0)
c = np.expand_dims(a, axis=1)
d = np.expand_dims(a, axis=2)
e = np.expand_dims(a, axis=3)
f = np.expand_dims(a, axis=-1)

print(b.shape)  # (1, 2, 3, 4)
print(c.shape)  # (2, 1, 3, 4)
print(d.shape)  # (2, 3, 1, 4)
print(e.shape)  # (2, 3, 4, 1)
print(f.shape)  # (2, 3, 4, 1)

a = np.arange(3*4).reshape((3,4))

b = np.expand_dims(a, axis=(0, 1))
c = np.expand_dims(a, axis=(1, 2))
# d = np.expand_dims(a, axis=(0, 0))    err
e = np.expand_dims(a, axis=(0, 2))

print(b.shape)  # (1, 1, 3, 4)
print(c.shape)  # (3, 1, 1, 4)
# print(d.shape)
print(e.shape)  # (1, 3, 1, 4)

위 코드를 천천히 따라가다 보면 알 수 있듯이, np.expand_dims()를 활용하면 원하는 axis(축)에 차원을 추가할 수 있다. 중복 추가는 안되지만, tuple의 형태로 한 번에 여러 축에도 차원을 추가할 수 있다.

 

- np.squeeze()

np.squeeze()는 말 그대로 쥐어짜는 것이다. "차원을 쥐어짠다?" 불필요한 차원을 제거하거나 줄이는 메소드이다.

import numpy as np

a = np.ones(shape=(3,1,4))

b = np.squeeze(a)
print(b.shape)  # (3, 4)

a = np.ones(shape=(1,1,2,1,4,5,3,1,2))

b = np.squeeze(a)
print(b.shape)  # (2, 4, 5, 3, 2)

데이터 처리를 하다 보면, 브로드캐스팅 등의 이유로 차원을 확장시켜야 하는 경우가 생긴다. 같은 맥락에서 차원을 축소시켜야 하는 경우도 생긴다. 그런 경우 활용할 수 있는 메소드이다.

 

- np.swapaxes()

np.swapaxes()는 말 그대로 "축을 서로 바꾼다"는 의미의 메소드이다. 

import numpy as np

a = np.ones(shape=(3, 4, 5, 6))

# np.swapaxes(arg1, arg2, arg3)
# arg2,arg3 : 서로 바꿀 차원 idx
b = np.swapaxes(a, 0, 1)
c = np.swapaxes(a, 0, 2)
d = np.swapaxes(a, 0, 3)

print(a.shape)  # (3, 4, 5, 6)
print(b.shape)  # (4, 3, 5, 6)
print(c.shape)  # (5, 4, 3, 6)
print(d.shape)  # (6, 4, 5, 3)

e = np.swapaxes(a, 0, -1)   # = (a, 0, -1)

print(e.shape)  # (6, 4, 5, 3)

차원을 서로 바꾸는 np.swapaxes() 메소드를 사용하려면, 바꾸는 "서로"지정해줘야 한다.

코드의 주석에 작성해놨듯, 서로 바꿔줄 차원의 index들을 파라미터로 지정해줘야 한다. 

 

- np.moveaxis()

np.moveaxis()는 말 그대로 "축을 이동하다"는 개념의 메소드이다. 의미로 보면 np.swapaxis()와 같은 개념이라고 생각할 수 있는데, 동작 과정을 보면 살짝 다르다는 걸 알 수 있다.

 

import numpy as np

a = np.ones(shape=(3, 4, 5, 6))

b = np.moveaxis(a, source=0, destination=1)
c = np.moveaxis(a, source=0, destination=2)
d = np.moveaxis(a, source=0, destination=-1)

# np.moveaxis()
# source=n, destination=m   
# n번째 차원을 m차원으로 옮기고, 
# 나머지는 왼쪽으로 옮김
print(a.shape)  # (3, 4, 5, 6)
print(b.shape)  # (4, 3, 5, 6)
print(c.shape)  # (4, 5, 3, 6)
print(d.shape)  # (4, 5, 6, 3)

np.swapaxis()는 서로 바꾸는 것이지만, np.moveaxis()"특정 차원"을 "특정 위치"로 이동시키는 것이다. 그래서 파라미터 속성으로 source와 destination이 있다. 

source는 "이동시키고 싶은 차원의 index",

destination은 "이동시킬 차원의 index"

이다. 그리고 이동이 완료되면, 나머지 차원들은 왼쪽으로 당겨지면서 자리를 채우게 된다.

관련한 실제 동작과 결과는 위 코드를 참조하면 되겠다.

 

- np.transpose()

차원 조작의 마지막이다. np.transpose()는 transpose라는 단어의 뜻에서 알 수 있듯, "전치시키는" 메소드이다. 

 

import numpy as np

a = np.ones(shape=(2,3,4))

b = np.transpose(a)
c = a.T

print(a.shape)  # (2, 3, 4)
print(b.shape)  # (4, 3, 2)
print(c.shape)  # (4, 3, 2)

위 코드와 같이 np.transpose()기본형으로 사용하면 차원을 역으로, 거꾸로, 뒤에서부터 다시 쌓는다.

그리고 np.tranpose()의 기본형의 약어로서 ndarray.T이 사용된다는 점도 함께 이해하자.

 

import numpy as np

a = np.ones(shape=(2,3,4))

b = np.transpose(a, axes=(0,1,2))
c = np.transpose(a, axes=(1,2,0))
d = np.transpose(a, axes=(2,1,0))
e = np.transpose(a, axes=(-1,1,0))

print(a.shape)  # (2, 3, 4)
print(b.shape)  # (2, 3, 4)
print(c.shape)  # (3, 4, 2)
print(d.shape)  # (4, 3, 2)
print(e.shape)  # (4, 3, 2)

np.transpose()에는 axes라는 속성이 있다. 앞선 차원 조작 메소드들은 하나 혹은 두 개를 변경하는 거지만, np.transpose()에서 axes 속성을 사용하면, 다수의 차원들을 한 번에 변경할 수 있다.

상황에 따라 활용도 높게 사용할 수 있겠다.

반응형

댓글