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: '<?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
方面做些什么?谢谢。
【问题讨论】:
通过“我能做的事情”,您是否正在寻找一个 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('<?24')
,这就是错误的来源。
如果您只是编辑 descr
和 shape
值,并确保 dict repr 保持相同的长度(通过用空格填充),那么您可以使用 load
。
那么,<?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
更改为'<f8'
,将shape
更改为(30, 20, 3)
,然后看看你会得到什么。如果第一个 (30, 20)
是您想要的数组,而另外两个全为零,那么您就完成了;把它切片。 (如果你想减少内存使用,也许ascontiguous
它。)
【讨论】:
感谢您的快速回复。标头确实包含'descr': '<?24',
,但我对答案的_Bool
部分感到困惑,因为原始向量是双精度类型。
@DMS ?
表示_Bool
。 希望 C++ 代码实际上并没有将所有双精度数转换为布尔值,并且除了非零之外,还丢弃了关于它们的所有内容。唯一可以确定的方法是查看原始字节部分(都是\x00
和\x01
,还是范围广泛的值?),或者只是尝试将其解析为'<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': '<?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 描述符:的主要内容,如果未能解决你的问题,请参考以下文章
GridSearchCV 给出 ValueError:DecisionTreeRegressor 不支持连续
决策树 accuracy_score 给出“ValueError:发现样本数量不一致的输入变量”
用户输入给出“ValueError:int() 以 10 为底的无效文字:”