Python numpy自定义数据类型挑战

Python numpy自定义数据类型挑战,python,arrays,numpy,binary,complex-numbers,Python,Arrays,Numpy,Binary,Complex Numbers,我有一个自定义数据类型my_类型的数组,我成功地从二进制文件中读取了该数组。自定义数据类型有一个标题部分,后面是数据。数据部分是np.int16数字,因此自定义数据类型如下所示: header, imaginary, real, imaginary, real, ..., imaginary, real 现在,我正在寻找一种聪明的方法来使用Numpy的视图获取一个np.complex64数组,该数组只包含数据,而无需复制/循环等。考虑到以下事实: 应忽略标题部分 以某种方式纠正顺序(即第

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

header, imaginary, real, imaginary, real,  ..., imaginary, real 
现在,我正在寻找一种聪明的方法来使用Numpy的视图获取一个np.complex64数组,该数组只包含数据,而无需复制/循环等。考虑到以下事实:

  • 应忽略标题部分
  • 以某种方式纠正顺序(即第一个实数、假数)
  • 结果数组应该是complex64而不是complex32
即,从自定义数据类型的数组:

[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
的内容复制到大的数组中


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

所有3个需求都与
视图冲突

忽略
标题
字段需要选择其他字段。选择单个场显然是一种观点,但多个场的状态是不断变化的。当我尝试除查看值以外的任何操作时,我会收到一条警告:

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()).
请记住,数据是按元素逐元素排列的,数据类型元组值以紧凑的块表示——本质上是显示的紧凑版本。忽略
标题
需要跳过该组字节<代码>视图
可以处理由
跨步
产生的跳过,但不能处理这些数据类型字段跳过

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')])
要切换real/imaginay列,我必须复制一份
complex
要求两个浮点数连续且有序

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

float32
float64
显然不是
视图的改变。一个使用每个数字4字节,另一个使用8字节。如果不复制,就不能将4“查看”为8。

@hpaulj完全正确,这与视图冲突

然而,你可能问错了问题

numpy
当然可以做你想做的事情,但你需要在内存中做一个临时拷贝

总的来说,重新考虑“将整个文件读入内存,然后查看”的方法可能会更好。相反,先查找(或读入)标题,然后使用
从文件
读入数据部分。之后,只要您不介意制作一个从
float32
float64
的副本,就可以相对简单地将内容转换为您想要的内容


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

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)
现在我们来读一读

忽略标题的关键是在使用
从文件
读取数据之前,先
查找
标题

然后,我们可以对数据进行解交织,同时将其转换为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)

谢谢你的回答。事实上,我使用的是
seek
,因为这些文件通常都很大,每个文件都可以达到2GB。但问题是,恼人的标题出现在每个数据帧之前,因此循环似乎是必要的……这很好。我不知道对连续数据的要求。我想知道从速度上看,复制“成本”是多少…@xaratustra。不多事实上,通常在处理之前将大型数据集复制到最佳顺序是值得的。现在(1.19+)多字段索引生成一个
视图
,即带有字段“空白”的原始数据类型。如果您需要一个连续数组(例如,用于查看复杂数组),则有一个
repack
函数。很难判断何时谈论文件上的数据以及加载的数组。在从文件中一次读取一个“数据帧”时转换数据是一回事,转换结构化数组是另一回事。如果您已经让数组显示为
dtype
shape
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)