6.3. Skapa arrayer¶
Varje exempel på resten av dessa sidor börjar med en ndarray redan i handen. Denna sida är katalogen över hur den arrayen blir till. Det finns fyra familjer av konstruktorer:
Från en Python-iterabel – den vanliga litteral-/list-/tupelformen.
Förfylld med en given form – nollor, ettor, ett konstant värde, en identitetsmatris.
Genererad som en sekvens – värden i ett intervall eller jämnt fördelade.
Omslutning av en buffert som redan finns i RAM – fallet med kringutrustning.
Varje konstruktor tar ett dtype=-nyckelord och har som standard float. Sensordata vill nästan alltid ha en mindre dtype än standardvärdet.
Varje exempel nedan börjar med:
from ulab import numpy as np
6.3.1. Från en Python-iterabel¶
array() bygger en ndarray från valfri iterabel av tal:
a = np.array([1, 2, 3, 4])
print(a)
Utdata:
array([1.0, 2.0, 3.0, 4.0], dtype=float)
Nästlade iterabler producerar flerdimensionella arrayer. De inre iterablerna måste alla ha samma längd, annars utlöses ValueError
m = np.array([[1, 2, 3],
[4, 5, 6]], dtype=np.uint8)
En redan befintlig ndarray är också en giltig indata; array() kopierar alltid. För att undvika kopian när den inte behövs, använd asarray()
b = np.asarray(a, dtype=np.float) # same dtype -> no copy
6.3.2. Förfylld med en given form¶
När målformen är känd men innehållet ännu inte är det, allokera bufferten i förväg och skriv in i den senare:
zeros()– fylld med nollor.ones()– fylld med ettor.full()– fylld med ett givet värde.empty()– alias förzeros()(ulablämnar inte bufferten oinitialiserad).eye()– identitetsliknandeN-gånger-M-matris med ettor på denk:te diagonalen.diag()– en diagonalmatris från en vektor, eller diagonalen i en matris.
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
Argumentet shape är antingen ett enskilt heltal (för en 1-D-array) eller en tupel.
6.3.3. Genererad som en sekvens¶
arange()– jämnt fördelade värden som den inbyggdarange(), men som alltid returnerar enndarraynp.arange(0, 10, 2) # array([0, 2, 4, 6, 8])linspace()–numjämnt fördelade punkter mellan två gränser, med den övre gränsen inkluderad närendpoint=Truenp.linspace(0, 1, num=11) # 0.0, 0.1, ..., 1.0logspace()– geometriskt fördelade punkter.startochstopär exponenter, inte ändpunkter; resultatet löper frånbase ** starttillbase ** stopnp.logspace(0, 3, num=4) # 1.0, 10.0, 100.0, 1000.0meshgrid()– bygger två koordinatmatriser från två 1-D-arrayer så att en per-pixel-funktionf(x, y)kan utvärderas över ett helt rutnät i ett enda vektoriserat anrop. Givet en x-vektor av längdWoch en y-vektor av längdH, returnerarmeshgridtvåH-gånger-W-matriser:Xär x-vektorn upprepad nedför varje rad,Yär y-vektorn upprepad tvärs över varje kolumn, så attX[i, j]är x-koordinaten ochY[i, j]är y-koordinaten för cellen på radioch kolumnjx = 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)utvärderar sedan funktionen i varje cell i rutnätet i ett enda uttryck. En karta över avstånd-från-centrum över en(H, W)-bildruta är till exempelnp.sqrt((X - cx)**2 + (Y - cy)**2)mot matriserna sommeshgrid()returnerade.
6.3.4. Sammanfogning¶
concatenate() sammanfogar en tupel av arrayer längs en befintlig axel:
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)
Alla indata måste dela samma dtype och ndim och matcha på varje axel utom den som sammanfogas. concatenate() allokerar en ny array som är tillräckligt stor för att rymma varje indata och kopierar in datan, så det är rätt verktyg för engångssammanfogning av arrayer som redan finns; det är fel verktyg inuti en strömmande loop, där mönstret är att förallokera destinationen en gång och skriva in i den via tilldelning till delar (slice assignment).
6.3.5. Omslutning av en befintlig buffert¶
Den mest användbara konstruktorn på en kamera är frombuffer(). Den omtolkar en befintlig byteliknande buffert som en 1-D ndarray utan att kopiera en enda byte:
buf = bytearray(8)
audio = np.frombuffer(buf, dtype=np.int16)
# 4 int16 samples, sharing memory with buf
Skrivningar via audio syns i buf och vice versa. Den valda dtype måste dela buffertlängden jämnt.
offset= hoppar över ett sidhuvud i början av bufferten; count= begränsar hur många element som läses:
np.frombuffer(buf, dtype=np.uint8, offset=2, count=4)
Detta är rätt konstruktor närhelst en kringutrustning lämnar över en rå buffert till applikationen – ADC-sampel i en bytearray, en nyttolast hämtad från SPI. De byte som kringutrustningen skrev är arrayen.
När en kringutrustning skriver flerbytesvärden i en byteordning som kamerans CPU inte läser nativt, vänder byteswap() byteordningen för varje element så att värdena läses korrekt. Den returnerar en ny array som standard; att ange inplace=True modifierar källan på plats.
frombuffer() hanterar endast de dtyper som numpy själv definierar. För kringutrustning som producerar 32-bitars heltalssampel konverterar from_int32_buffer() med flera till float i en enda omgång.
6.3.6. Avkortning av utskrift¶
Att skriva ut en stor array visar bara dess första och sista få element, med ... i mitten, så att IDE-terminalen inte fylls med tusentals värden:
>>> print(np.arange(1000, dtype=np.uint16))
array([0, 1, 2, ..., 997, 998, 999], dtype=uint16)
set_printoptions() åsidosätter tröskelvärdena när felsökning behöver hela bufferten:
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äser tillbaka de aktuella inställningarna som en dict.