2013-07-10 13 views
10

Rozważ następujące ćwiczenie w nadawaniu tablicy Numpy.Numpy, python: automatyczne rozszerzanie wymiarów tablic podczas emisji

import numpy as np 
v = np.array([[1.0, 2.0]]).T # column array 

A2 = np.random.randn(2,10) # 2D array 
A3 = np.random.randn(2,10,10) # 3D 

v * A2 # works great 

# causes error: 
v * A3 # error 

Znam zasady NumPy nadawczych i jestem zaznajomiony z bsxfun funkcjonalność w Matlab. Rozumiem, dlaczego próba nadania tablicy (2,1) do tablicy (2, N, N) kończy się niepowodzeniem, i że muszę przekształcić tablicę (2,1) w tablicę (2,1,1) przed tym nadawanie przechodzi.

Moje pytanie brzmi: czy jest jakiś sposób, aby powiedzieć Pythonowi, aby automatycznie podkładał wymiarowość tablicy podczas próby emisji, bez konieczności wyraźnego wymawiania jej koniecznego wymiaru?

I nie chce jednoznacznie para The (2,1) wektor z wielowymiarowej tablicy to będzie transmitowane na --- inaczej mógłby zrobić coś głupiego i absurdalnie brzydki jak mult_v_A = lambda v,A: v.reshape([v.size] + [1]*(A.ndim-1)) * A. Nie wiem z góry, czy tablica "A" będzie 2D, 3D czy N-D.

Funkcja nadawania Matlab'a bsxfun niejawnie podkłada wymiary w razie potrzeby, więc mam nadzieję, że jest coś, co mógłbym zrobić w Pythonie.

+4

Mój pogląd jest taki, że jest to funkcja, a nie błąd. Załóżmy na przykład, że masz wektor kolumnowy "v" 2 na 1, a potem masz "ndarray" 2 na 2 na 10. Czy chcesz przekształcić 'v', aby miał kształt' (2,1,1) 'lub kształt' (1,2,1) '? Jeśli po prostu podmienisz wymiary, może to być niejednoznaczne dla użytkownika. Wymuszenie wyraźnej zmiany kształtu jest lepszą ogólną procedurą i pozostawienie użytkownikowi funkcji specjalnej do automatycznego przekształcania, jeśli użytkownik ma ustaloną konwencję. Ale nie jest dobrze tworzyć globalny "numpy", który wymusza na tobie konwencję. Zbyt łatwo byłoby nadużywać. – ely

+0

-1 @EMS. Ta niejednoznaczność jest łatwo rozwiązana przez określenie, że pierwszy wymiar nie-singletonowy będzie używany w transmisji. Taka postawa "w ten sposób jest lepsza" jest całkowicie nieodpowiednia dla systemów używanych przez profesjonalnych programistów i matematyków stosowanych --- jest to wada pod względem nieczytelności i complectedness, a nie cechą. –

+0

-1 @Ahmed Fasih. Jestem matematykiem stosującym się do codziennego pisania kodu Pythona do zastosowań naukowych i uważam, że proponowana przez ciebie konwencja zawsze przyjmująca pierwszy wymiar nie singletonowy byłaby bardzo słaba. Znacznie lepiej jest napisać funkcję, która przyjmuje tę konwencję niż dla programistów NumPy, aby martwić się o kodowanie konwencji takiej, która przynosi korzyści niektórym użytkownikom (takim jak Ty), ale nie byłaby przydatna dla niektórych innych użytkowników (takich jak ja). – ely

Odpowiedz

9

Jest brzydki, ale to będzie działać :

(v.T * A3.T).T 

Jeśli nie dają mu żadnych argumentów, transpozycji odwraca kształt krotki, więc można teraz liczyć na zasadach nadawania wykonywać swoją magię. Ostatnia transpozycja przywraca wszystko do właściwej kolejności.

+1

To jest faktycznie mniej brzydki niż to, co miałem po przestudiowaniu odpowiedzi @ unutbu, który był 'np.swapaxes (v.T * np.swapaxes (A3,0, -1), 0, -1)'! Wiedząc, że transponuje odwroty, wszystkie wymiary sprawiają, że jest to o wiele starsze. Przynajmniej użytkownicy zobaczą te transpozycje i miejmy nadzieję, że "OK, tutaj odbywa się nadawanie z niewielkim akcentem funkcyjności, aby wymiary były wyrównane, ok, jestem w porządku". Dzięki, szefie. –

8

Transmisja NumPy dodaje dodatkowe osie po lewej stronie.

Więc jeśli zorganizować swoje tablice więc wspólne osie są po prawej i broadcastable osie są po lewej stronie, a następnie można użyć nadawanie bez problemu:

import numpy as np 
v = np.array([[1.0, 2.0]]) # shape (1, 2) 

A2 = np.random.randn(10,2) # shape (10, 2) 
A3 = np.random.randn(10,10,2) # shape (10, 10, 2) 

v * A2 # shape (10, 2) 

v * A3 # shape (10, 10, 2) 
+0

To przynajmniej jest rozwiązaniem połowicznym. Ustalona konwencja w mojej aplikacji jest niestety taka, że ​​wektory takie jak "v" są tablicami kolumn. Zakładając, że nie chciałem zreorganizować kodu (i moich użytkowników), aby oczekiwać tablic wierszy, zastanawiam się, czy funkcja, która zamienia wymiary na wielokrotność transmisji, jest naprawdę mniej dowolna niż operacja przekształcania, która przeplata 'A' i' v' w moim oryginalnym wpisie. –

+0

Czy jest jakiś powód, dla którego Numpy dodaje wymiary po lewej, ale nie po prawej? Wydaje się to arbitralne, ale być może jest jakieś ważne uzasadnienie związane z pamięcią lub algebrą? –

+0

Być może odpowiadając na moje (pod) pytanie, czy to dlatego, że emisja rozpoczyna się od wymiarów śledzących tablic i działa w lewo, i dodaje wymiary w razie potrzeby, o ile zasady są spełnione? Ciekawy! –

Powiązane problemy