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

[넘파이 기초] flatten 와 ravel의 차이 | 메모리 관리(.copy() vs .view())

꼬예 2021. 4. 10.

넘파이에서 이 둘의 기능은 사실상 같습니다.

그래서 아마 많은 분들이 둘이 어떤 차이가 있을지 잘 모르실텐데요.

 

오늘은 이 둘의 기능 및 차이를 알아보고 주의해야 할점을 공부해봅시다.

 

먼저 둘을 이해하기 위해선 .copy()와 .view() 메소드를 통해 메모리 공유에 대한 개념부터 알아야 합니다.

 

 

 

.copy()

import numpy as np

a = np.arange(5) # array([0, 1, 2, 3, 4])
b = a.copy()

b[0] = 100
print(a)
print(b)

위와 같이 5개의 원소를 가진 배열을 a 변수에 넣고. 이 값을 복사(copy)에서 다시 b에 넣은 후 

b[0] 의 값을 바꾼 경우입니다. 

a, b 의 값이 어떻게 나올까요?

위와같이 b배열의 값을 변경했으니 b의 1번째 원소가 바뀐걸 확인 할 수 있습니다..

문제는 .view()함수를 이용할때인데요..

 

 

 

.view()

import numpy as np

a = np.arange(5)
b = a.view()

b[0] = 100

print(a)
print(b)

위와 똑같이 실행했을때 output은 ..

b뿐만 아니라 a까지 값이 변경된것을 알 수있습니다. 

 

정리하자면. 

'.view()'는 기존값이 저장되어있는 메모리를 같이 쓰는 것이기때문에 다른 변수에 값을 할당했다할지라도 변경시 다같이 변경되는 것을 알 수있고,

 

'.copy()'는 서로 다른 메모리저장소를 이용하겠다는 의미임으로, 값을 변경해도 서로에게 영향을 끼치지 않는 것입니다. 

 

사실 view() 함수를 넣지 않아도 파이썬에서는 디폴트로 view()함수처럼 메모리를 공유하는것으로 설정되어있습니다.

그래야지 메모리 낭비를 줄일 수있으니까요.!

import numpy as np

a = np.arange(5)
b = a

b[0] = 100

print(a)
print(b)

output은 역시 .view()를 이용할때와 같게 나옵니다.

 

 

flatten

많이 돌아 왔네요. 드디어 flatten에 대해서 알아보겠습니다. 

flatten은 말그대로 영어 뜻 그대로 평평하게 해주는 기능을 합니다.

 

import numpy as np

a = np.random.randint(0, 10, (2,3)) #0부터 9까지 2행 3열형태로 행렬을 만들어줍니다.

print('변경전 a \n',a)
b = a.flatten() # 그 행렬을 벡터 형태로 나열해줍니다.
b[0]= -10

print('변경후 a \n',a)
print('b ',b)

 

평탄화 작업(?) 을 마친 b의 1번째 값을 -10으로 변경 해보겠습니다

 

flatten 변경한 b의 1번째 원소만 변경이 되었습니다.

즉 flatten 메소드는 메모리를 복사(.copy())해서 다른 공간에 저장하기때문에 원본에는 변화가 없습니다.  

 

 

 

np.ravel

np.ravel 도 flatten가지로 평탄화(?) 작업을 해주는 api입니다.

flatten과 무엇이 다른지 한번 확인해보겠습니다.

 

import numpy as np

a = np.random.randint(0, 10, (2,3))
print('변경전 a \n',a)
b = a.ravel() 
b[0]= -10

print('변경후 a \n',a)
print('b ',b)

 

b값을 변경하자 거기에 상응하는 위치에있는 a 값도 같이 변경이 되어버리네요..

.flatten()과는 다르게  .ravel()은 같은 메모리를 공유한다는 것을 알 수 있습니다. 

 

.ravel 을 쓰고싶은데 메모리를 따로 쓰고싶다면.. .copy()를 이용하면 되겠지요?

아래 코드로 확인해볼게요.

import numpy as np

a = np.random.randint(0, 10, (2,3))
print('변경전 a \n',a)
b = a.ravel().copy() # ravel에 copy추가
b[0]= -10

print('변경후 a \n',a)
print('b ',b)

.flatten과 동일하게 출력되는 것을 확인할수 있네요.

 

 

.base 사용

flatten과 ravel 같이 기능은 같지만 메모리상 전혀 다른 동작을 하는 api들 중에는 reshape와 resize도 있습니다. 

우리가 모든 api들이 메모리상 어떤 동작을 하는지 확인할 수 없습니다. 

그때 필요한것이 이 base입니다. 

 

어떻게 동작하는지 확인해 보겠습니다. 

 

사용방법은 간단합니다. 

b.base is a 

b의 근간이 a에 있냐? 라고 묻는 겁니다.

 

False 이면 근간이 아니야! > 메모리공간을 따로쓴다

True 이면 근간이 맞아 > 같은 메모리 공간을 쓴다

import numpy as np

a = np.arange(4)
b = a.flatten()
print('변경전 ',b)

b[0] = 100

print('b.base :',b.base is a, '\n') 
print('a :',a)
print('변경후 ',b)

위와 같이 flatten 메소드를 이용한 값의 결과를 확인해보죠.

앞서 배운것처럼 copy개념인 flatten b.base is a가 False 가 나옵니다.

False가 나오면 메모리를 따로 쓴다! 라고 정리 하시면 되겠습니다. 

 

그럼 확인을 위해 ravel은 True 가 나오는지 볼까요?

 

import numpy as np

a = np.arange(4)
b = a.ravel()
print('변경전 ',b)

b[0] = 100

print('b.base :',b.base is a, '\n') 
print('a :',a)
print('변경후 ',b)

True! 를 확인할 수 있습니다. 

 

새로운 api를 만나거나 내가 데이터를 만지는데 뭔가.. 두렵다 싶으면 base를 적극 활용해 보세요!

 

 

 

이 글과 읽으면 좋은글

 

 

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

댓글