numpy数组的dtype如何内部计算?

时间:2019-03-15 11:25:43

标签: python arrays numpy

当我意识到result_scan参数鲜为人知的行为时,我只是在弄混numpy数组。

似乎随着输入的变化而变化。例如,

dtypes

给予t = np.array([2, 2]) t.dtype

但是,

dtype('int32')

给予t = np.array([2, 22222222222]) t.dtype

所以,我的第一个问题是:如何计算?它是否使数据类型适合于最大元素作为所有元素的数据类型?如果是这样,您是否不认为它需要更多空间,因为它不必要地存储多余的内存来将2作为64位整数存储在第二个数组中?

再次,如果我想更改dtype('int64')的第零个元素

array([2, 2])

我得到t = np.array([2, 2]) t[0] = 222222222222222

我的第二个问题是:如果更改特定值,为什么它不支持创建数组时的逻辑?为什么不重新计算和重新评估?

感谢您的帮助。预先感谢。

1 个答案:

答案 0 :(得分:3)

让我们尝试在文档中找到相关内容。

来自np.array文档字符串:

  

array(...)

     

[...]

     

参数

     

[...]

     

dtype:数据类型,可选       数组所需的数据类型。如果未给出,则类型将       确定为将对象保留在对象中所需的最小类型       序列。此参数只能用于“上载”阵列。对于       向下转换,请使用.astype(t)方法。

     

[...]

(我的重点)

请注意,这并不完全准确,例如,对于整数数组,如示例所示,系统(C)默认整数优先于较小的整数类型。

请注意,为了使numpy更快,数组中所有元素的大小必须相同。否则,您将如何快速定位第1000个元素?另外,混合类型不会节省太多空间,因为您必须将每个元素的类型存储在原始数据之上。

是第二个问题。首先。 numpy中有类型提升规则。我为此找到的最好的文档是np.result_type文档字符串:

  

result_type(...)result_type(* arrays_and_dtypes)

     

返回应用NumPy类型提升产生的类型   规则。

     

NumPy中的类型提升与类似语言的规则类似   C ++,略有不同。当标量和数组都为   使用时,数组的类型优先,且数组的实际值   标量被考虑在内。

     

例如,计算3 * a,其中a是32位浮点数的数组,   直观上应该导致32位浮点输出。如果3是一个   32位整数,NumPy规则表明它无法无损转换   转换为32位浮点数,因此结果类型应为64位浮点数。通过   检查常数“ 3”的值,我们发现它适合   8位整数,可以无损地转换为32位浮点数。

     

[...]

我在这里没有引用全部内容,请参阅文档字符串以获取更多详细信息。

这些规则的确切应用方式很复杂,似乎代表着直观和效率之间的折衷。

例如,选择基于输入而不是结果

>>> A = np.full((2, 2), 30000, 'i2')
>>> 
>>> A
array([[30000, 30000],
       [30000, 30000]], dtype=int16)
# 1
>>> A + 30000
array([[-5536, -5536],
       [-5536, -5536]], dtype=int16)
# 2
>>> A + 60000
array([[90000, 90000],
       [90000, 90000]], dtype=int32)

这里赢得效率。可以说#1的行为像#2那样更为直观。但这会很昂贵。

而且,与您的问题更直接相关的是,类型提升仅适用于原地,不适用于原地:

# out-of-place
>>> A_new = A + 60000
>>> A_new
array([[90000, 90000],
       [90000, 90000]], dtype=int32)
# in-place
>>> A += 60000
>>> A
array([[24464, 24464],
       [24464, 24464]], dtype=int16)

# out-of-place
>>> A_new = np.where([[0, 0], [0, 1]], 60000, A)
>>> A_new
array([[30000, 30000],
       [30000, 60000]], dtype=int32)
# in-place
>>> A[1, 1] = 60000
>>> A
array([[30000, 30000],
       [30000, -5536]], dtype=int16)

同样,这似乎很不直观。但是,这种选择有令人信服的理由。

这些应该回答您的第二个问题:

更改为更大的dtype将需要分配更大的缓冲区并复制所有数据。大型阵列不仅昂贵。

numpy中的许多习惯用法都依赖于视图,并且事实是,写入视图会直接修改基本数组(和其他重叠视图)。因此,数组不会随时随意更改其数据缓冲区。为了不中断视图之间的链接,阵列必须知道其数据缓冲区中的所有视图,这会增加很多管理开销,并且所有这些视图也必须更改其数据指针和元数据。而且,如果第一个数组本身是另一个数组的视图(例如一个切片),那么情况就更糟了。

我想我们可以就不值得达成共识,这就是为什么类型不能就地推广的原因。

相关问题