我需要将文本文件中的复数读入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
我读过的帖子暗示这是某些行中+ -
符号的问题,但是,即使删除了额外的+
符号,也会出现相同的错误。
答案 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]
建立索引会给出复数值的一维数组。
(可以使用对ravel
,squeeze
或reshape
的来电。)
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 ])
(分隔符设置为';'
,但它可能是任何字符
不会出现在文件中。)