Numpy: Ein komplexes Array aus 2 echten erstellen?

70

Ich möchte 2 Teile desselben Arrays zu einem komplexen Array kombinieren:

Data[:,:,:,0] , Data[:,:,:,1]

Diese funktionieren nicht:

x = np.complex(Data[:,:,:,0], Data[:,:,:,1])
x = complex(Data[:,:,:,0], Data[:,:,:,1])

Vermisse ich etwas Mag numpy es nicht, Array-Funktionen für komplexe Zahlen auszuführen? Hier ist der Fehler:

TypeError: only length-1 arrays can be converted to Python scalars
Duncan Tait
quelle

Antworten:

77

Dies scheint zu tun, was Sie wollen:

numpy.apply_along_axis(lambda args: [complex(*args)], 3, Data)

Hier ist eine andere Lösung:

# The ellipsis is equivalent here to ":,:,:"...
numpy.vectorize(complex)(Data[...,0], Data[...,1])

Und noch eine einfachere Lösung:

Data[...,0] + 1j * Data[...,1]

PS : Wenn Sie Speicher sparen möchten (kein Zwischenarray):

result = 1j*Data[...,1]; result += Data[...,0]

Die unten stehende Lösung von devS ist ebenfalls schnell.

Eric O Lebigot
quelle
Gleicher Fehler Ich fürchte: TypeError: Nur Arrays der Länge 1 können in Python Scalars konvertiert werden
Duncan Tait
@ Duncan: Ich habe die ursprüngliche Antwort nach Durchführung des Tests aktualisiert. Es scheint jetzt zu funktionieren.
Eric O Lebigot
Vielen Dank, das funktioniert. Es ist jedoch SEHR langsam (wie zu erwarten - da es sich nicht wirklich um eine Numpy-Funktion handelt), es dauert jetzt 5 Sekunden pro Schleife anstatt 0,1
Duncan Tait
@ Duncan: Ich habe zwei weitere Lösungen hinzugefügt: Es kann sich auch lohnen, sie zeitlich festzulegen. Wenn dies für Sie funktioniert, geben Sie bitte die Antwort!
Eric O Lebigot
Ausgezeichnet, sie sind beide viel schneller :)
Duncan Tait
44

Es gibt natürlich das ziemlich Offensichtliche:

Data[...,0] + 1j * Data[...,1]
Pierre GM
quelle
24

Wenn Ihre Real- und Imaginärteile die Slices entlang der letzten Dimension sind und Ihr Array entlang der letzten Dimension zusammenhängend ist, können Sie dies einfach tun

A.view(dtype=np.complex128)

Wenn Sie Floats mit einfacher Genauigkeit verwenden, ist dies der Fall

A.view(dtype=np.complex64)

Hier ist ein ausführlicheres Beispiel

import numpy as np
from numpy.random import rand
# Randomly choose real and imaginary parts.
# Treat last axis as the real and imaginary parts.
A = rand(100, 2)
# Cast the array as a complex array
# Note that this will now be a 100x1 array
A_comp = A.view(dtype=np.complex128)
# To get the original array A back from the complex version
A = A.view(dtype=np.float64)

Wenn Sie die zusätzliche Dimension entfernen möchten, die vom Casting übrig bleibt, können Sie so etwas tun

A_comp = A.view(dtype=np.complex128)[...,0]

Dies funktioniert, weil eine komplexe Zahl im Speicher eigentlich nur zwei Gleitkommazahlen sind. Der erste repräsentiert den Realteil und der zweite repräsentiert den Imaginärteil. Die Ansichtsmethode des Arrays ändert den d-Typ des Arrays, um anzuzeigen, dass Sie zwei benachbarte Gleitkommawerte als eine einzige komplexe Zahl behandeln möchten, und aktualisiert die Dimension entsprechend.

Diese Methode kopiert keine Werte in das Array und führt keine neuen Berechnungen durch. Sie erstellt lediglich ein neues Array-Objekt, das denselben Speicherblock unterschiedlich anzeigt. Das macht es so, dass diese Operation viel ausgeführt werden kann schneller ausgeführt werden als alles, was das Kopieren von Werten beinhaltet. Dies bedeutet auch, dass alle Änderungen, die im Array mit komplexen Werten vorgenommen werden, im Array mit den Real- und Imaginärteilen wiedergegeben werden.

Es kann auch etwas schwieriger sein, das ursprüngliche Array wiederherzustellen, wenn Sie die zusätzliche Achse entfernen, die unmittelbar nach der Typumwandlung vorhanden ist. Dinge wie A_comp[...,np.newaxis].view(np.float64)funktionieren derzeit nicht, da NumPy zum jetzigen Zeitpunkt nicht erkennt, dass das Array beim Hinzufügen der neuen Achse noch C-zusammenhängend ist. Siehe dieses Problem . A_comp.view(np.float64).reshape(A.shape)scheint jedoch in den meisten Fällen zu funktionieren.

