python - ValueError:当更改为更大的 dtype 时,其大小必须是数组最后一个轴的总大小(以字节为单位)的除数
问题描述
在第三方提供的 numpy 数据集上运行时,我遇到了以下异常:
ValueError: When changing to a larger dtype, its size must be a divisor of the total size in bytes of the last axis of the array
在什么情况下numpy会提出这个问题?我的代码正在对 numpy 数组应用一个视图,我试图在其中应用一个dtype
与行中元素数匹配的结构。
X.view([('', X.dtype)] * X.shape[1])
当在函数内部调用语句时,我看到此错误f
- 但不是在每次调用此函数时f
:
ipdb> X.view([('', X.dtype)] * X.shape[1])
*** ValueError: When changing to a larger dtype, its size must be a divisor of the total size in bytes of the last axis of the array.
X
始终是具有两个轴的数组(len(X.shape)
始终为 2),因此您会期望一个长的结构dtype
以X.shape[1]
适合最后一个轴(X.shape[1]
)。
并非所有数据集都发生异常,那么是什么导致 numpy 为某些数组而不是其他数组抛出此异常?我什至看不到哪个 .py numpy 源代码抛出了这个错误。
我发现很难为此生成一个 MCVE,但我已将其缩小到一个colab 笔记本,它仍然有点大,可以在这里发布。
这里X
应该是iris
我从 scikit learn 得到的数据集的一个子集。
from sklearn.datasets import load_iris
X = load_iris().data
我的代码如下所示:
def f(X):
X_rows = X.view([('', X.dtype)] * X.shape[1])
def g(X):
f(X)
def h(X):
f(X)
# call the functions
g(X) # this runs without a problem
f(X) # this returns the error
解决方案
您正在尝试在具有不兼容内存布局的数组上创建视图,其中输出dtype
的项目大小不完全适合内存中覆盖源数组“最后一个”轴的全长所需的字节数. 如果您只是直接.dtype
在数组上设置属性,则例外也适用,而不仅仅是(在该新对象上创建一个带有set 的新对象)。ndarray.view()
ndarray
dtype
这里的“最后一个”轴是内存布局方面的“最里面”维度;对于 C 阶数组是shape[-1]
,对于 Fortran 阶数组是shape[0]
. 该维度大小乘以原始大小dtype.itemsize
必须可以被 new 整除dtype.itemsize
,否则您无法干净地“遍历”内部存储器结构。
例如,对于形状(4, 3, 5)
和 adtype.itemsize
为 8 的 C 顺序(行主顺序)数组,“最后一个”轴占用 5 * 8 == 40 字节的内存,因此您可以在此创建一个更大的视图大小为 10、20 和 40 的 dtype。但是,相同的数组但按Fortran顺序(列优先顺序)使用 4 * 8 == 32 字节的内存,将您的选项限制为仅大小为 16 和 32 的更大 dtype。
如果X.view([('', X.dtype)] * X.shape[1])
失败,则要么X.shape
具有比 2 更多的维度,要么是使用 Fortran 排序的数组。您可以通过使用更正第一个X.shape[-1]
,您可以通过查看来检查 lattr ndarray.flags['F_CONTIGUOUS']
。将这些组合成一个表达式,如下所示:
X_rows = X.view([('', X.dtype)] * X.shape[0 if X.flags['F_CONTIGUOUS'] else -1])
但是,正如ndarray.view()
文档警告的那样:
dtype
通常应避免在由切片、转置、fortran 排序等定义的数组上使用更改大小(每个条目的字节数)的视图。[.]
当您尝试更改 Fortran 顺序数组的 dtype 时,会引发警告:
DeprecationWarning: Changing the shape of an F-contiguous array by descriptor assignment is deprecated. To maintain the Fortran contiguity of a multidimensional Fortran array, use 'a.T.view(...).T' instead
所以最好转置数组,创建视图,然后再次转置结果视图:
if X.flags['F_CONTIGUOUS']:
X_rows = X.T.view([('', X.dtype)] * X.shape[0]).T
你仍然需要坚持X.shape[0]
这里,那是shape[-1]
转置数组。
不赞成更改对 Fortran 顺序数组的支持这一事实dtype
也可以解释异常对“最后一个轴”的引用,这在 C 顺序数组方面是非常自然的,但在应用于 Fortran 顺序数组时感觉违反直觉.
我什至看不到哪个 .py numpy 源代码抛出了这个错误。
Numpy 主要是用 C 语言编写的(带有少量 Fortran 77),因此您需要深入研究已编译组件的源代码。dtype
错误在描述符设置器函数中引发,这里在PyArray_View()
函数调用PyObject_SetAttrString()
函数以设置dtype
属性时调用该函数,当从ndarray.view()
方法调用它时。
根据源代码,不仅不推荐更改 Fortran 顺序数组的 dtype,而且根本不支持非连续数组的视图(这意味着如果两者都是X.flags['C_CONTIGUOUS']
,那么您根本无法更改)。X.flags['F_CONTIGUOUS']
False
dtype
推荐阅读
- reactjs - 刷新页面上的购物车项目丢失
- react-native-android - React native 如何在 expo 中测试后台任务?
- .net - 如果将自签名 SSL 证书添加到 Trusted Root Certification Authorities,是否不需要将证书添加到 WebClient ClientCertificates?
- sql - 如何将列更改为行
- google-workspace - 403 尝试安装 G Suite 市场应用程序时,当我拥有所需的权限时
- python - 制作 bash 文件以显示到终端
- c# - 当我只是尝试从网格视图中获取单元格的值时,我收到有关日期时间的错误
- bash - 在 perl 脚本中捕获 bash 输出值
- r - 列表中的行长度不同
- javascript - 如何在 JavaSript 中对对象进行排序