numpy.load给出ValueError:descr不是有效的dtype描述符:

时间:2018-09-06 00:13:45

标签: python c++ numpy

我已经使用npy在C ++程序中编写了一个cnpy文件:

vector < double > vrmsd(max,99.9);
.
.
.
cnpy::npy_save(frmsd,&vrmsd,{nfeat},"w");

以示例here为例。

但是当我尝试使用numpy加载文件时,出现错误

y = np.load(frmsd)
  

ValueError: descr is not a valid dtype descriptor: '<?24'

下面,我将hexdump -C的结果粘贴到一个npy文件中,该文件包含一个长度为2的vector<double>(应包含46.950、43.94):

00000000  93 4e 55 4d 50 59 01 00  46 00 7b 27 64 65 73 63  |.NUMPY..F.{'desc|
00000010  72 27 3a 20 27 3c 3f 32  34 27 2c 20 27 66 6f 72  |r': '<?24', 'for|
00000020  74 72 61 6e 5f 6f 72 64  65 72 27 3a 20 46 61 6c  |tran_order': Fal|
00000030  73 65 2c 20 27 73 68 61  70 65 27 3a 20 28 32 2c  |se, 'shape': (2,|
00000040  29 2c 20 7d 20 20 20 20  20 20 20 20 20 20 20 0a  |), }           .|
00000050  10 4d 1b 02 00 00 00 00  20 4d 1b 02 00 00 00 00  |.M...... M......|
00000060  20 4d 1b 02 00 00 00 00  00 ff 00 00 00 ff 00 00  | M..............|
00000070  c8 33 19 02 00 00 00 00  94 99 90 5b 00 00 00 00  |.3.........[....|
00000080

此问题也已发布到cnpy github网站。只是想知道我在numpy方面是否可以做些什么?谢谢。

2 个答案:

答案 0 :(得分:0)

如果您想从numpy方面解决此问题……那么,您可能不想修改numpy以理解非标准的descr字符串,而且我怀疑即使您将该descr字符串视为似乎是正确的声称无论如何都会得到垃圾。

但是您可以进行一些变通的解决方法。

如果打开二进制文件,则应以以下内容开头:

\x93NUMPY\x01\x00v\x00{'descr': '<?24', 'fortran_order': False, 'shape': (30, 20), }

...,后跟一些空格,这些空格在原始字节之前以换行符结尾。

您可以在十六进制编辑器或文本编辑器中仔细编辑此文件,也可以使用Python代码以二进制模式打开文件,读取文件,对字节执行一些常规的字符串操作并写回。

特别是,看起来像python dict repr的位实际上就是那个,并且这些值恰好代表了您认为的含义。加载文件最终尝试创建np.dtype('<?24'),这就是错误的出处。

如果您仅编辑descrshape值,并确保将dict repr保持相同的长度(通过填充空格),那将为您提供一些{{1} }。

那么load是什么意思?嗯,这不是PEP 3118struct指定的有效格式,但是它确实适合numpy对该格式的扩展名。例如,在numpy中,您可以指定<?24,意思是“与f8相同,但为8个字节”。因此,假设这意味着f的24字节小尾数版本,如果使用C99编译则表示?,如果不是,则表示_Bool,并且应解释为{{ 1}}。

因此,如果numpy允许此descr指定dtype,则意味着每个单元格均为24字节,解释为小尾数整数,解释为bool。当然,numpy不知道如何处理除1、2、4或8个字节以外的任何长度的整数,并且它期望布尔值是1个字节,因此是不允许的。但是您可以读到与24个独立的bool相同的内容。

您如何做到的?只需将char字符串更改为bool,将descr更改为'?',现在您将获得30x20x24布尔数组,并且如果对shape进行切片,您将获得一个30x20的布尔数组。或者,(30, 20, 24)可能会这样做而无需更改[..., 0]

问题是,您的C ++值为double,而不是布尔值。

希望它是用little-endian格式写的double,每个double后面有16个额外的0字节。如果是这样,只需将'24?'更改为shape,将descr更改为'<f8',然后看看会得到什么。如果第一个shape是您想要的数组,而其他两个都是零,那么您就完成了;切成薄片。 (如果您想减少内存使用量,可以使用(30, 20, 3)。)

答案 1 :(得分:0)

在您提供的示例中,按照npy_save()参数的格式存在错误。

而不是

cnpy::npy_save(frmsd,&vrmsd,{nfeat},"w");

您要

cnpy::npy_save(frmsd,&vrmsd[0],{nfeat},"w");