IanH
quelle
+1: Sehr klare Erklärung der Einschränkungen der Methode. Möglicherweise möchten Sie explizit eine weitere Einschränkung (gemeinsam genutzter Speicher zwischen A_compund A) sowie einen Vorteil dieser Methode (Geschwindigkeit) hinzufügen .
Eric O Lebigot
17

Das ist, wonach Sie suchen:

from numpy import array

a=array([1,2,3])
b=array([4,5,6])

a + 1j*b

->array([ 1.+4.j,  2.+5.j,  3.+6.j])
Nadapez
quelle
Dies ist nur ein Teil des Duplikats früherer Antworten wie der von Pierre GM oder meiner: Ich denke, dass der einzige Effekt darin besteht, sich die Zeit für fast keinen Mehrwert zu nehmen (über das Beispiel hinaus), daher würde ich vorschlagen, dass Sie ihn löschen.
Eric O Lebigot
3
14 Leute sind anderer Meinung! Obwohl die Tiefe schwach ist und kein Häkchen verdient, hat mich dieses Beispiel am schnellsten zu dem gebracht, was ich brauchte.
Supergra
14

Ich bin Python-Neuling, daher ist dies möglicherweise nicht die effizienteste Methode. Wenn ich die Absicht der Frage richtig verstehe, haben die unten aufgeführten Schritte für mich funktioniert.

>>> import numpy as np
>>> Data = np.random.random((100, 100, 1000, 2))
>>> result = np.empty(Data.shape[:-1], dtype=complex)
>>> result.real = Data[...,0]; result.imag = Data[...,1]
>>> print Data[0,0,0,0], Data[0,0,0,1], result[0,0,0]
0.0782889873474 0.156087854837 (0.0782889873474+0.156087854837j)
devS
quelle
Interessante Idee. Die Frage ist jedoch über das Kombinieren Data[:,:,:,0]und Data[:,:,:,1](komplizierter als Ihre a). Anstatt zu verwenden zeros(), sollten Sie auch das schnellere und angemessenere verwenden empty().
Eric O Lebigot
1
Ich habe es mit der Lösung Data […, 0] + 1j * Data […, 1] verglichen. Mit Data = random.rand (100,100,1000,2) ist c = Nullen (a.shape [: - 1], dtype = complex); c.real = Data [..., 0]; c.imag = Daten [..., 1]; ist 2x schneller als die einfachen Daten […, 0] + 1j * Daten […, 1]. Überraschenderweise war der Effekt der Verwendung von Leer anstelle von Nullen vernachlässigbar.
Pavel Bazant
1
+1. Hinweis: Ich erhalte die gleiche Geschwindigkeit mit einer Variation meiner letzten Antwort : result = 1j*Data[...,1]; result += Data[...,0]. Diese Antwort ist jedoch natürlicher, wenn keine einzige Formel verwendet wird.
Eric O Lebigot
Ich denke, dies ist die beste Antwort, da die Absicht beim Lesen des Codes offensichtlich ist. Erics Antworten sind zwar funktional korrekt, aber beim Zurücklesen des Codes weniger klar.
Biggsy
4
import numpy as np

n = 51 #number of data points
# Suppose the real and imaginary parts are created independently
real_part = np.random.normal(size=n)
imag_part = np.random.normal(size=n)

# Create a complex array - the imaginary part will be equal to zero
z = np.array(real_part, dtype=complex)
# Now define the imaginary part:
z.imag = imag_part
print(z)
Ahmet Tugrul Basokur
quelle
0

Wenn Sie wirklich Leistung (mit großen Arrays) erzielen möchten , wählen Sie numexpr kann verwendet werden, das mehrere Kerne nutzt.

Konfiguration:

>>> import numpy as np
>>> Data = np.random.randn(64, 64, 64, 2)
>>> x, y = Data[...,0], Data[...,1]

Mit numexpr:

>>> import numexpr as ne
>>> %timeit result = ne.evaluate("complex(x, y)")
573 µs ± 21.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Im Vergleich zur schnellen Numpy-Methode:

>>> %timeit result = np.empty(x.shape, dtype=complex); result.real = x; result.imag = y
1.39 ms ± 5.74 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Kieferknie
quelle
0

Ich benutze die folgende Methode:

import numpy as np

real = np.ones((2, 3))
imag = 2*np.ones((2, 3))

complex = np.vectorize(complex)(real, imag)
# OR
complex = real + 1j*imag
Lerner
quelle
-1

Das hat bei mir funktioniert:

Eingang:

[complex(a,b) for a,b in zip([1,2,3],[1,2,3])]

Ausgabe:

[(1+4j), (2+5j), (3+6j)]
Nikolay Frick
quelle
Sie erstellen eine Liste und kein numpy Array
Camion