Der wahrscheinlich sauberste Weg ist 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]]
Trotzdem können Sie häufig vermeiden, Ihre Arrays mithilfe von Broadcasting vollständig zu wiederholen . Angenommen, ich wollte einen (3,)
Vektor hinzufügen :
c = np.array([1, 2, 3])
zu a
. Ich konnte den Inhalt von a
3 Mal in der dritten Dimension kopieren und dann den Inhalt von c
zweimal sowohl in der ersten als auch in der zweiten Dimension kopieren , so dass meine beiden Arrays waren (2, 2, 3)
, und dann ihre Summe berechnen. Dies ist jedoch viel einfacher und schneller:
d = a[..., None] + c[None, None, :]
Hier a[..., None]
hat Form (2, 2, 1)
und c[None, None, :]
hat Form (1, 1, 3)
*. Wenn ich die Summe berechne, wird das Ergebnis entlang der Abmessungen der Größe 1 "ausgestrahlt", was mir ein Ergebnis der Form gibt (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]]
Broadcasting ist eine sehr leistungsfähige Technik, da der zusätzliche Aufwand für das Erstellen wiederholter Kopien Ihrer Eingabearrays im Speicher vermieden wird.
* Obwohl ich sie aus Gründen der Übersichtlichkeit eingefügt habe, sind die None
Indizes in c
nicht wirklich erforderlich - Sie können dies auch tun a[..., None] + c
, dh ein (2, 2, 1)
Array gegen ein (3,)
Array senden . Dies liegt daran, dass, wenn eines der Arrays weniger Dimensionen als das andere hat, nur die nachfolgenden Dimensionen der beiden Arrays kompatibel sein müssen. Um ein komplizierteres Beispiel zu geben:
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]
undb[:,:,2]
. Jedes Slice der dritten Dimension ist eine Kopie des ursprünglichen 2D-Arrays. Das ist nicht so offensichtlich, wenn man es nur ansiehtprint(b)
.np.newaxis
ist nur ein Alias vonNone
Ein anderer Weg ist zu verwenden
numpy.dstack
. Angenommen, Sie möchten die Matrixzeiten wiederholena
num_repeats
:Der Trick besteht darin, die Matrix
a
in eine Liste eines einzelnen Elements zu verpacken und dann mit dem*
Operator die Elemente in dieser Liste zu duplizierennum_repeats
.Zum Beispiel, wenn:
Dies wiederholt das Array von
[1 2; 1 2]
5 Mal in der dritten Dimension. So überprüfen Sie (in IPython):Am Ende können wir sehen, dass die Form der Matrix
2 x 2
mit 5 Schichten in der dritten Dimension ist.quelle
reshape
? Schneller? gibt die gleiche Struktur? Es ist definitiv ordentlicher.Verwenden Sie eine Ansicht und erhalten Sie freie Laufzeit! Erweitern Sie generische
n-dim
Arrays aufn+1-dim
In NumPy eingeführt
1.10.0
, können wir nutzen,numpy.broadcast_to
um einfach eine3D
Ansicht in das2D
Eingabearray zu generieren . Der Vorteil wäre kein zusätzlicher Speicheraufwand und praktisch freie Laufzeit. Dies ist in Fällen wichtig, in denen die Arrays groß sind und wir mit Ansichten arbeiten können. Dies würde auch bei generischenn-dim
Fällen funktionieren .Ich würde das Wort
stack
anstelle von verwendencopy
, da die Leser es möglicherweise mit dem Kopieren von Arrays verwechseln, die Speicherkopien erstellen.Stapel entlang der ersten Achse
Wenn wir Eingaben
arr
entlang der ersten Achse stapeln möchten , wäre die Lösungnp.broadcast_to
zum Erstellen einer3D
Ansicht:Stapel entlang der dritten / letzten Achse
Um Eingaben
arr
entlang der dritten Achse zu stapeln , wäre die Lösung zum Erstellen einer3D
Ansicht:Wenn wir tatsächlich eine Speicherkopie benötigen, können wir diese jederzeit anhängen
.copy()
. Daher wären die Lösungen -So funktioniert das Stapeln für die beiden Fälle, die mit ihren Forminformationen für einen Beispielfall angezeigt werden:
Dieselben Lösungen würden funktionieren, um eine
n-dim
Eingabe zu erweitern und dien+1-dim
Ausgabe entlang der ersten und letzten Achse anzuzeigen. Lassen Sie uns einige Fälle mit höherer Dunkelheit untersuchen -3D-Eingabefall:
4D Eingangsfall:
und so weiter.
Timings
Lassen Sie uns einen großen Beispielfall verwenden
2D
und die Timings abrufen und überprüfen, ob die Ausgabe a istview
.Lassen Sie uns beweisen, dass die vorgeschlagene Lösung tatsächlich eine Ansicht ist. Wir werden das Stapeln entlang der ersten Achse verwenden (die Ergebnisse für das Stapeln entlang der dritten Achse wären sehr ähnlich) -
Lassen Sie uns das Timing zeigen, dass es praktisch kostenlos ist -
Eine Ansicht zu sein,
N
von3
zu3000
ändern, hat nichts an Timings geändert und beide sind an Timing-Einheiten vernachlässigbar. Daher effizient sowohl im Speicher als auch in der Leistung!quelle
Bearbeiten Sie @ Mr.F, um die Dimensionsreihenfolge beizubehalten:
quelle
B.shape
Drucken(N, 2, 2)
für einen beliebigen Wert vonN
. Wenn Sie transponierenB
mitB.T
dann passt es die erwartete Ausgabe.B[0], B[1],...
auf diese Weise erhalten Sie das richtige Slice, das ich argumentieren und sagen werde, dass es einfacher zu tippen ist als zu verwendenB[:,:,0], B[:,:,1]
usw.B[:,:,i]
und das ist es, woran ich gewöhnt bin.Hier ist ein Sendebeispiel, das genau das tut, was angefordert wurde.
Dann
b*a
ist das gewünschte Ergebnis und(b*a)[:,:,0]
erzeugtarray([[1, 2],[1, 2]])
, welches das Original ista
, wie auch(b*a)[:,:,1]
usw.quelle
Dies kann jetzt auch mit np.tile wie folgt erreicht werden:
quelle