6.3. Tworzenie tablic¶
Każdy przykład na pozostałych stronach zaczyna się od gotowej tablicy ndarray. Ta strona to katalog sposobów, w jakie taka tablica powstaje. Istnieją cztery rodziny konstruktorów:
Z iterowalnego obiektu Pythona – zwykła forma literału / listy / krotki.
Wstępnie wypełniona o danym kształcie – zera, jedynki, stała wartość, macierz jednostkowa.
Wygenerowana jako sekwencja – wartości z zakresu lub równomiernie rozłożone.
Opakowująca bufor już obecny w pamięci RAM – przypadek urządzenia peryferyjnego.
Każdy konstruktor przyjmuje słowo kluczowe dtype= i domyślnie używa float. Dane z sensorów prawie zawsze wymagają mniejszego dtype niż domyślny.
Każdy poniższy przykład zaczyna się od:
from ulab import numpy as np
6.3.1. Z iterowalnego obiektu Pythona¶
array() buduje ndarray z dowolnego iterowalnego obiektu liczb:
a = np.array([1, 2, 3, 4])
print(a)
Wynik:
array([1.0, 2.0, 3.0, 4.0], dtype=float)
Zagnieżdżone obiekty iterowalne tworzą tablice wielowymiarowe. Wewnętrzne obiekty iterowalne muszą mieć tę samą długość, w przeciwnym razie zgłaszany jest ValueError
m = np.array([[1, 2, 3],
[4, 5, 6]], dtype=np.uint8)
Istniejąca już ndarray jest również poprawnym wejściem; array() zawsze kopiuje. Aby uniknąć kopiowania, gdy nie jest potrzebne, użyj asarray()
b = np.asarray(a, dtype=np.float) # same dtype -> no copy
6.3.2. Wstępnie wypełniona o danym kształcie¶
Gdy docelowy kształt jest znany, ale zawartość jeszcze nie, zaalokuj bufor z wyprzedzeniem i zapisz do niego dane później:
zeros()– wypełniona zerami.ones()– wypełniona jedynkami.full()– wypełniona zadaną wartością.empty()– alias dlazeros()(ulabnie pozostawia bufora niezainicjalizowanego).eye()– macierzN-na-Mpodobna do jednostkowej, z jedynkami nak-tej przekątnej.diag()– macierz diagonalna z wektora lub przekątna macierzy.
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 jest albo pojedynczą liczbą całkowitą (dla tablicy 1-W), albo krotką.
6.3.3. Wygenerowana jako sekwencja¶
arange()– równomiernie rozłożone wartości jak wbudowanerange(), ale zawsze zwracającendarraynp.arange(0, 10, 2) # array([0, 2, 4, 6, 8])linspace()–numrównomiernie rozłożonych punktów między dwiema granicami, z dołączoną górną granicą, gdyendpoint=Truenp.linspace(0, 1, num=11) # 0.0, 0.1, ..., 1.0logspace()– punkty rozłożone geometrycznie.startistopsą wykładnikami, a nie punktami krańcowymi; wynik biegnie odbase ** startdobase ** stopnp.logspace(0, 3, num=4) # 1.0, 10.0, 100.0, 1000.0meshgrid()– buduje dwie macierze współrzędnych z dwóch tablic 1-W, tak aby funkcję per-pikself(x, y)można było obliczyć dla całej siatki w jednym wektoryzowanym wywołaniu. Dla wektora x o długościWi wektora y o długościHfunkcjameshgridzwraca dwie macierzeH-na-W:Xto wektor x powtórzony w każdym wierszu, aYto wektor y powtórzony w każdej kolumnie, więcX[i, j]jest współrzędną x, aY[i, j]współrzędną y komórki w wierszuii kolumniejx = 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)oblicza następnie funkcję w każdej komórce siatki w jednym wyrażeniu. Mapa odległości od środka dla ramki(H, W)to na przykładnp.sqrt((X - cx)**2 + (Y - cy)**2)na macierzach zwróconych przezmeshgrid().
6.3.4. Łączenie¶
concatenate() łączy krotkę tablic wzdłuż istniejącej osi:
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)
Wszystkie wejścia muszą mieć ten sam dtype i ndim oraz zgadzać się na każdej osi poza osią łączenia. concatenate() alokuje nową tablicę wystarczająco dużą, aby pomieścić każde wejście, i kopiuje do niej dane, więc jest właściwym narzędziem do jednorazowego łączenia istniejących już tablic; jest natomiast niewłaściwym narzędziem wewnątrz pętli strumieniowej, gdzie wzorcem jest jednorazowe wstępne zaalokowanie miejsca docelowego i zapisywanie do niego przez przypisanie wycinka.
6.3.5. Opakowywanie istniejącego bufora¶
Najbardziej przydatnym konstruktorem na kamerze jest frombuffer(). Reinterpretuje istniejący bufor bajtopodobny jako 1-W tablicę ndarray bez kopiowania ani jednego bajtu:
buf = bytearray(8)
audio = np.frombuffer(buf, dtype=np.int16)
# 4 int16 samples, sharing memory with buf
Zapisy przez audio są widoczne w buf i odwrotnie. Wybrany dtype musi równo dzielić długość bufora.
offset= pomija nagłówek na początku bufora; count= ogranicza liczbę odczytywanych elementów:
np.frombuffer(buf, dtype=np.uint8, offset=2, count=4)
To właściwy konstruktor, gdy urządzenie peryferyjne przekazuje aplikacji surowy bufor – próbki z ADC w bytearray, ładunek pobrany z SPI. Bajty zapisane przez urządzenie peryferyjne są tą tablicą.
Gdy urządzenie peryferyjne zapisuje wartości wielobajtowe w kolejności bajtów, której procesor kamery nie odczytuje natywnie, byteswap() odwraca kolejność bajtów każdego elementu, tak aby wartości odczytywały się poprawnie. Domyślnie zwraca nową tablicę; przekazanie inplace=True modyfikuje źródło w miejscu.
frombuffer() obsługuje tylko dtype, które definiuje samo numpy. Dla urządzeń peryferyjnych produkujących 32-bitowe próbki całkowitoliczbowe from_int32_buffer() i pokrewne funkcje konwertują do float w jednym przebiegu.
6.3.6. Skracanie wydruku¶
Wydruk dużej tablicy pokazuje tylko jej kilka pierwszych i ostatnich elementów, z ... w środku, aby terminal IDE nie zapełnił się tysiącami wartości:
>>> print(np.arange(1000, dtype=np.uint16))
array([0, 1, 2, ..., 997, 998, 999], dtype=uint16)
set_printoptions() nadpisuje progi, gdy debugowanie wymaga całego bufora:
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() odczytuje bieżące ustawienia jako słownik.