6.3. Creación de arrays¶
Cada ejemplo del resto de estas páginas comienza con un ndarray ya disponible. Esta página es el catálogo de cómo se crea ese array. Hay cuatro familias de constructores:
A partir de un iterable de Python – la habitual forma literal / lista / tupla.
Rellenado previamente con una forma dada – ceros, unos, un valor constante, una matriz identidad.
Generado como una secuencia – valores en un rango o espaciados uniformemente.
Envolviendo un búfer ya presente en RAM – el caso de los periféricos.
Cada constructor acepta una palabra clave dtype= y su valor predeterminado es float. Los datos de sensores casi siempre requieren un dtype más pequeño que el predeterminado.
Cada ejemplo de abajo comienza con:
from ulab import numpy as np
6.3.1. A partir de un iterable de Python¶
array() construye un ndarray a partir de cualquier iterable de números:
a = np.array([1, 2, 3, 4])
print(a)
Salida:
array([1.0, 2.0, 3.0, 4.0], dtype=float)
Los iterables anidados producen arrays multidimensionales. Los iterables internos deben tener todos la misma longitud, o se lanza ValueError:
m = np.array([[1, 2, 3],
[4, 5, 6]], dtype=np.uint8)
Un ndarray ya existente también es una entrada válida; array() siempre copia. Para evitar la copia cuando no es necesaria, usa asarray():
b = np.asarray(a, dtype=np.float) # same dtype -> no copy
6.3.2. Rellenado previamente con una forma dada¶
Cuando se conoce la forma de destino pero aún no el contenido, asigna el búfer por adelantado y escribe en él más tarde:
zeros()– relleno de ceros.ones()– relleno de unos.full()– relleno con un valor dado.empty()– alias dezeros()(ulabno deja el búfer sin inicializar).eye()– matriz deNporMsimilar a la identidad, con unos en lak-ésima diagonal.diag()– una matriz diagonal a partir de un vector, o la diagonal de una 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
El argumento shape es o bien un único entero (para un array de 1-D) o una tupla.
6.3.3. Generado como una secuencia¶
arange()– valores espaciados uniformemente como elrange()integrado, pero devolviendo siempre unndarray:np.arange(0, 10, 2) # array([0, 2, 4, 6, 8])linspace()–numpuntos espaciados uniformemente entre dos límites, con el límite superior incluido cuandoendpoint=True:np.linspace(0, 1, num=11) # 0.0, 0.1, ..., 1.0logspace()– puntos espaciados geométricamente.startystopson exponentes, no extremos; el resultado va desdebase ** starthastabase ** stop:np.logspace(0, 3, num=4) # 1.0, 10.0, 100.0, 1000.0meshgrid()– construye dos matrices de coordenadas a partir de dos arrays de 1-D para que una función por píxelf(x, y)pueda evaluarse sobre toda una cuadrícula en una sola llamada vectorizada. Dado un vector x de longitudWy un vector y de longitudH,meshgriddevuelve dos matrices deHporW:Xes el vector x repetido en cada fila,Yes el vector y repetido en cada columna, de modo queX[i, j]es la coordenada x eY[i, j]es la coordenada y de la celda en la filaiy la columnaj: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)evalúa entonces la función en cada celda de la cuadrícula en una sola expresión. Un mapa de distancia al centro sobre un fotograma de(H, W), por ejemplo, esnp.sqrt((X - cx)**2 + (Y - cy)**2)aplicado a las matrices que devolviómeshgrid().
6.3.4. Unión¶
concatenate() une una tupla de arrays a lo largo de un eje 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)
Todas las entradas deben compartir el mismo dtype y ndim, y coincidir en todos los ejes salvo el de unión. concatenate() asigna un array nuevo lo bastante grande para contener todas las entradas y copia los datos en él, por lo que es la herramienta adecuada para unir de una sola vez arrays que ya existen; es la herramienta equivocada dentro de un bucle de streaming, donde el patrón es preasignar el destino una vez y escribir en él mediante asignación por rebanadas.
6.3.5. Envolver un búfer existente¶
El constructor más útil en una cámara es frombuffer(). Reinterpreta un búfer existente de tipo bytes como un ndarray de 1-D sin copiar un solo byte:
buf = bytearray(8)
audio = np.frombuffer(buf, dtype=np.int16)
# 4 int16 samples, sharing memory with buf
Las escrituras a través de audio son visibles en buf y viceversa. El dtype elegido debe dividir exactamente la longitud del búfer.
offset= omite una cabecera al principio del búfer; count= limita cuántos elementos se leen:
np.frombuffer(buf, dtype=np.uint8, offset=2, count=4)
Este es el constructor adecuado siempre que un periférico entrega a la aplicación un búfer en bruto – muestras de un ADC en un bytearray, una carga útil extraída de SPI. Los bytes que el periférico escribió son el array.
Cuando un periférico escribe valores de varios bytes en un orden de bytes que la CPU de la cámara no lee de forma nativa, byteswap() invierte el orden de bytes de cada elemento para que los valores se lean correctamente. Por defecto devuelve un array nuevo; pasar inplace=True modifica el origen en el sitio.
frombuffer() solo maneja los dtypes que numpy define por sí mismo. Para periféricos que producen muestras enteras de 32 bits, from_int32_buffer() y similares convierten a float en una sola pasada.
6.3.6. Truncamiento de impresión¶
Al imprimir un array grande solo se muestran sus primeros y últimos elementos, con ... en medio, para que el terminal del IDE no se llene con miles de valores:
>>> print(np.arange(1000, dtype=np.uint16))
array([0, 1, 2, ..., 997, 998, 999], dtype=uint16)
set_printoptions() anula los umbrales cuando la depuración necesita el búfer 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() devuelve los ajustes actuales como un diccionario.