6.3. Vytváření polí¶
Každý příklad na zbytku těchto stránek začíná tím, že již máme po ruce ndarray. Tato stránka je katalogem toho, jak takové pole vznikne. Existují čtyři rodiny konstruktorů:
Z Python iterovatelného objektu – obvyklá forma literálu / seznamu / n-tice.
Předvyplněné na daný tvar – nuly, jedničky, konstantní hodnota, jednotková matice.
Vygenerované jako posloupnost – hodnoty v rozsahu nebo rovnoměrně rozložené.
Zabalení bufferu, který už je v RAM – případ periferie.
Každý konstruktor přijímá klíčové slovo dtype= a má výchozí hodnotu float. Data ze senzorů téměř vždy chtějí menší dtype, než je výchozí.
Každý níže uvedený příklad začíná takto:
from ulab import numpy as np
6.3.1. Z Python iterovatelného objektu¶
array() sestaví ndarray z libovolného iterovatelného objektu obsahujícího čísla:
a = np.array([1, 2, 3, 4])
print(a)
Výstup:
array([1.0, 2.0, 3.0, 4.0], dtype=float)
Vnořené iterovatelné objekty produkují vícerozměrná pole. Vnitřní iterovatelné objekty musí mít všechny stejnou délku, jinak je vyvolána výjimka ValueError
m = np.array([[1, 2, 3],
[4, 5, 6]], dtype=np.uint8)
Platným vstupem je i již existující ndarray; array() vždy kopíruje. Pokud se chcete kopii vyhnout, když není potřeba, použijte asarray()
b = np.asarray(a, dtype=np.float) # same dtype -> no copy
6.3.2. Předvyplněné na daný tvar¶
Když je cílový tvar známý, ale obsah ještě ne, alokujte buffer předem a zapisujte do něj později:
zeros()– vyplněné nulami.ones()– vyplněné jedničkami.full()– vyplněné danou hodnotou.empty()– alias prozeros()(ulabnenechává buffer neinicializovaný).eye()– maticeN-krát-Mpodobná jednotkové s jedničkami nak-té diagonále.diag()– diagonální matice z vektoru, nebo diagonála matice.
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
Argument shape je buď jediné celé číslo (pro 1-D pole), nebo n-tice.
6.3.3. Vygenerované jako posloupnost¶
arange()– rovnoměrně rozložené hodnoty jako u vestavěné funkcerange(), ale vždy vracejícíndarraynp.arange(0, 10, 2) # array([0, 2, 4, 6, 8])linspace()–numrovnoměrně rozložených bodů mezi dvěma mezemi, s horní mezí zahrnutou, pokud jeendpoint=Truenp.linspace(0, 1, num=11) # 0.0, 0.1, ..., 1.0logspace()– geometricky rozložené body.startastopjsou exponenty, nikoli koncové body; výsledek probíhá odbase ** startdobase ** stopnp.logspace(0, 3, num=4) # 1.0, 10.0, 100.0, 1000.0meshgrid()– sestaví dvě souřadnicové matice ze dvou 1-D polí, takže lze funkci na pixelf(x, y)vyhodnotit nad celou mřížkou v jediném vektorizovaném volání. Při zadání x-vektoru délkyWa y-vektoru délkyHvracímeshgriddvě maticeH-krát-W:Xje x-vektor opakovaný v každém řádku,Yje y-vektor opakovaný v každém sloupci, takžeX[i, j]je x-souřadnice aY[i, j]je y-souřadnice buňky v řádkuia sloupcijx = 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)pak vyhodnotí funkci v každé buňce mřížky v jediném výrazu. Mapa vzdálenosti od středu nad snímkem(H, W)je napříkladnp.sqrt((X - cx)**2 + (Y - cy)**2)proti maticím, které funkcemeshgrid()vrátila.
6.3.4. Spojování¶
concatenate() spojí n-tici polí podél existující osy:
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)
Všechny vstupy musí sdílet stejný dtype a ndim a shodovat se na každé ose kromě té spojované. concatenate() alokuje nové pole dostatečně velké, aby pojalo každý vstup, a data do něj zkopíruje, takže je to správný nástroj pro jednorázové spojení polí, která už existují; je to nesprávný nástroj uvnitř streamovací smyčky, kde je vzorem jednorázová předalokace cíle a zápis do něj pomocí přiřazení do řezu.
6.3.5. Zabalení existujícího bufferu¶
Nejužitečnějším konstruktorem na kameře je frombuffer(). Reinterpretuje existující buffer podobný bytes jako 1-D ndarray bez kopírování jediného bajtu:
buf = bytearray(8)
audio = np.frombuffer(buf, dtype=np.int16)
# 4 int16 samples, sharing memory with buf
Zápisy přes audio jsou viditelné v buf a naopak. Zvolený dtype musí délku bufferu beze zbytku dělit.
offset= přeskočí hlavičku na začátku bufferu; count= omezuje, kolik prvků se přečte:
np.frombuffer(buf, dtype=np.uint8, offset=2, count=4)
Toto je správný konstruktor, kdykoli periferie předá aplikaci surový buffer – vzorky z ADC v bytearray, data získaná z SPI. Bajty, které periferie zapsala, jsou tím polem.
Když periferie zapisuje vícebajtové hodnoty v pořadí bajtů, které CPU kamery nativně nečte, byteswap() obrátí pořadí bajtů každého prvku, takže se hodnoty čtou správně. Ve výchozím nastavení vrací nové pole; předání inplace=True upraví zdroj na místě.
frombuffer() zvládá jen dtypy, které numpy sám definuje. Pro periferie produkující 32bitové celočíselné vzorky převedou from_int32_buffer() a příbuzné funkce data na float v jednom průchodu.
6.3.6. Zkracování výpisu¶
Výpis velkého pole zobrazí jen jeho prvních a posledních několik prvků s ... uprostřed, takže se terminál IDE nezaplní tisíci hodnot:
>>> print(np.arange(1000, dtype=np.uint16))
array([0, 1, 2, ..., 997, 998, 999], dtype=uint16)
set_printoptions() přepíše prahy, když ladění potřebuje celý buffer:
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() načte aktuální nastavení zpět jako slovník.