numpy.load 给出 ValueError: descr is not a valid dtype 描述符:

Posted

技术标签:

【中文标题】numpy.load 给出 ValueError: descr is not a valid dtype 描述符:【英文标题】:numpy.load gives ValueError: descr is not a valid dtype descriptor: 【发布时间】:2018-09-06 00:13:45 【问题描述】:

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

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: '&lt;?24'

下面我将hexdump -C 的结果粘贴到一个npy 文件中,该文件包含一个长度为2 的vector&lt;double&gt;(应该包含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 方面做些什么?谢谢。

【问题讨论】:

通过“我能做的事情”,您是否正在寻找一个 hacky 解决方法? 好吧,我不是在一个hacky解决方法之上!当然,如果我能让文件头符合 npy 标准,那将是最好的,但即使是 hack 也可能让我对正在发生的事情有所了解。 你能保存一个小得多的数组(比如 4x2),然后向我们展示保存文件的实际内容吗?向您展示如何处理它比编写一个示例要容易得多。 啊,是的。会做 能否请您告诉我如何显示二进制文件的内容(linux 或 mac OS)? 【参考方案1】:

如果你想从 numpy 方面解决这个问题……好吧,你可能不想修改 numpy 来理解非标准的 descr 字符串,而且我怀疑即使你把那个 descr 字符串当作它看起来的那样声称无论如何你都会得到垃圾。

但是你可以做一个hacky的解决方法。

如果你打开二进制文件,它应该以这样的开头:

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

…后面是一些空格,在原始字节之前以换行符结尾。

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

特别是,看起来像 Python dict repr 的位实际上正是如此,并且值的含义正是您认为的含义。加载文件最终会尝试创建np.dtype('&lt;?24'),这就是错误的来源。

如果您只是编辑 descrshape 值,并确保 dict repr 保持相同的长度(通过用空格填充),那么您可以使用 load

那么,&lt;?24 是什么意思?好吧,这不是PEP 3118 和struct 指定的有效格式,但它确实符合numpy 对该格式的扩展模式。例如,在 numpy 中,可以指定 f8,意思是“与 f 相同,但 8 个字节”。因此,据推测,这意味着? 的 24 字节 little-endian 版本,如果使用 C99 编译则意味着 _Bool,如果不是,则意味着 char,并且意味着在 Python 中被解释为 bool

所以,如果 numpy 允许这个描述器指定一个 dtype,这意味着每个单元格都是 24 个字节,解释为一个小端整数,解释为一个布尔值。当然 numpy 不知道如何处理除 1、2、4 或 8 字节之外的任何长度的整数,并且它希望 bools 为 1 字节,因此不允许。但是您可以读取与 24 个单独的布尔值相同的内容。

你是怎么做到的?只需将descr 字符串更改为'?',将shape 更改为(30, 20, 24),现在你就有了一个30x20x24 的布尔数组,如果你切片[..., 0],你会得到一个30x20 的布尔数组。或者,'24?' 可能会这样做,而无需更改 shape

问题是,您的 C++ 值是双精度值,而不是布尔值。

希望它只是以 little-endian 格式编写双打,每个双打后有 16 个额外的 0 字节。如果是这样,只需将descr 更改为'&lt;f8',将shape 更改为(30, 20, 3),然后看看你会得到什么。如果第一个 (30, 20) 是您想要的数组,而另外两个全为零,那么您就完成了;把它切片。 (如果你想减少内存使用,也许ascontiguous 它。)

【讨论】:

感谢您的快速回复。标头确实包含'descr': '&lt;?24', ,但我对答案的_Bool 部分感到困惑,因为原始向量是双精度类型。 @DMS ? 表示_Bool希望 C++ 代码实际上并没有将所有双精度数转换为布尔值,并且除了非零之外,还丢弃了关于它们的所有内容。唯一可以确定的方法是查看原始字节部分(都是\x00\x01,还是范围广泛的值?),或者只是尝试将其解析为'&lt;f8' 值的三倍如你所愿,看看它是否正确。 hexdump -C 给出: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': '&lt;?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 3d 8b 01 00 00 00 00 20 3d 8b 01 00 00 00 00 |.=...... =......| 00000060 20 3d 8b 01 00 00 00 00 00 ff 00 00 00 ff 00 00 | =..............| 嗯,这很难看,但它看起来像一个值范围。 无论如何,除非你的双打都超小,否则我认为数据可能会丢失。例如,前 8 个原始字节大约是 1e-316 作为 little-endian double,即使转换为浮点数和零填充,它也大约是 5e-38。不管怎样,我猜这不是你的实际第一个值?【参考方案2】:

根据您提供的示例中npy_save() 参数的格式,您有一个错误。

而不是,

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

你想要,

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

【讨论】:

以上是关于numpy.load 给出 ValueError: descr is not a valid dtype 描述符:的主要内容,如果未能解决你的问题,请参考以下文章

使用 numpy.load 时遇到问题

GridSearchCV 给出 ValueError:DecisionTreeRegressor 不支持连续

决策树 accuracy_score 给出“ValueError:发现样本数量不一致的输入变量”

用户输入给出“ValueError:int() 以 10 为底的无效文字:”

连接两个 NumPy 数组给出“ValueError:所有输入数组必须具有相同的维数”

Django ORM 迁移在 IntegerField 上给出“ValueError:int() 的无效文字”