Python numpy自定义数据类型挑战
我有一个自定义数据类型my_类型的数组,我成功地从二进制文件中读取了该数组。自定义数据类型有一个标题部分,后面是数据。数据部分是np.int16数字,因此自定义数据类型如下所示: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数组,该数组只包含数据,而无需复制/循环等。考虑到以下事实: 应忽略标题部分 以某种方式纠正顺序(即第
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)