6.3. Arrays maken¶
Elk voorbeeld op de rest van deze pagina’s begint met een ndarray die al in de hand is. Deze pagina is de catalogus van hoe die array tot stand komt. Er zijn vier families van constructors:
Vanuit een Python-iterable – de gebruikelijke literal / lijst / tuple-vorm.
Vooraf gevuld met een gegeven vorm – nullen, enen, een constante waarde, een eenheidsmatrix.
Gegenereerd als een reeks – waarden met een bereik of gelijkmatig verdeeld.
Een buffer omhullen die al in RAM staat – het randapparaatgeval.
Elke constructor neemt een dtype=-trefwoord aan en heeft standaard float. Sensordata wil vrijwel altijd een kleinere dtype dan de standaard.
Elk voorbeeld hieronder begint met:
from ulab import numpy as np
6.3.1. Vanuit een Python-iterable¶
array() bouwt een ndarray uit elke iterable van getallen:
a = np.array([1, 2, 3, 4])
print(a)
Uitvoer:
array([1.0, 2.0, 3.0, 4.0], dtype=float)
Geneste iterables produceren multidimensionale arrays. De binnenste iterables moeten allemaal dezelfde lengte hebben, anders wordt ValueError opgeworpen:
m = np.array([[1, 2, 3],
[4, 5, 6]], dtype=np.uint8)
Een reeds bestaande ndarray is ook een geldige invoer; array() kopieert altijd. Gebruik asarray() om de kopie te vermijden wanneer er geen nodig is:
b = np.asarray(a, dtype=np.float) # same dtype -> no copy
6.3.2. Vooraf gevuld met een gegeven vorm¶
Wanneer de doelvorm bekend is maar de inhoud nog niet, alloceer dan de buffer vooraf en schrijf er later in:
zeros()– gevuld met nullen.ones()– gevuld met enen.full()– gevuld met een gegeven waarde.empty()– alias voorzeros()(ulablaat de buffer niet ongeïnitialiseerd).eye()– eenheidsmatrix-achtigeN-bij-M-matrix met enen op dek-de diagonaal.diag()– een diagonaalmatrix uit een vector, of de diagonaal van een matrix.
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
Het shape-argument is ofwel een enkel geheel getal (voor een 1-D-array) of een tuple.
6.3.3. Gegenereerd als een reeks¶
arange()– gelijkmatig verdeelde waarden zoals de ingebouwderange(), maar geeft altijd eenndarrayterug:np.arange(0, 10, 2) # array([0, 2, 4, 6, 8])linspace()–numgelijkmatig verdeelde punten tussen twee grenzen, waarbij de bovengrens is inbegrepen wanneerendpoint=Truenp.linspace(0, 1, num=11) # 0.0, 0.1, ..., 1.0logspace()– geometrisch verdeelde punten.startenstopzijn exponenten, geen eindpunten; het resultaat loopt vanbase ** starttotbase ** stopnp.logspace(0, 3, num=4) # 1.0, 10.0, 100.0, 1000.0meshgrid()– bouwt twee coördinaatmatrices uit twee 1-D-arrays zodat een functie per pixelf(x, y)over een heel raster kan worden geëvalueerd in één gevectoriseerde aanroep. Gegeven een x-vector van lengteWen een y-vector van lengteH, geeftmeshgridtweeH-bij-W-matrices terug:Xis de x-vector herhaald langs elke rij,Yis de y-vector herhaald over elke kolom, zodatX[i, j]de x-coördinaat enY[i, j]de y-coördinaat is van de cel op rijien kolomjx = 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)evalueert vervolgens de functie op elke cel van het raster in één expressie. Een afstand-tot-het-midden-kaart over een(H, W)-frame is bijvoorbeeldnp.sqrt((X - cx)**2 + (Y - cy)**2)toegepast op de matrices diemeshgrid()teruggaf.
6.3.4. Samenvoegen¶
concatenate() voegt een tuple van arrays samen langs een bestaande as:
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)
Alle invoeren moeten dezelfde dtype en ndim delen, en overeenkomen op elke as behalve de samenvoegende. concatenate() alloceert een nieuwe array die groot genoeg is om elke invoer te bevatten en kopieert de data erin, dus het is het juiste gereedschap voor het in één keer samenvoegen van arrays die al bestaan; het is het verkeerde gereedschap binnen een streaming-lus, waar het vooraf eenmalig alloceren van de bestemming en daarin schrijven via slice-toewijzing het patroon is.
6.3.5. Een bestaande buffer omhullen¶
De nuttigste constructor op een camera is frombuffer(). Het herinterpreteert een bestaande bytes-achtige buffer als een 1-D ndarray zonder ook maar één byte te kopiëren
buf = bytearray(8)
audio = np.frombuffer(buf, dtype=np.int16)
# 4 int16 samples, sharing memory with buf
Schrijfacties via audio zijn zichtbaar in buf en vice versa. De gekozen dtype moet de bufferlengte gelijkmatig delen.
offset= slaat een header aan het begin van de buffer over; count= beperkt hoeveel elementen worden gelezen:
np.frombuffer(buf, dtype=np.uint8, offset=2, count=4)
Dit is de juiste constructor wanneer een randapparaat de applicatie een ruwe buffer overhandigt – ADC-samples in een bytearray, een payload opgehaald uit SPI. De bytes die het randapparaat schreef zijn de array.
Wanneer een randapparaat multi-byte-waarden schrijft in een byte-volgorde die de CPU van de camera niet van nature leest, keert byteswap() de byte-volgorde van elk element om zodat de waarden correct worden gelezen. Het geeft standaard een nieuwe array terug; het meegeven van inplace=True wijzigt de bron ter plekke.
frombuffer() verwerkt alleen de dtypes die numpy zelf definieert. Voor randapparaten die 32-bits integer-samples produceren, converteren from_int32_buffer() en verwanten in één doorloop naar float.
6.3.6. Print-afkapping¶
Het printen van een grote array toont alleen de eerste en laatste paar elementen, met ... in het midden, zodat de IDE-terminal niet volloopt met duizenden waarden:
>>> print(np.arange(1000, dtype=np.uint16))
array([0, 1, 2, ..., 997, 998, 999], dtype=uint16)
set_printoptions() overschrijft de drempelwaarden wanneer bij het debuggen de hele buffer nodig is:
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() leest de huidige instellingen terug als een dict.