무효 클릭 IP 추적 중...
머신러닝,딥러닝/넘파이,numpy

[넘파이 기초] axis, keepdims 마스터하기

꼬예 2021. 4. 23.

안녕하세요 이번 시간에는 넘파이를 이용할때마다 자주보는 axis, keepdims!

하지만 할때마다 헷갈리는 두녀석을 완벽하게 이해하는 시간을 가져보고자 합니다.

 

 

 

 

 "axis = 0" 과 "axis =1" | np.sum() 연산

1. axis = 0일 때

import numpy as np

a= np.arange(12).reshape((3,-1)) # 3행으로만들고 나머지는 원소갯수에 따라 알아서 맞추라고 지정.

sum_ = a.sum(axis=0) # np.sum(a,axis=0)이랑 같음

print("ndarray: {}\n{}".format(a.shape, a))
print("ndarray.sum(axis=0): {}\n{}".format(sum_.shape,sum_))

output :

 

2. axis = 1일 때

import numpy as np

a= np.arange(12).reshape((3,-1)) # 3행으로만들고 나머지는 원소갯수에 따라 알아서 맞추라고 지정(-1)

sum_ = a.sum(axis=1) # np.sum(a,axis=1)이랑 같음

print("ndarray: {}\n{}".format(a.shape, a))
print("ndarray.sum(axis=0): {}\n{}".format(sum_.shape,sum_))

output :

 

두 결과를 보시면 아 axis = 0 , 1일때 어떤 방향으로 연산이 되는지 감이 오실겁니다. 

그림을 통해 무엇을 중요시 봐야하는지 다시한번 보죠!

axis =1 은 파란선방향 axis = 0은 빨간색 방향으로 연산을 합니다. 

이때 axis =1 을 통해 연산을 한 결과의 shape을 주목해주십시오! 

어떤가요? 2차원에서 1차원으로 차원이 한 차원 downgrade 되었네요!

그리고 (3,4) 에 column 부분이 없어졌습니다.

 

aixs = 0은 빨간색 방향으로 연산을 합니다.

그리고 연산을 통한 결과의 shapedms (4,) 로 (3,4)에서 3 부분 즉 row부분이 날아갔군요..

 

정리하자면, row 방향으로 연산(axis=0)을 할땐 row 부분(여기선 3)이 사라지고 column 방향으로 연산(axis=1)을 할때는 column의 숫자(여기선 4)가 사라지는 것을 확인 할 수 있네요! 조금만 생각하면 당연한거지만 차원이 커지면 헷갈릴 수 있으니 머리에 잘 넣어두시면 좋겠습니다.

 

+ 보너스

axis = 0, axis=1 도대체 어느 방향으로 연산하는거지? 라고 자주 헷갈리시는 분들은 이렇게 외워주시면 좋겠습니다!

 

위 예시만 보고 아 axis = 0 은 row 방향이고 axis  = 1은 column 방향이다라고 외우시기보다 저는 이런방식을 추천드립니다.

 

"axis = 0 이 가장 바깥차원 방향 axis = 1 이 그 다음 차원방향이다." 라고 외워 주시면 좋겠습니다.

이게 무슨 말이냐구요? 

 

(2,3) 행렬이 있다고 합시다.

여기서 (2,3)은 (3,) 벡터가 2개 있는 것을 의미합니다. 

 

23보다 더큰 차원의 개념이죠?

 

(3,2,4)의 텐서가 있다고 합시다.

이건 풀어서 설명하면

(4,)의 벡터가 2개 있는데 ===>  (2,4)

근데 그녀석(2,4)이 3개가 있다는 말입니다. ====> (3,2,4)

즉 3이 가장 바깥차원의 수 , 2가 그 다음 , 4가 가장 안쪽 차원의 갯수이겠지요?

 

이제 어느정도 감이 잡히셨을 겁니다. 

axis = 0 일때 row 방향이라는건 2차원일때만 해당되는이야기입니다.

3차원에서 axis = 0 즉 제일 바깥 차원이 뭐죠? 채널입니다. 그렇기 때문에 채널의 방향으로 연산이 됩니다. 

아래와 같이 말이죠.

참고로 axis = 0하고 axis = 1만 있는게 아닙니다.

차원이 커지면 axis = 3, 4, 5 가 있을수도 있겠죠?

 

 

 

 

브로드캐스팅

axis 가 연산을 하기 위해 존재하므로 넘파이의 대표적인 연산 기술인 브로드캐스팅과는 뗄레야 뗄수 없는 관계입니다.

 

하지만 위에서 말씀드린대로 axis 를 통해 연산을하면 한차원이 다운그레이드되면서 shape의 모양이 바뀌게 됩니다. 

앞선 브로드캐스팅 연산 2편 포스팅에서 말씀드린것처럼 차원이 다를경우 브로드캐스팅이 될때가있고 안될때가 있는데요.  

위의 그림을 다시 한번 보겠습니다. 

브로드캐스팅 편을 보신분은 알겠지만 axis = 1로 연산을 했을경우 브로드캐스팅 연산이 불가능합니다.

