numpy:从2个真实的数组创建一个复杂的数组?


70

我想将同一数组的2个部分组合成一个复杂的数组:

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

这些不起作用:

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

我想念什么吗?numpy是否不喜欢对复数执行数组函数?这是错误:

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

Answers:


77

这似乎可以满足您的要求:

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

这是另一种解决方案:

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

还有另一个更简单的解决方案:

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

PS:如果要保存内存(无中间阵列):

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

devS的以下解决方案也很快。


恐怕出现相同的错误:TypeError:只能将长度为1的数组转换为Python标量
Duncan Tait 2010年

@邓肯:我在执行测试后更新了原始答案。现在看来,它正在工作。
Eric O Lebigot

非常感谢,确实有效。不过,它的速度非常慢(如您所料-由于它实际上不是一个numpy函数),现在每个循环需要5秒钟而不是0.1秒
Duncan Tait 2010年

@Duncan:我添加了另外两个解决方案:也许也值得时间。如果这对您有用,请竖起答案!
Eric O Lebigot

太好了,他们俩都快得多了:)
Duncan Tait 2010年


24

如果您的实部和虚部是沿最后一个维度的切片,而数组沿最后一个维度是连续的,则可以

A.view(dtype=np.complex128)

如果您使用的是单精度浮点数,则为

A.view(dtype=np.complex64)

这是一个更完整的例子

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)

如果您想摆脱铸件留下的多余尺寸,可以执行以下操作

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

之所以可行,是因为在内存中,复数实际上只是两个浮点数。第一个代表实部,第二个代表虚部。数组的view方法更改数组的dtype以反映您要将两个相邻的浮点值视为单个复数,并相应地更新尺寸。

此方法不会复制数组中的任何值或执行任何新的计算,它所做的只是创建一个新的数组对象,该对象以不同的方式查看同一块内存。这使得它使这个操作可以进行比任何涉及复制值更快。这也意味着对复数值数组所做的任何更改都将反映在具有实部和虚部的数组中。

如果删除类型转换后立即存在的多余轴,则恢复原始数组也可能会有些棘手。之类的东西A_comp[...,np.newaxis].view(np.float64)当前不起作用,因为在撰写本文时,NumPy在添加新轴时未检测到数组仍为C连续的。看到这个问题A_comp.view(np.float64).reshape(A.shape)似乎在大多数情况下都有效。


+1:非常清楚地说明了该方法的局限性。您可能希望显式添加另一个限制(A_comp和之间的共享内存A),并且还需要此方法的优点(速度)。
Eric O Lebigot

17

这是您要寻找的:

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

这只是Pierre GM或我的早期答案的部分重复:我认为它的唯一作用是花费人们的时间几乎没有附加值(超出示例),因此建议您删除它。
埃里克·O·勒比戈特

3
14个人不同意!虽然深度较弱,不值得打勾,但此示例使我最快地达到了所需。
supergra

14

我是python新手,所以这可能不是最有效的方法,但是,如果我正确理解了问题的意图,下面列出的步骤对我有用。

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

有趣的主意。但是,问题在于合并Data[:,:,:,0]Data[:,:,:,1](比您的复杂a)。另外,zeros()应该使用更快,更合适的方法来代替使用empty()
Eric O Lebigot 2014年

1
我将其与Data […,0] + 1j * Data […,1]解决方案进行了比较。使用Data = random.rand(100,100,1000,2),c = zeros(a.shape [:-1],dtype = complex); c.real = Data [...,0]; c.imag = Data [...,1]; 比简单的Data […,0] + 1j * Data […,1]快2倍。令人惊讶的是,使用空而不是零的影响可以忽略不计。
帕维尔·巴赞特

1
+1。注意:我得到的速度与上一个答案的变化相同:result = 1j*Data[...,1]; result += Data[...,0]。但是,如果不使用单个公式,则此答案更为自然。
Eric O Lebigot

我认为这是最好的答案,因为在阅读代码时,意图很明显。Eric的答案虽然在功能上是正确的,但在读回代码时却不清楚。
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)

0

如果您真的想提高性能(使用大数组),可以使用numexpr,它利用了多个内核。

设定:

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

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)

与快速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

我使用以下方法:

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.