Prawdopodobnie najczystszym sposobem jest użycie np.repeat
:
a = np.array([[1, 2], [1, 2]])
print(a.shape)
# (2, 2)
# indexing with np.newaxis inserts a new 3rd dimension, which we then repeat the
# array along, (you can achieve the same effect by indexing with None, see below)
b = np.repeat(a[:, :, np.newaxis], 3, axis=2)
print(b.shape)
# (2, 2, 3)
print(b[:, :, 0])
# [[1 2]
# [1 2]]
print(b[:, :, 1])
# [[1 2]
# [1 2]]
print(b[:, :, 2])
# [[1 2]
# [1 2]]
Powiedziawszy to, często można całkowicie uniknąć powtarzania tablic, używając rozgłaszania . Na przykład, powiedzmy, że chcę dodać (3,)
wektor:
c = np.array([1, 2, 3])
do a
. Mogłem skopiować zawartość a
3 razy w trzecim wymiarze, a następnie skopiować zawartość c
dwukrotnie w pierwszym i drugim wymiarze, tak aby obie moje tablice były (2, 2, 3)
, a następnie obliczyć ich sumę. Jest to jednak znacznie prostsze i szybsze:
d = a[..., None] + c[None, None, :]
Tutaj a[..., None]
ma kształt (2, 2, 1)
i c[None, None, :]
ma kształt (1, 1, 3)
*. Kiedy obliczam sumę, wynik jest `` rozrzucany '' wzdłuż wymiarów rozmiaru 1, dając mi wynik kształtu (2, 2, 3)
:
print(d.shape)
# (2, 2, 3)
print(d[..., 0]) # a + c[0]
# [[2 3]
# [2 3]]
print(d[..., 1]) # a + c[1]
# [[3 4]
# [3 4]]
print(d[..., 2]) # a + c[2]
# [[4 5]
# [4 5]]
Rozgłaszanie jest bardzo skuteczną techniką, ponieważ pozwala uniknąć dodatkowego obciążenia związanego z tworzeniem powtarzających się kopii tablic wejściowych w pamięci.
* Chociaż włączyłem je dla jasności, None
indeksy w c
nie są w rzeczywistości potrzebne - możesz to zrobić a[..., None] + c
, np. Rozgłaszać (2, 2, 1)
tablicę względem (3,)
tablicy. Dzieje się tak, ponieważ jeśli jedna z tablic ma mniej wymiarów niż druga, to tylko końcowe wymiary dwóch tablic muszą być zgodne. Aby podać bardziej skomplikowany przykład:
a = np.ones((6, 1, 4, 3, 1)) # 6 x 1 x 4 x 3 x 1
b = np.ones((5, 1, 3, 2)) # 5 x 1 x 3 x 2
result = a + b # 6 x 5 x 4 x 3 x 2
b[:,:,0]
,b[:,:,1]
ib[:,:,2]
. Każdy trzeci wycinek wymiaru jest kopią oryginalnej szyku 2D. Nie jest to takie oczywiste samo patrzenieprint(b)
.np.newaxis
to tylko aliasNone
Innym sposobem jest użycie
numpy.dstack
. Przypuśćmy, że chcesz powtórzyća
num_repeats
czasy macierzy :Sztuczka polega na zawinięciu macierzy
a
w listę pojedynczego elementu, a następnie użycie*
operatora do zduplikowania elementów z tej listynum_repeats
razy.Na przykład, jeśli:
Powtarza to tablicę
[1 2; 1 2]
5 razy w trzecim wymiarze. Aby zweryfikować (w IPythonie):Na końcu widzimy, że kształt matrycy jest
2 x 2
z 5 warstwami w trzecim wymiarze.źródło
reshape
? Szybciej? daje taką samą strukturę? Jest zdecydowanie schludniej.Użyj widoku i uzyskaj bezpłatne środowisko uruchomieniowe! Rozszerz
n-dim
tablice ogólne don+1-dim
Wprowadzone w NumPy
1.10.0
, możemy wykorzystać,numpy.broadcast_to
aby po prostu wygenerować3D
widok w2D
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ż wn-dim
przypadku ogólnych przypadków.Użyłbym tego słowa
stack
zamiastcopy
, 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ązaniemnp.broadcast_to
do utworzenia3D
widoku byłoby -Stos wzdłuż trzeciej / ostatniej osi
Aby ułożyć dane wejściowe
arr
wzdłuż trzeciej osi, rozwiązaniem do utworzenia3D
widoku byłoby -Jeśli faktycznie potrzebujemy kopii pamięci, zawsze możemy ją
.copy()
tam dołączyć . W związku z tym rozwiązania byłyby: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 -
Te same rozwiązania działałyby, gdyby rozszerzyć dane
n-dim
wejściowe, abyn+1-dim
wyświetlić dane wyjściowe wzdłuż pierwszej i ostatniej osi. Zbadajmy kilka bardziej ciemnych przypadków -Obudowa wejściowa 3D:
Obudowa wejściowa 4D:
i tak dalej.
Czasy
Wykorzystajmy duży przykładowy
2D
przypadek, pobierzmy czasy i sprawdźmy, czy wyjście jest plikiemview
.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) -
Sprawdźmy czasy, aby pokazać, że jest to praktycznie bezpłatne -
Będąc widokiem, zwiększając się
N
z3
do3000
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!źródło
Edytuj @ Mr.F, aby zachować kolejność wymiarów:
źródło
B.shape
Drukuje(N, 2, 2)
dla dowolnej wartościN
. Jeśli dokonasz transpozycjiB
z,B.T
to pasuje do oczekiwanego wyniku.B[0], B[1],...
da ci właściwy wycinek, który będę argumentować i powiem, że jest łatwiejszy doB[:,:,0], B[:,:,1]
B[:,:,i]
i do tego jestem przyzwyczajony.Oto przykład nadawania, który robi dokładnie to, o co proszono.
Następnie
b*a
jest pożądany rezultat i(b*a)[:,:,0]
produkujearray([[1, 2],[1, 2]])
, który jest oryginałema
, tak jak robi(b*a)[:,:,1]
, itd.źródło
Można to teraz również osiągnąć za pomocą np.tile w następujący sposób:
źródło