연산을 하려고하면 아마도 아래와 같은 "ValueError : operands could not be broadcast ..." 오류를 만나게될겁니다.

하지만 저 친구를 가지고 우리는 연산을 하고싶습니다..

어떻게 해야할까요? (3,)를 (3,1)로 변경해주면됩니다. 즉 차원을 맞춰주는것이지요.

이것에 대한 자세한 연산법은 브로드캐스팅 연산 1편에서 자세히 설명하였으니 참고바랍니다.

 

하지만 매번 차원을 바꿔주기 귀찮으니 이때 사용하는 것이 바로 keepdims입니다.

 

keepdims 사용

import numpy as np

a= np.arange(12).reshape((3,-1))


print("ndarray: {}\n{}".format(a.shape, a))

sum_class = np.sum(a, axis=0, keepdims=True)
sum_student = np.sum(a, axis=1 , keepdims=True)

print("sum_class: {}\n{}".format(sum_class.shape,sum_class))
print("sum_student): {}\n{}".format(sum_student.shape,sum_student))

output :

사용법은 연산하고자하는 함수 안에 keepdims = True로 설정해주시면 됩니다. 

보시는것처럼 벡터의 [] 하나씩 더 추가되면서 행렬 즉 2차원이 된것을 보실 수 있습니다. 

 

위 그림을 보시면 keepdims 를 적용하자 차원이 죽으면서 사라졌던 부분이 숫자 1로 바뀌면서 shape과 관계 없이 브로드캐스팅이 가능한 상태가 되었네요!

 

3차원 텐서 적용(axis =1 적용)

조금더 고차원으로 넘어가서 지금 까지 배운 내용을 적용해 보겠습니다. 

 

먼저 문제를 하나 내겠습니다.!

 

(2,3,4)의 텐서가 있다고 합시다. 

그런데 우리는 axis =1 을 적용해서  sum()를 이용해 연산을 한값을 sum_ 이라고 합시다. 

이 sum_은 (2,3,4)와 브로드캐스팅이 가능할까요?

 

정답부터 말하자면 '불가능' 입니다

왜그럴까요?

 

앞서 설명드린대로 3차원에서 axis =1 방향으로 연산이란 row 방향 연산을 의미합니다. 

다시말하면 row 방향의 숫자가 죽어서 

(2,3,4) --> (2,4)의 형태로 됩니다. 

 

(제가 왜 계속 위에서 차원과 shape을 강조했는지 이해가 되실겁니다. 

이 부분이 이해가 안되시면 위에가서 다시한번 읽어보세요! 고차원이 될 수록 더 헷갈리니까요.)

 

그런데!

 

여기서 (2,4)의 shape을 가진 sum_ 이 과연 (2,3,4)와 연산이 가능할까요?

불가능합니다. 바로 이때 사용하는게 keepdims 입니다. 

 

코드를 통해 확인하겠습니다. 

import numpy as np

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

sum_ = a.sum(axis=1)
sum_k = a.sum(axis=1, keepdims =True)

print("ndarray: {}\n{}".format(a.shape, a))
print("axis=1: {}\n{}".format(sum_.shape, sum_)) # 이건 브로드캐스팅 불가능
print("axis=1, keepdims=True:  {}\n{}".format(sum_k.shape, sum_k)) #이건 브로드 캐스팅 가능

output :

keepdims를 True로 설정하니 사라졌던 부분이 다시 1로 생겼네요.

차원이 같아졌고 가운데 1이 있으니 브로드캐스팅이 가능합니다. 

 

 

 

3차원 텐서 적용(axis =2 적용)

import numpy as np

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

sum_ = a.sum(axis=2)
sum_k = a.sum(axis=2, keepdims =True)

print("ndarray: {}\n{}".format(a.shape, a))
print("axis=1: {}\n{}".format(sum_.shape, sum_))
print("axis=1, keepdims=True:  {}\n{}".format(sum_k.shape, sum_k))

이번엔 위코드에 axis =2 를 적용해볼게요

그럼 연산한 sum_이 어떤 shape이 될까요? 

 

axis = 0 도아니고 1도 아니고 2이니.. 

3차원에서 가장 안쪽인 column 방향으로 연산 한다는 뜻이네요.

column을 나타내는 4가 사라진 (2,3)이 sum_의 shape이 됩니다. 

output :

하지만 (2,3)은 (2,3,4)와 브로드캐스팅 연산이 안되니 kepdims = True를 통해 shape을 변경해줍니다.

역시 마찬가지로 사라졌던 4자리가 1로 바뀌었네요!

 

정리

이번 시간에는 axis 의 방향에 따라 어떻게 shape이 바뀌게되고, 

또 그 shape을 keepdims 를 이용해서 브로드 캐스팅 까지 알아보았습니다. 

 

 

 

 

 

이 글과 읽으면 좋은글

  • 트위터 공유하기
  • 페이스북 공유하기
  • 카카오톡 공유하기
이 컨텐츠가 마음에 드셨다면 커피 한잔(후원) ☕

댓글