将复杂数据读入numpy数组

时间:2014-07-29 18:53:07

标签: python numpy

我需要将文本文件中的复数读入numpy数组。我的问题类似于这个Writing and reading complex numbers using numpy.savetxt and numpy.loadtxt,但是,这里的解决方案是改变数据保存的格式。我没有这个奢侈,因为文本文件是由其他软件生成的,我无法改变。文本文件的示例如下:

25 + 0i
8.43818 + -4.94194i
4.46817 + -5.08305i
4.55764 + -3.02201i
2.69138 + -5.43104i
-0.151334 + -4.83717i
1.98336 + -1.3339i
3.59002 + -0.932973i
1.42727 + -0.617317i
1.02005 + -1.14214i
-0.15564 + 2.74564i

我尝试了以下内容:

np.loadtxt('file.txt',delimiter='\n',dtype=np.complex128)

然而我收到错误:

ValueError: complex() arg is a malformed string

我读过的帖子暗示这是某些行中+ -符号的问题,但是,即使删除了额外的+符号,也会出现相同的错误。

2 个答案:

答案 0 :(得分:5)

  

但是,这里的解决方案是改变

中保存数据的格式

好消息,你没必要!

numpy.loadtxt可以使用任何可迭代的行,而不仅仅是文件对象。

因此,您可以将文件对象包装在一个简单的生成器中,该生成器可以动态转换行,并将其提供给loadtxt,每个人都会很高兴。

像这样:

def transform_complex(line):
    # insert your code here

with open('file.txt', 'rb') as f:
    lines = map(transform_complex, f)
    arr = np.loadtxt(lines, dtype=np.complex128)

(如果你使用的是Python 2.x,文件很大,你可能想要使用itertools.imap而不是map。)

“在此处插入您的代码”部分,您可以从有效的答案填写,但不是一个可接受的解决方案,因为它需要修改文件。由于我在你的链接中没有看到这样的答案,我不确定那是什么,但是例如,也许就是这样:

def transform_complex(line):
    return line.replace(b'+ -', b'- ')

在本地测试内容,看起来输入实际上有三个问题。

您可以使用savetxt测试输出应该的外观。例如:

>>> arr = np.array([1-2j])
>>> f = io.BytesIO()
>>> np.savetxt(f, arr)
>>> f.getvalue()
b' (1.000000000000000000e+00-2.000000000000000000e+00j)\n'

(在Python 2.x中,您将看不到b前缀。)

并非所有这些差异都是相关的 - 你不必使用指数表示法,你不需要parens等等 - 但看起来这三个是:

  • 复数中+周围不允许有空格。
  • 虚数单位必须为j,而不是i
  • 不允许+-

所以:

def transform_complex(line):
    return line.replace(b' ', b'').replace(b'+-', b'-').replace(b'i', b'j')

答案 1 :(得分:2)

@ abarnert的答案很好,但不要忘记loadtxt有一个参数,converters, 它提供了一个用于自定义字段处理方式的钩子。这是一对夫妇 示例,说明如何使用它来处理此文件。

在第一个版本中,保留了默认分隔符(空格), 所以有三列。 usecols用于忽略中间列('+')。转换器用于 将最后一列(第2列)转换为浮点值。它使用切片丢弃 最后一个字符,即'i'。使用这些参数,loadtxt返回一个数组 具有浮点值的形状(11,2)。通过调用view方法 键入np.complex128,数组将转换为浮点值数组 形状(11,1)。最后,使用[:,0]建立索引会给出复数值的一维数组。 (可以使用对ravelsqueezereshape的来电。)

In [24]: loadtxt('file.txt', converters={2:lambda f: float(f[:-1])}, usecols=(0,2)).view(np.complex128)[:,0]
Out[24]: 
array([ 25.000000+0.j      ,   8.438180-4.94194j ,   4.468170-5.08305j ,
         4.557640-3.02201j ,   2.691380-5.43104j ,  -0.151334-4.83717j ,
         1.983360-1.3339j  ,   3.590020-0.932973j,   1.427270-0.617317j,
         1.020050-1.14214j ,  -0.155640+2.74564j ])

下一个版本将整行视为单个字段。以下功能 将文件中使用的格式的字符串转换为复数:

In [36]: def to_complex(field):
   ....:     return complex(field.replace(' ', '').replace('+-', '-').replace('i', 'j'))
   ....: 

E.g

In [39]: to_complex('8.43818 + -4.94194i')
Out[39]: (8.43818-4.94194j)

loadtxt调用将每一行视为单个字段,并使用 转换器将每个字段转换为复数:

In [37]: loadtxt('file.txt', converters={0: to_complex}, dtype=np.complex128, delimiter=';')
Out[37]: 
array([ 25.000000+0.j      ,   8.438180-4.94194j ,   4.468170-5.08305j ,
         4.557640-3.02201j ,   2.691380-5.43104j ,  -0.151334-4.83717j ,
         1.983360-1.3339j  ,   3.590020-0.932973j,   1.427270-0.617317j,
         1.020050-1.14214j ,  -0.155640+2.74564j ])

(分隔符设置为';',但它可能是任何字符 不会出现在文件中。)

相关问题