Pytanie Numpy: Tworzenie złożonej tablicy z 2 prawdziwych?


Przysięgam, że to powinno być takie łatwe ... Dlaczego nie? :(

W rzeczywistości chcę połączyć 2 części tej samej tablicy, aby utworzyć złożoną tablicę:

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

Te nie działają:

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

Czy czegoś brakuje? Czy numpy nie przypomina wykonywania funkcji tablicowych na liczbach zespolonych? Oto błąd:

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

44
2018-04-08 09:22


pochodzenie




Odpowiedzi:


Wydaje się, że robi to, co chcesz:

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

Oto inne rozwiązanie:

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

A jeszcze inne prostsze rozwiązanie:

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

PS: Jeśli chcesz zaoszczędzić pamięć (bez pośredniej tablicy):

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

Poniższe rozwiązanie devS jest również szybkie.


55
2018-04-08 09:38



Ten sam błąd Obawiam się: TypeError: tylko tablice długości-1 można konwertować na skalowania Pythona - Duncan Tait
@Duncan: zaktualizowałem oryginalną odpowiedź po wykonaniu testu. Wygląda na to, że działa teraz. - Eric Lebigot
wielkie dzięki, które działa. Jest BARDZO powolny (jak można się było spodziewać - ponieważ nie jest to funkcja numpy), zajmuje teraz 5 sekund na pętlę zamiast 0,1 - Duncan Tait
@Duncan: Dodałem dwa inne rozwiązania: być może warto je również odmienić. Jeśli to działa dla Ciebie, proszę kciukiem odpowiedź! - Eric Lebigot
Doskonale, oboje są znacznie szybsi :) - Duncan Tait


Jest oczywiście dość oczywiste:

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

28
2017-09-05 19:34



Również Data.view(complex) - Bi Rico


Jeśli twoje prawdziwe i urojone części są fragmentami wzdłuż ostatniego wymiaru, a twoja tablica jest ciągła wzdłuż ostatniego wymiaru, możesz po prostu zrobić

A.view(dtype=np.complex128)

Jeśli używasz pojedynczej precyzji, to będzie

A.view(dtype=np.complex64)

Oto pełniejszy przykład

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)

Jeśli chcesz pozbyć się dodatkowego wymiaru, który pozostaje od rzucania, możesz zrobić coś takiego

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

Działa to, ponieważ w pamięci liczba zespolona to tak naprawdę dwie liczby zmiennoprzecinkowe. Pierwsza reprezentuje część rzeczywistą, a druga reprezentuje część urojoną. Metoda widoku tablicy zmienia typ dtype w celu odzwierciedlenia, że ​​chcesz traktować dwie sąsiednie wartości zmiennoprzecinkowe jako pojedynczą liczbę zespoloną i odpowiednio aktualizuje wymiar.

Ta metoda nie kopiuje żadnych wartości w tablicy ani nie wykonuje nowych obliczeń, a jedynie tworzy nowy obiekt tablicy, który inaczej wyświetla ten sam blok pamięci. To sprawia, że ​​ta operacja może zostać wykonana dużo szybszy niż wszystko, co wiąże się z kopiowaniem wartości. Oznacza to również, że wszelkie zmiany dokonane w tablicy o wartości zespolonej zostaną odzwierciedlone w tablicy za pomocą części rzeczywistych i urojonych.

Odzyskanie oryginalnej tablicy może być nieco trudniejsze, jeśli usuniesz dodatkową oś, która znajduje się bezpośrednio po rzutowaniu. Rzeczy jak A_comp[...,np.newaxis].view(np.float64) obecnie nie działa, ponieważ, poczynając od tego zapisu, NumPy nie wykrywa, że ​​tablica wciąż jest w ciągłym C przy dodawaniu nowej osi. Widzieć ten przypadek. A_comp.view(np.float64).reshape(A.shape) wydaje się jednak działać w większości przypadków.


15
2018-02-24 18:51



+1: Bardzo jasne wyjaśnienie ograniczeń metody. Możesz dodać jednoznacznie inne ograniczenie (pamięć współużytkowana między A_comp i A), a także zaletą tej metody (prędkości). - Eric Lebigot
@EOL Dzięki. Odpowiednio zaktualizowałem odpowiedź. - IanH


Oto czego szukasz:

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])

13
2018-01-06 17:09



Jest to tylko częściowy duplikat wcześniejszych odpowiedzi, takich jak Pierre GM lub mój: myślę, że jego jedynym skutkiem jest pochłonięcie czasu ludzi prawie bez żadnej wartości dodanej (poza tym przykładem), więc sugerowałbym, abyś go skasował. - Eric Lebigot


Jestem nowicjuszką Pythona, więc może to nie być najskuteczniejsza metoda, ale jeśli dobrze rozumiem intencję pytania, kroki wymienione poniżej działają dla mnie.

>>> 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)

7
2017-10-28 18:48



Ciekawy pomysł. Jednak pytanie dotyczy łączenia Data[:,:,:,0] i Data[:,:,:,1] (bardziej skomplikowane niż twoje a). Ponadto zamiast używać zeros(), powinieneś użyć tego szybciej i bardziej odpowiedniego empty(). - Eric Lebigot
Porównałem go z rozwiązaniem Data [..., 0] + 1j * Data [..., 1]. Z danymi = random.rand (100,100,1000,2), c = zera (a.shape [: - 1], dtype = complex); c.real = Data [..., 0]; c.imag = Dane [..., 1]; jest 2x szybszy niż proste dane [..., 0] + 1j * Dane [..., 1]. Co zaskakujące, efekt użycia pustych zamiast zer był znikomy. - Pavel Bazant
+1. Uwaga: otrzymuję tę samą prędkość z odmianą mojej ostatniej odpowiedzi: result = 1j*Data[...,1]; result += Data[...,0]. Ta odpowiedź jest bardziej naturalna, jeśli pojedyncza formuła nie jest używana. - Eric Lebigot


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)

3
2018-03-12 06:47





To zadziałało dla mnie:

wkład:

from scipy import *

array([[1,2],[3,2]]).astype(complex)

wydajność:

array([[ 1.+0.j, 2.+0.j], 
       [ 3.+0.j, 2.+0.j]])

0
2017-07-18 19:08



-1, pozostawia część wyobrażoną równą zero - Pavel Bazant


Jeśli naprawdę chcesz poprawić wydajność (z dużymi tablicami), numexpr może być użyty, który wykorzystuje wiele rdzeni.

Ustawiać:

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

Z 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)

W porównaniu do metody szybkiej numpy:

>>> %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)

0
2017-08-15 12:45