gpt4 book ai didi

python - numpy.view给定valueError

转载 作者:行者123 更新时间:2023-11-28 22:53:21 25 4
gpt4 key购买 nike

在libtiff保存文件的上下文中遇到了这个问题,但现在我只是感到困惑。有人能告诉我为什么这两个不相等吗?

ar1 = zeros((1000,1000),dtype=uint16)
ar1 = ar1.view(dtype=uint8) # works

ar2 = zeros((1000,2000),dtype=uint16)
ar2 = ar2[:,1000:]
ar2 = ar2.view(dtype=uint8) # ValueError: new type not compatible with array.

编辑:
所以这也行吗?
ar2 = zeros((1000,2000),dtype=uint16)
ar2 = array(ar2[:,1000:])
ar2 = ar2.view(dtype=uint8)

最佳答案

摘要
简而言之,就是在切片之前移动视图。
而不是:

ar2 = zeros((1000,2000),dtype=uint16)
ar2 = ar2[:,1000:]
ar2 = ar2.view(dtype=uint8)

做:
ar2 = zeros((1000,2000),dtype=uint16)
ar2 = ar2.view(dtype=uint8) # ar2 is now a 1000x4000 array...
ar2 = ar2[:,2000:] # Note the 2000 instead of 1000!

所发生的情况是,切片数组不是连续的(正如@Craig所指出的),并且在保守的方面有 view个错误,并且不会尝试重新解释非连续的内存缓冲区。(在这种情况下,这是可能的,但在某些情况下,这会导致一个非均匀跨步数组,而numpy不允许这样做。)
如果您不太熟悉 numpy,则可能是您误解了 view,实际上您需要 astype
view做什么?
首先,让我们详细了解一下 view的作用。在这种情况下,如果可能,它会将numpy数组的内存缓冲区重新解释为新的数据类型。这意味着当您使用view时,数组中元素的数量经常会改变。(您也可以使用它将数组视为 ndarray的另一个子类,但我们现在将跳过这一部分。)
你可能已经意识到了以下问题(你的问题有点微妙),但如果没有,这里有一个解释。
例如:
In [1]: import numpy as np

In [2]: x = np.zeros(2, dtype=np.uint16)

In [3]: x
Out[3]: array([0, 0], dtype=uint16)

In [4]: x.view(np.uint8)
Out[4]: array([0, 0, 0, 0], dtype=uint8)

In [5]: x.view(np.uint32)
Out[5]: array([0], dtype=uint32)

如果要用新数据类型复制数组,请使用 astype
In [6]: x
Out[6]: array([0, 0], dtype=uint16)

In [7]: x.astype(np.uint8)
Out[7]: array([0, 0], dtype=uint8)

In [8]: x.astype(np.uint32)
Out[8]: array([0, 0], dtype=uint32)

现在让我们看看在查看二维数组时会发生什么。
In [9]: y = np.arange(4, dtype=np.uint16).reshape(2, 2)

In [10]: y
Out[10]:
array([[0, 1],
[2, 3]], dtype=uint16)

In [11]: y.view(np.uint8)
Out[12]:
array([[0, 0, 1, 0],
[2, 0, 3, 0]], dtype=uint8)

请注意,数组的形状已经改变,并且这些变化发生在最后一个轴上(在这种情况下,添加了额外的列)。
乍一看,可能是添加了额外的零。不是要插入额外的零,而是 uint162表示等于两个 uint8s,一个值为 2另一个值为 0。因此,255以下的任何 uint16都将导致值和零,而超过该值的任何值都将导致两个更小的 uint8s。例如:
In [13]: y * 100
Out[14]:
array([[ 0, 100],
[200, 300]], dtype=uint16)

In [15]: (y * 100).view(np.uint8)
Out[15]:
array([[ 0, 0, 100, 0],
[200, 0, 44, 1]], dtype=uint8)

幕后发生了什么
Numpy数组由一个“原始”内存缓冲区组成,该缓冲区通过一个形状、一个数据类型和跨步(以及一个偏移量)进行解释,但现在我们忽略它。有关更多详细信息,有几个好的概述: the official documentationthe numpy bookscipy-lectures
这使得numpy具有非常高的内存效率,并且可以以许多不同的方式“切片”底层内存缓冲区,而无需复制。
步长告诉NUMPY在内存缓冲器中跳转多少字节,以沿着一个特定轴进行一个增量。
例如:
In [17]: y
Out[17]:
array([[0, 1],
[2, 3]], dtype=uint16)

In [18]: y.strides
Out[18]: (4, 2)

因此,要在数组中深入一行,numpy需要在内存缓冲区中前进4个字节,而要在数组中深入一列,numpy需要前进2个字节。对数组进行转置就等于反转跨步(和形状,但在本例中, y是2x2):
In [19]: y.T.strides
Out[19]: (2, 4)

当我们将数组视为 uint8时,跨步会发生变化。我们仍然每行前进4个字节,但每列只有一个字节:
In [20]: y.view(np.uint8).strides
Out[20]: (4, 1)

但是,numpy数组必须具有每个维度一个跨距长度。这就是“匀速前进”的意思。换句话说,向前移动一行/列/不管怎样,numpy每次都需要能够在底层内存缓冲区中步进相同的数量。换句话说,没有办法告诉numpy为每一行/每一列/每一种类型的数据分步不同的数量。
因此, view走的是一条非常保守的路线。如果数组不是连续的,并且视图会改变数组的形状和步幅,那么它不会尝试处理它。正如@Craig所指出的,正是因为 y的片段不连续, view才不起作用。
在很多情况下(你的就是其中之一),结果数组是有效的,但是 view方法并不试图对此过于聪明。
要想真正发挥其作用,您可以使用 numpy.lib.stride_tricks.as_strided或直接使用 __array_interface__。它是一个很好的学习工具,可以用来进行实验,但你必须真正了解你在做什么,才能有效地使用它。
无论如何,希望这能帮上一点忙!对不起,你的回答太冗长了!

关于python - numpy.view给定valueError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19521493/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com