numpy custom dtype challenge

时间:2015-09-24 14:38:14

标签: python arrays numpy binary complex-numbers

我有一个自定义dtype my_type 的数组,我从二进制文件中成功读取了该数组。自定义dtype后面有一个标题部分。数据部分是 np.int16 数字,因此自定义dtype如下所示:

header, imaginary, real, imaginary, real,  ..., imaginary, real 

现在我正在寻找一种智能的方式来使用Numpy的视图来获取 np.complex64 仅数据的数组考虑到以下事实,没有复制/循环等:

  • 标题部分应该被忽略
  • 以某种方式纠正顺序(即第一个真实的,想象的)
  • 生成的数组应该是complex64而不是complex32!

即,从自定义dtype数组:

[my_type, my_type, ..., my_type] 

我喜欢得到一个更大的数组:

[complex64, complex64, ..., complex64]

是否可以使用Numpy的视图一次性完成此操作?

更新

所以解决方案是在内存中复制。非常感谢下面的答案。但是因为恼人的标题出现在每个数据帧之前,所以似乎尽管在存储器中进行了复制,仍然需要在所有数据帧上进行循环。我以示意图的方式:

a = np.arange(10, dtype=np.float16)
skip_annoying_header = 2
r = np.zeros(a.size - skip_annoying_header, np.float16)
r[0::2], r[1::2] = a[skip_annoying_header + 1::2], a[skip_annoying_header::2]
r = r.astype(np.float32)
r = r.view(np.complex64)

我在每个数据框的for循环中执行此操作,然后在for循环结束时,我再次将r的内容复制到数组。

这种循环可以以某种方式消除吗?

2 个答案:

答案 0 :(得分:3)

所有3个要求都与view冲突。

忽略header字段需要选择其他字段。选择单个字段显然是一个视图,但多个字段的状态是不断变化的。当我尝试除了简单地查看值之外的任何事情时,我会收到警告:

In [497]: dt=np.dtype('U10,f,f,f,f')
In [498]: x=np.zeros((5,),dt)

In [505]: x[['f1','f3']].__array_interface__
/usr/bin/ipython3:1: FutureWarning: Numpy has detected that you (may be) writing to an array returned
by numpy.diagonal or by selecting multiple fields in a record
array. This code will likely break in a future numpy release --
see numpy.diagonal or arrays.indexing reference docs for details.
The quick fix is to make an explicit copy (e.g., do
arr.diagonal().copy() or arr[['f0','f1']].copy()).

请记住,数据是逐个元素排列的,dtype元组值在紧凑块中 - 基本上是显示的紧凑版本。忽略header需要跳过该组字节。 view可以处理由strides生成的跳过,但不能处理这些dtype字段跳过。

In [533]: x
Out[533]: 
array([('header', 0.0, 5.0, 1.0, 10.0), ('header', 1.0, 4.0, 1.0, 10.0),
       ('header', 2.0, 3.0, 1.0, 10.0), ('header', 3.0, 2.0, 1.0, 10.0),
       ('header', 4.0, 1.0, 1.0, 10.0)], 
      dtype=[('f0', '<U10'), ('f1', '<f4'), ('f2', '<f4'), ('f3', '<f4'), ('f4', '<f4')])

要探索对复杂字段进行重新排序,请尝试使用二维数组:

In [509]: y=np.arange(10.).reshape(5,2)  # 2 column float
In [510]: y.view(complex)    # can be viewed as complex
Out[510]: 
array([[ 0.+1.j],
       [ 2.+3.j],
       [ 4.+5.j],
       [ 6.+7.j],
       [ 8.+9.j]])
In [511]: y[:,::-1].view(complex)
...
ValueError: new type not compatible with array.

要切换real / imaginay列,我必须复制。 complex要求2个浮点数是连续且有序的。

In [512]: y[:,::-1].copy().view(complex)
Out[512]: 
array([[ 1.+0.j],
       [ 3.+2.j],
       [ 5.+4.j],
       [ 7.+6.j],
       [ 9.+8.j]])

float32float64显然不是view更改。一个使用每个数字4个字节,另一个8.您不能查看&#39; 4为8而不复制。

答案 1 :(得分:2)

@hpaulj绝对正确,这与视图冲突。

但是,你可能会问错误的问题。

numpy当然可以做您想做的事情,但您需要在内存中制作临时副本。

总的来说,通过重新思考&#34;将整个文件读入内存然后查看它,可能会更好地满足您的需求。做法。而是寻找过去(或读入)标题,然后用fromfile读入数据部分。不过,只要您不介意制作副本从float32float64,就可以相对直接地将事情操作到您想要的内容中。 &#39; S

首先,让我们生成一个类似于你的文件:

import numpy as np

reals = np.arange(100).astype(np.float32)
imag = -9999.0 * np.ones(100).astype(np.float32)

data = np.empty(reals.size + imag.size, dtype=np.float32)
data[::2], data[1::2] = imag, reals

with open('temp.dat', 'wb') as outfile:
    # Write a 1Kb header (of literal "x"'s, in this case)
    outfile.write(1024 * 'x')
    outfile.write(data)

现在我们将其阅读。

在使用seek阅读数据之前,忽略标题的关键是fromfile过去。

然后,我们可以解交织数据并同时转换为64位浮点数。

最后,您可以将生成的2xN长度float64数组视为N长complex128数组。 (注意:complex128是复数的64位版本。complex64是32位版本。)

例如:

import numpy as np

with open('temp.dat', 'rb') as infile:
    # Seek past header
    infile.seek(1024)

    # Read in rest of file as float32's
    data = np.fromfile(infile, dtype=np.float32)

result = np.empty(data.size, np.float64)

# De-interleave imag & real back into expected real & imag, converting to 64-bit
result[::2], result[1::2] = data[1::2], data[::2]

# View the result as complex128's (i.e. 64-bit complex numbers)
result = result.view(np.complex128)