이 문서를 읽기 위해서는 NumPy에 대한 기본적인 경험이 있어야 한다. 그래서 기본적 Numpy 배열의 기본구조 특히 메모리 레이아웃, 뷰, 복사(copy), 데이터타입등을 설명하려 한다.
dtype이 np.float32인 배열의 모든 값을 지우려는 간단한 예제를 생각해보자. 속도를 극대화하기 위해서는 어덯게 해야 할 까. 아래의 구문은 (적어도 NumPy에 익숙한 사람들에게는) 명확하지만, 우리가 원하는 건 속도다.
흥미롭게도 np.float64와 같은 더 큰 데이터 유형으로 배열을 캐스팅함으로써 25%의 속도요소를 얻었다. 그러나 배열을 바이트배열(np.int8)로 했을 때 50%의 속도향상이 있었다. 이러한 속도향상의 이유는 NumPy의 내부 구현과 컴파일러 최적화의 차이일 것이다. 이 예제는 NumPy의 철학을 보여준다.
ndarray는 NumPy의 다차원 배열객체로, N 개의 정수를 각 블록의 위치에 매핑하는 색인 체계를 가지고 있는 1차원 세그먼트로 구성이 된다. 다시 말해서 인덱스를 이용해서 접근 할 수 있는 연속적인 메모리블럭이다. N차원 배열을 1차원으로 환원하기 때문에 훨씬 빠르게 작동한다.
아래 코드는 9개의 int16 타입의 데이터 9개를 저장 할 수 있는, 3x3 2차원 배열을 만들었다.
2차원 이상의 배열을 탐색 할 때, 각 차원으로 이동 할 수 있는 정보를 담은 튜플이 필요하다. 이것을 strides라고 한다.
Z는 2차원배열이다. 이때 배열에 있는 데이터의 타입은 int16/2byte로 모두 동일하기 때문에, 1차원 세그먼트로 재 구성했을 때, 값을 빠르게 찾을 수 있다. 아이템의 크기가 2byte 이며, 하나의 배열이 3개의 아이템을 가지고 있다는 것만 알고 있으면 된다. 즉 이 경우 strides는 (6,2)가 된다.
View와 Copy는 최적화와 관련된 중요한 옵션이다. 앞 장에서 간단히 살펴보긴 했는데, 그 이상의 복잡한 내용들이 있다.
Direct and indirect access
먼저 indexing과 fancy indexing의 차이점을 살펴보겠다. 배열이 리턴을 할 경우 처음에는 항상 view를 리턴하고 그 다음에는 복사(copy)를 반환한다. 첫번째를 수정하면 원래 배열이 수정되지만 두 번째 반환 배열을 수정 할 경우 (원본은 그대로이고)복사본이 수정되기 때문에 숙지를 하고 있어야 한다.
위 예제는 3개의 intermediate 배열을 만들었다. 2*X의 결과와 2*Y의 결과가 저장되며, 마지막으로 2*X + 2*Y의 결과가 반환됐다. 이 경우에는 배열이 충분히 작아서 큰 차이가 나지 않는다. 하지만 배열이 큰 경우 이러한 식은 신중하게 사용해야한다. intermediate 배열은 최종 결과만 중요하고 나중에 X, Y가 필요하지 않은 경우에 적당하다.
Anatomy of an array
소개
메모리 레이아웃
View and copies
참고
numpy.arange
View and Copies
Direct and indirect access
Temporary copy
마무리
Recent Posts
Archive Posts
Tags