2013-07-10 9 views
10

Betrachten Sie die folgende Übung in Numpy Array Broadcasting.Numpy, Python: Abmessungen von Arrays automatisch beim Senden erweitern

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 

Ich kenne die Numpy Regeln für den digitalen Rundfunk und ich bin vertraut mit bsxfun Funktionalität in Matlab. Ich verstehe, warum der Versuch, ein (2,1) -Array in ein (2, N, N) -Array zu übertragen, fehlschlägt, und dass ich das (2,1) -Array vorher in ein (2,1,1) -Array umformen muss Sendung geht durch.

Meine Frage ist: Gibt es irgendeine Möglichkeit, Python zu sagen, die Dimensionalität eines Arrays automatisch zu paddern, wenn es versucht, zu übertragen, ohne dass ich ihm die notwendige Dimension spezifisch mitteilen muss?

ich will nicht explizit Paar den (2,1) Vektor mit dem mehrdimensionalen Array gegen werden, es wird ausgestrahlt --- sonst ich etwas dumm und absurd hässlich wie mult_v_A = lambda v,A: v.reshape([v.size] + [1]*(A.ndim-1)) * A tun könnte. Ich weiß nicht vorher, ob das "A" -Array 2D oder 3D oder N-D sein wird.

Matlabs bsxfun Broadcasting-Funktion füllt implizit die Dimensionen wie benötigt, also hoffe ich, dass ich etwas in Python machen kann.

+4

Meine Ansicht ist, dass dies eine Funktion und kein Fehler ist. Nehmen wir beispielsweise an, Sie hätten einen 2-mal-1-Spaltenvektor "v" und dann hätten Sie ein 2-mal-2-mal-10 "ndarray". Möchten Sie 'v' umformen' (2,1,1) 'oder Form' (1,2,1) '? Wenn Sie nur die Dimensionen auffüllen, könnte dies für den Benutzer mehrdeutig sein. Das Erzwingen einer expliziten Umformung ist ein besseres allgemeines Verfahren und überlässt es dem Benutzer, eine spezielle Funktion zu schreiben, um die Umformung automatisch durchzuführen, wenn der Benutzer eine feste Konvention hat. Aber es ist nicht gut, einen globalen "numpigen" Dimensions-Padder zu machen, der eine Konvention auf dich drängt. Es wäre zu leicht zu missbrauchen. – ely

+0

-1 @EMS. Diese Mehrdeutigkeit wird leicht gelöst, indem spezifiziert wird, dass die erste Nicht-Singleton-Dimension in der Übertragung verwendet wird. Diese Haltung von "So ist es besser" ist völlig ungeeignet für Systeme, die von professionellen Programmierern und angewandten Mathematikern verwendet werden - das ist ein Fehler in Bezug auf Unlesbarkeit und Vollständigkeit, kein Merkmal. –

+0

-1 @Ahmed Fashih. Ich bin ein angewandter Mathematiker, der jeden Tag Python-Code für wissenschaftliche Anwendungen schreibt, und ich glaube, dass Ihre vorgeschlagene Konvention, immer die erste Nicht-Singleton-Dimension zu übernehmen, sehr schlecht wäre. Viel besser für Sie, eine Funktion zu schreiben, die diese Konvention annimmt, als für NumPy-Entwickler, die sich Gedanken darüber machen, eine Konvention wie die, die einigen Benutzern (wie Ihnen) Vorteile bringt, zu schreiben, aber für andere Benutzer (wie mich) nicht nützlich wäre. – ely

Antwort

9

Es ist hässlich, aber dies funktionieren wird :

(v.T * A3.T).T 

Wenn Sie irgendwelche Argumente geben es nicht, Transponieren kehrt die Form Tupel, so dass Sie jetzt auf den Rundfunk Regeln verlassen können ihre Magie zu tun. Die letzte Transponierung gibt alles in der richtigen Reihenfolge zurück.

+1

Es ist tatsächlich weniger hässlich als das, was ich nach dem Studium von @ unutbu's Antwort hatte, die 'np.swapaxes (v.T * np.swapaxes (A3,0, -1), 0, -1) 'war! Zu wissen, dass die Transponierung alle Dimensionen umkehrt, macht das viel besser. Wenigstens werden die Benutzer diese Transpositionen sehen und hoffentlich denken "Ok, es gibt hier eine Sendung, mit einem winzigen Hauch von Funkiness, um die Dimensionen in Ordnung zu bringen, ok, mir geht es gut". Danke Chef. –

8

NumPy Broadcasting fügt zusätzliche Achsen auf der linken Seite hinzu.

Also, wenn Sie Ihre Arrays anordnen, so dass die gemeinsamen Achsen auf der rechten Seite und die sende Achsen sind auf der linken Seite, dann können Sie Rundfunk ohne Probleme verwenden:

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

Dies ist zumindest eine halbwegs Lösung. Die etablierte Konvention in meiner Anwendung ist leider, dass Vektoren wie 'v' Spaltenarrays sind. Angenommen, ich wollte den Code (und meine Benutzer) nicht auf Zeilenarrays umstellen, diskutiere ich, ob eine Funktion, die Dimensionen tauscht, um eine Broadcast-Multiplikation auszuführen, wirklich weniger komplex ist als eine Umformoperation, die "A" und " v' in meinem ursprünglichen Beitrag. –

+0

Gibt es einen Grund, warum Numpy links Dimensionen hinzufügt, aber nicht auf der rechten Seite? Es scheint willkürlich, aber vielleicht gibt es einige wichtige Gründe in Bezug auf Gedächtnis oder Algebra? –

+0

Möglicherweise meine eigene (Teil-) Frage zu beantworten, liegt es daran, dass der Rundfunk bei den nachlaufenden Dimensionen der Arrays beginnt und nach links arbeitet, und fügt bei Bedarf weitere Dimensionen hinzu, solange die Regeln eingehalten werden? Interessant! –