Użyj widoku i uzyskaj bezpłatne środowisko uruchomieniowe! Rozszerz n-dim
tablice ogólne don+1-dim
Wprowadzone w NumPy1.10.0
, możemy wykorzystać, numpy.broadcast_to
aby po prostu wygenerować 3D
widok w 2D
tablicy wejściowej. Korzyścią byłoby brak dodatkowego obciążenia pamięci i praktycznie wolne środowisko wykonawcze. Byłoby to istotne w przypadkach, gdy tablice są duże i możemy pracować z widokami. Działa to również w n-dim
przypadku ogólnych przypadków.
Użyłbym tego słowa stack
zamiast copy
, ponieważ czytelnicy mogliby pomylić je z kopiowaniem tablic, które tworzą kopie pamięci.
Stos wzdłuż pierwszej osi
Jeśli chcemy ułożyć dane wejściowe arr
wzdłuż pierwszej osi, rozwiązaniem np.broadcast_to
do utworzenia 3D
widoku byłoby -
np.broadcast_to(arr,(3,)+arr.shape) # N = 3 here
Stos wzdłuż trzeciej / ostatniej osi
Aby ułożyć dane wejściowe arr
wzdłuż trzeciej osi, rozwiązaniem do utworzenia 3D
widoku byłoby -
np.broadcast_to(arr[...,None],arr.shape+(3,))
Jeśli faktycznie potrzebujemy kopii pamięci, zawsze możemy ją .copy()
tam dołączyć . W związku z tym rozwiązania byłyby:
np.broadcast_to(arr,(3,)+arr.shape).copy()
np.broadcast_to(arr[...,None],arr.shape+(3,)).copy()
Oto jak działa układanie w stos dla dwóch przypadków, pokazane wraz z informacjami o ich kształcie dla przykładowej sprawy -
# Create a sample input array of shape (4,5)
In [55]: arr = np.random.rand(4,5)
# Stack along first axis
In [56]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[56]: (3, 4, 5)
# Stack along third axis
In [57]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[57]: (4, 5, 3)
Te same rozwiązania działałyby, gdyby rozszerzyć dane n-dim
wejściowe, aby n+1-dim
wyświetlić dane wyjściowe wzdłuż pierwszej i ostatniej osi. Zbadajmy kilka bardziej ciemnych przypadków -
Obudowa wejściowa 3D:
In [58]: arr = np.random.rand(4,5,6)
# Stack along first axis
In [59]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[59]: (3, 4, 5, 6)
# Stack along last axis
In [60]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[60]: (4, 5, 6, 3)
Obudowa wejściowa 4D:
In [61]: arr = np.random.rand(4,5,6,7)
# Stack along first axis
In [62]: np.broadcast_to(arr,(3,)+arr.shape).shape
Out[62]: (3, 4, 5, 6, 7)
# Stack along last axis
In [63]: np.broadcast_to(arr[...,None],arr.shape+(3,)).shape
Out[63]: (4, 5, 6, 7, 3)
i tak dalej.
Czasy
Wykorzystajmy duży przykładowy 2D
przypadek, pobierzmy czasy i sprawdźmy, czy wyjście jest plikiem view
.
# Sample input array
In [19]: arr = np.random.rand(1000,1000)
Udowodnijmy, że proponowane rozwiązanie jest rzeczywiście poglądem. Użyjemy układania wzdłuż pierwszej osi (wyniki byłyby bardzo podobne do układania wzdłuż trzeciej osi) -
In [22]: np.shares_memory(arr, np.broadcast_to(arr,(3,)+arr.shape))
Out[22]: True
Sprawdźmy czasy, aby pokazać, że jest to praktycznie bezpłatne -
In [20]: %timeit np.broadcast_to(arr,(3,)+arr.shape)
100000 loops, best of 3: 3.56 µs per loop
In [21]: %timeit np.broadcast_to(arr,(3000,)+arr.shape)
100000 loops, best of 3: 3.51 µs per loop
Będąc widokiem, zwiększając się N
z 3
do 3000
niczego nie zmienia się w czasie i oba są pomijalne w jednostkach czasowych. Dlatego wydajne zarówno pod względem pamięci, jak i wydajności!
b[:,:,0]
,b[:,:,1]
ib[:,:,2]
. Każdy trzeci wycinek wymiaru jest kopią oryginalnej szyku 2D. Nie jest to takie oczywiste samo patrzenieprint(b)
.