6.3. 배열 만들기¶
이 페이지 이후의 모든 예제는 이미 손에 들고 있는 ndarray로 시작합니다. 이 페이지는 그 배열이 어떻게 생겨나는지에 대한 카탈로그입니다. 생성자에는 네 가지 계열이 있습니다:
Python 이터러블로부터 – 일반적인 리터럴 / 리스트 / 튜플 형식.
주어진 형상으로 미리 채워짐 – 0, 1, 상수 값, 단위 행렬.
시퀀스로 생성됨 – 범위형 또는 균등 간격 값.
이미 RAM에 있는 버퍼를 래핑함 – 주변장치의 경우.
모든 생성자는 dtype= 키워드를 받으며 기본값은 float입니다. 센서 데이터는 거의 항상 기본값보다 작은 dtype을 원합니다.
아래의 모든 예제는 다음으로 시작합니다:
from ulab import numpy as np
6.3.1. Python 이터러블로부터¶
array()는 숫자로 이루어진 임의의 이터러블로부터 ndarray를 만듭니다:
a = np.array([1, 2, 3, 4])
print(a)
출력:
array([1.0, 2.0, 3.0, 4.0], dtype=float)
중첩 이터러블은 다차원 배열을 생성합니다. 내부 이터러블은 모두 같은 길이를 가져야 하며, 그렇지 않으면 ValueError가 발생합니다:
m = np.array([[1, 2, 3],
[4, 5, 6]], dtype=np.uint8)
기존의 ndarray 또한 유효한 입력입니다. array()는 항상 복사합니다. 복사가 필요하지 않을 때 이를 피하려면 asarray()를 사용하세요:
b = np.asarray(a, dtype=np.float) # same dtype -> no copy
6.3.2. 주어진 형상으로 미리 채워짐¶
대상 형상은 알려져 있지만 내용이 아직 정해지지 않았을 때는 버퍼를 미리 할당하고 나중에 그 안에 씁니다:
zeros()– 0으로 채워짐.ones()– 1로 채워짐.full()– 주어진 값으로 채워짐.eye()–k번째 대각선에 1이 있는 단위 행렬과 유사한NxM행렬.diag()– 벡터로부터 만든 대각 행렬, 또는 행렬의 대각선.
np.zeros((3, 3)) # 3x3 of zeros
np.ones(5, dtype=np.uint8) # length-5 vector of ones
np.full((2, 3), 7, dtype=np.int8) # 2x3, all 7
np.eye(4) # 4x4 identity
np.diag([1, 2, 3]) # 3x3, [1, 2, 3] on the diagonal
shape 인자는 단일 정수(1차원 배열의 경우)이거나 튜플입니다.
6.3.3. 시퀀스로 생성됨¶
arange()– 내장range()처럼 균등 간격 값을 생성하지만 항상ndarray를 반환합니다:np.arange(0, 10, 2) # array([0, 2, 4, 6, 8])linspace()– 두 경계 사이의num개 균등 간격 점으로,endpoint=True일 때 상한이 포함됩니다:np.linspace(0, 1, num=11) # 0.0, 0.1, ..., 1.0logspace()– 기하적으로 간격을 둔 점.start와stop은 끝점이 아니라 지수입니다. 결과는base ** start에서base ** stop까지 이어집니다:np.logspace(0, 3, num=4) # 1.0, 10.0, 100.0, 1000.0meshgrid()– 두 개의 1차원 배열로부터 두 개의 좌표 행렬을 만들어, 픽셀별 함수f(x, y)를 하나의 벡터화된 호출로 전체 그리드에 걸쳐 계산할 수 있게 합니다. 길이W의 x-벡터와 길이H의 y-벡터가 주어지면,meshgrid는 두 개의HxW행렬을 반환합니다.X는 모든 행에 걸쳐 아래로 반복된 x-벡터이고,Y는 모든 열에 걸쳐 반복된 y-벡터이므로,X[i, j]는 행i와 열j에 있는 셀의 x-좌표이고Y[i, j]는 y-좌표입니다:x = np.arange(4) # [0, 1, 2, 3] y = np.arange(3) # [0, 1, 2] X, Y = np.meshgrid(x, y) # X = [[0, 1, 2, 3], # [0, 1, 2, 3], # [0, 1, 2, 3]] # Y = [[0, 0, 0, 0], # [1, 1, 1, 1], # [2, 2, 2, 2]]
그러면
f(X, Y)는 하나의 표현식으로 그리드의 모든 셀에서 함수를 계산합니다. 예를 들어(H, W)프레임에 대한 중심으로부터의 거리 맵은meshgrid()가 반환한 행렬에 대해np.sqrt((X - cx)**2 + (Y - cy)**2)입니다.
6.3.4. 결합¶
concatenate()는 기존 축을 따라 배열의 튜플을 결합합니다:
a = np.array([[1, 2], [3, 4]], dtype=np.uint8)
b = np.array([[5, 6]], dtype=np.uint8)
np.concatenate((a, b), axis=0)
# array([[1, 2], [3, 4], [5, 6]], dtype=uint8)
모든 입력은 같은 dtype과 ndim을 공유해야 하며, 결합하는 축을 제외한 모든 축에서 일치해야 합니다. concatenate()는 모든 입력을 담을 만큼 충분히 큰 새 배열을 할당하고 데이터를 복사해 넣으므로, 이미 존재하는 배열을 일회성으로 결합하는 데 적합한 도구입니다. 스트리밍 루프 내부에서는 적합하지 않으며, 그곳에서는 대상을 한 번 미리 할당하고 슬라이스 할당을 통해 그 안에 쓰는 것이 패턴입니다.
6.3.5. 기존 버퍼 래핑하기¶
카메라에서 가장 유용한 생성자는 frombuffer()입니다. 이것은 기존의 bytes 유사 버퍼를 단 한 바이트도 복사하지 않고 1차원 ndarray로 재해석합니다:
buf = bytearray(8)
audio = np.frombuffer(buf, dtype=np.int16)
# 4 int16 samples, sharing memory with buf
audio를 통한 쓰기는 buf에서 보이며 그 반대도 마찬가지입니다. 선택한 dtype은 버퍼 길이를 균등하게 나누어야 합니다.
offset=은 버퍼 시작 부분의 헤더를 건너뛰고, count=는 읽는 요소의 개수를 제한합니다:
np.frombuffer(buf, dtype=np.uint8, offset=2, count=4)
이것은 주변장치가 애플리케이션에 원시 버퍼를 넘겨줄 때 적합한 생성자입니다 – bytearray의 ADC 샘플, SPI에서 가져온 페이로드. 주변장치가 쓴 바이트가 곧 배열입니다.
주변장치가 카메라의 CPU가 기본적으로 읽지 않는 바이트 순서로 다중 바이트 값을 쓸 때, byteswap()은 각 요소의 바이트 순서를 뒤집어 값이 올바르게 읽히도록 합니다. 기본적으로 새 배열을 반환하며, inplace=True를 전달하면 원본을 그 자리에서 수정합니다.
frombuffer()는 numpy 자체가 정의하는 dtype만 처리합니다. 32비트 정수 샘플을 생성하는 주변장치의 경우, from_int32_buffer() 및 관련 함수가 한 번에 float로 변환합니다.
6.3.6. 출력 잘림¶
큰 배열을 출력하면 처음과 마지막 몇 개 요소만 표시되고 가운데에 ...이 들어가므로, IDE 터미널이 수천 개의 값으로 가득 차지 않습니다:
>>> print(np.arange(1000, dtype=np.uint16))
array([0, 1, 2, ..., 997, 998, 999], dtype=uint16)
set_printoptions()는 디버깅 시 전체 버퍼가 필요할 때 임계값을 재정의합니다:
np.set_printoptions(threshold=2000) # print up to 2000 elements in full
np.set_printoptions(edgeitems=10) # 10 items at each end, not 3
get_printoptions()는 현재 설정을 dict로 다시 읽어옵니다.