6.3. Criação de arrays¶
Todos os exemplos nas restantes páginas começam com um ndarray já disponível. Esta página é o catálogo de como esse array é criado. Existem quatro famílias de construtores:
A partir de um iterável Python – a forma habitual de literal / lista / tuplo.
Pré-preenchido com uma determinada forma – zeros, uns, um valor constante, uma matriz identidade.
Gerado como uma sequência – valores em intervalo ou com espaçamento uniforme.
A encapsular um buffer já em RAM – o caso periférico.
Todos os construtores aceitam a palavra-chave dtype= e assumem float por defeito. Os dados de sensor quase sempre necessitam de um dtype menor do que o predefinido.
Todos os exemplos abaixo começam com:
from ulab import numpy as np
6.3.1. A partir de um iterável Python¶
array() constrói um ndarray a partir de qualquer iterável de números:
a = np.array([1, 2, 3, 4])
print(a)
Saída:
array([1.0, 2.0, 3.0, 4.0], dtype=float)
Iteráveis aninhados produzem arrays multidimensionais. Os iteráveis internos devem ter todos o mesmo comprimento, caso contrário é levantada ValueError
m = np.array([[1, 2, 3],
[4, 5, 6]], dtype=np.uint8)
Um ndarray já existente é também um input válido; array() copia sempre. Para evitar a cópia quando não é necessária, use asarray()
b = np.asarray(a, dtype=np.float) # same dtype -> no copy
6.3.2. Pré-preenchido com uma determinada forma¶
Quando a forma pretendida é conhecida mas o conteúdo ainda não, aloque o buffer antecipadamente e escreva nele mais tarde:
zeros()– preenchido com zeros.ones()– preenchido com uns.full()– preenchido com um dado valor.empty()– alias dezeros()(ulabnão deixa o buffer não inicializado).eye()– matrizN-por-Msemelhante à identidade com uns nak-ésima diagonal.diag()– uma matriz diagonal a partir de um vetor, ou a diagonal de uma matriz.
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
O argumento shape é um inteiro simples (para um array 1-D) ou um tuplo.
6.3.3. Gerado como uma sequência¶
arange()– valores com espaçamento uniforme semelhante aorange()integrado, mas devolvendo sempre umndarraynp.arange(0, 10, 2) # array([0, 2, 4, 6, 8])linspace()–numpontos igualmente espaçados entre dois limites, com o limite superior incluído quandoendpoint=Truenp.linspace(0, 1, num=11) # 0.0, 0.1, ..., 1.0logspace()– pontos com espaçamento geométrico.startestopsão expoentes, não extremidades; o resultado vai debase ** startabase ** stopnp.logspace(0, 3, num=4) # 1.0, 10.0, 100.0, 1000.0meshgrid()– constrói duas matrizes de coordenadas a partir de dois arrays 1-D de modo a que uma função por pixelf(x, y)possa ser avaliada sobre toda uma grelha numa única chamada vetorizada. Dado um vetor-x de comprimentoWe um vetor-y de comprimentoH,meshgriddevolve duas matrizesH-por-W:Xé o vetor-x repetido em todas as linhas,Yé o vetor-y repetido em todas as colunas, pelo queX[i, j]é a coordenada x eY[i, j]é a coordenada y da célula na linhaie colunajx = 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)avalia então a função em cada célula da grelha numa única expressão. Um mapa de distância ao centro sobre um fotograma(H, W), por exemplo, énp.sqrt((X - cx)**2 + (Y - cy)**2)aplicado sobre as matrizes devolvidas pormeshgrid().
6.3.4. Concatenação¶
concatenate() junta um tuplo de arrays ao longo de um eixo existente:
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)
Todos os inputs devem partilhar o mesmo dtype e ndim, e coincidir em todos os eixos exceto o de concatenação. concatenate() aloca um novo array suficientemente grande para conter todos os inputs e copia os dados, sendo portanto a ferramenta certa para junção pontual de arrays já existentes; é a ferramenta errada dentro de um ciclo de streaming, onde o padrão correto é pré-alocar o destino uma vez e escrever nele através de atribuição por fatia.
6.3.5. A encapsular um buffer existente¶
O construtor mais útil numa câmara é frombuffer(). Reinterpreta um buffer do tipo bytes existente como um ndarray 1-D sem copiar um único byte:
buf = bytearray(8)
audio = np.frombuffer(buf, dtype=np.int16)
# 4 int16 samples, sharing memory with buf
As escritas através de audio são visíveis em buf e vice-versa. O dtype escolhido deve dividir o comprimento do buffer de forma exata.
offset= salta um cabeçalho no início do buffer; count= limita o número de elementos lidos:
np.frombuffer(buf, dtype=np.uint8, offset=2, count=4)
Este é o construtor correto sempre que um periférico entrega à aplicação um buffer em bruto – amostras de ADC num bytearray, um payload obtido de SPI. Os bytes escritos pelo periférico são o array.
Quando um periférico escreve valores de múltiplos bytes numa ordem de bytes que o CPU da câmara não lê nativamente, byteswap() inverte a ordem dos bytes de cada elemento para que os valores sejam lidos corretamente. Por defeito devolve um novo array; passando inplace=True modifica o original no lugar.
frombuffer() trata apenas os dtypes definidos pelo próprio numpy. Para periféricos que produzem amostras inteiras de 32 bits, from_int32_buffer() e funções semelhantes convertem para float numa única passagem.
6.3.6. Truncagem na impressão¶
A impressão de um array grande mostra apenas os primeiros e últimos elementos, com ... no meio, para que o terminal IDE não fique preenchido com milhares de valores:
>>> print(np.arange(1000, dtype=np.uint16))
array([0, 1, 2, ..., 997, 998, 999], dtype=uint16)
set_printoptions() substitui os limiares quando a depuração necessita do buffer completo:
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() lê as configurações atuais de volta como um dict.