Numpy: Teilen Sie jede Zeile durch ein Vektorelement

119

Angenommen, ich habe ein numpy-Array:

data = np.array([[1,1,1],[2,2,2],[3,3,3]])

und ich habe einen entsprechenden "Vektor":

vector = np.array([1,2,3])

Wie arbeite ich dataentlang jeder Zeile, um entweder zu subtrahieren oder zu dividieren, so dass das Ergebnis ist:

sub_result = [[0,0,0], [0,0,0], [0,0,0]]
div_result = [[1,1,1], [1,1,1], [1,1,1]]

Lange Rede, kurzer Sinn: Wie führe ich eine Operation für jede Zeile eines 2D-Arrays mit einem 1D-Array von Skalaren durch, die jeder Zeile entsprechen?

BFTM
quelle

Antworten:

181

Bitte schön. Sie müssen nur None(oder alternativ np.newaxis) kombiniert mit Rundfunk verwenden:

In [6]: data - vector[:,None]
Out[6]:
array([[0, 0, 0],
       [0, 0, 0],
       [0, 0, 0]])

In [7]: data / vector[:,None]
Out[7]:
array([[1, 1, 1],
       [1, 1, 1],
       [1, 1, 1]])
JoshAdel
quelle
13
Hier ist das Dokument.
Sazary
2
ein visuelles Beispiel
PlsWork
@ user108569 mit der neuesten Version von numpy (1.18.1) Nonefunktioniert immer noch gleichwertig mit np.newaxis. Ich bin nicht sicher, was Ihr Setup ist oder welches Problem Sie genau haben, aber die Antwort ist immer noch gültig.
JoshAdel
11

Wie bereits erwähnt, ist das Schneiden mit Noneoder mit np.newaxeseine großartige Möglichkeit, dies zu tun. Eine andere Alternative ist die Verwendung von Transponierungen und Rundfunk wie in

(data.T - vector).T

und

(data.T / vector).T

Für höherdimensionale Arrays können Sie die swapaxesMethode der NumPy-Arrays oder die NumPy- rollaxisFunktion verwenden. Es gibt wirklich viele Möglichkeiten, dies zu tun.

Eine ausführlichere Erklärung des Rundfunks finden Sie unter http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html

IanH
quelle
4

Die Lösung von JoshAdel verwendet np.newaxis, um eine Dimension hinzuzufügen. Eine Alternative besteht darin, reshape () zu verwenden, um die Dimensionen zur Vorbereitung der Übertragung auszurichten .

data = np.array([[1,1,1],[2,2,2],[3,3,3]])
vector = np.array([1,2,3])

data
# array([[1, 1, 1],
#        [2, 2, 2],
#        [3, 3, 3]])
vector
# array([1, 2, 3])

data.shape
# (3, 3)
vector.shape
# (3,)

data / vector.reshape((3,1))
# array([[1, 1, 1],
#        [1, 1, 1],
#        [1, 1, 1]])

Durch Ausführen der Umformung () können die Dimensionen für die Übertragung ausgerichtet werden:

data:            3 x 3
vector:              3
vector reshaped: 3 x 1

Beachten Sie, dass dies data/vectorin Ordnung ist, aber Sie nicht die gewünschte Antwort erhalten. Es teilt jede Spalte von array(anstelle jeder Zeile ) durch jedes entsprechende Element von vector. Es ist das, was Sie bekommen würden, wenn Sie explizit umgestalten würden vector, 1x3anstatt zu sein 3x1.

data / vector
# array([[1, 0, 0],
#        [2, 1, 0],
#        [3, 1, 1]])
data / vector.reshape((1,3))
# array([[1, 0, 0],
#        [2, 1, 0],
#        [3, 1, 1]])
stackoverflowuser2010
quelle
2

Der pythonische Weg, dies zu tun, ist ...

np.divide(data.T,vector).T

Dies sorgt für die Umformung und auch die Ergebnisse sind im Gleitkommaformat. In anderen Antworten liegen die Ergebnisse im gerundeten Ganzzahlformat vor.

#HINWEIS: Die Anzahl der Spalten in Daten und Vektor sollte übereinstimmen

Shantanu Pathak
quelle
Hinweis: Dies entspricht nicht den Anforderungen des OP. Das Endergebnis ist Array ([[1., 0.5, 0.33333333], [2., 1., 0.66666667], [3., 1.5, 1.]]). Es könnte 'Pythonic' sein, aber es ist falsch.
Mark Cramer
1
@ MarkCramer Danke. Ich habe meine Antwort korrigiert, um das richtige Ergebnis zu erzielen.
Shantanu Pathak
1

Hinzufügen zur Antwort von stackoverflowuser2010, im allgemeinen Fall können Sie nur verwenden

data = np.array([[1,1,1],[2,2,2],[3,3,3]])

vector = np.array([1,2,3])

data / vector.reshape(-1,1)

Dies verwandelt Ihren Vektor in einen column matrix/vector. So können Sie die elementweisen Operationen nach Ihren Wünschen ausführen. Zumindest für mich ist dies der intuitivste Weg, und da (in den meisten Fällen) numpy nur eine Ansicht desselben internen Speichers für die Umformung verwendet, ist dies auch effizient.

Miau
quelle
Dies sollte die akzeptierte Antwort sein. Das Erstellen eines Spaltenvektors mit .reshape(-1,1) ist die intuitivste Methode zur Verwendung von Broadcasting.
Paul Rougieux