2010-04-08 11 views
39

Przysięgam, że powinno być tak łatwo ... Dlaczego nie jest? :(Numpy: Tworzenie złożonej tablicy z 2 prawdziwych?

W rzeczywistości, chciałbym połączyć 2 części tej samej tablicy, aby złożony tablicy:

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

te nie działają:

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

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

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

Odpowiedz

50

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

I kolejny prostsze rozwiązanie:

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

PS: Jeśli chcesz zaoszczędzić pamięć (bez pośredniego array):

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

Rozwiązanie devS "jest również szybkie.

+0

sam błąd jestem przestraszony: TypeError: tylko długość-1 macierze mogą być konwertowane do Pythona skalary –

+0

@Duncan: I aktualizowany oryginalną odpowiedź po wykonaniu testu. Wygląda na to, że działa teraz. – EOL

+0

dzięki dużo, że działa. Jest BARDZO powolny (jak można się było spodziewać - ponieważ nie jest to naprawdę funkcja numpy), teraz trwa 5 sekund na pętlę zamiast 0,1 –

0

który pracował dla mnie:

wejściowe:

from scipy import * 

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

wyjściowa:

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

-1, pozostawia część urojoną równą zeru –

26

Jest oczywiście raczej oczywiste:

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

Również 'Data.view (complex)' –

7

Jestem nowicjuszką Pythona, więc może to nie być najskuteczniejsza metoda, ale jeśli dobrze rozumiem intencję pytania, kroki wymienione poniżej będą działały 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) 
+0

Interesujący pomysł. Jednak pytanie dotyczy połączenia "Data [:,:,:, 0]" i "Data [:,:,:, 1]" (bardziej skomplikowane niż twoje "a"). Ponadto, zamiast używać 'zeros()', powinieneś użyć szybszego i bardziej odpowiedniego 'empty()'. – EOL

+0

Porównałem to 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. –

+1

+1. Uwaga: Dostaję tę samą prędkość z odmianą mojej ostatniej odpowiedzi: 'result = 1j * Data [..., 1]; wynik + = Dane [..., 0] '. Ta odpowiedź jest bardziej naturalna, jeśli pojedyncza formuła nie jest używana. – EOL

11

To jest to, co 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]) 
+0

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, żebyś go skasował. – EOL

14

Jeśli rzeczywista i urojona są plastry wzdłuż ostatniego wymiaru a tablica przylega wzdłuż ostatniego wymiaru, można po prostu zrobić

A.view(dtype=np.complex128) 

Jeśli używasz pojedynczej precyzji pływaków, to byłoby

A.view(dtype=np.complex64) 

Oto pełniejsze 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 wokół z odlewu, można zrobić coś takiego

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

To działa, ponieważ w pamięć, liczba zespolona to tak naprawdę dwie liczby zmiennoprzecinkowe. Pierwsza reprezentuje część rzeczywistą, a druga reprezentuje część urojoną. Metoda widoku tablicy zmienia typ dtypu tablicy tak, aby traktować dwie sąsiednie wartości zmiennoprzecinkowe jako pojedynczą liczbę zespoloną i odpowiednio aktualizował 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 być wykonana szybciej niż wszystko, co wymaga kopiowania 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.

Może to być trochę trudniejsze odzyskać oryginalną tablicę, jeśli usuniesz dodatkową oś, która znajduje się bezpośrednio po rzutowaniu. Rzeczy takie jak A_comp[...,np.newaxis].view(np.float64) obecnie nie działają, ponieważ po tym pisaniu NumPy nie wykrywa, że ​​tablica wciąż jest przyległa do C przy dodawaniu nowej osi. Zobacz this issue. A_comp.view(np.float64).reshape(A.shape) wydaje się jednak działać w większości przypadków.

+0

+1: Bardzo jasne wyjaśnienie ograniczeń metody. Możesz dodać jednoznacznie inne ograniczenie (pamięć współdzieloną między 'A_comp' i' A'), a także zaletę tej metody (szybkość). – EOL

+0

@EOL Dzięki. Odpowiednio zaktualizowałem odpowiedź. – IanH

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