当我意识到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
。
我的第二个问题是:如果更改特定值,为什么它不支持创建数组时的逻辑?为什么不重新计算和重新评估?
感谢您的帮助。预先感谢。
答案 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中的许多习惯用法都依赖于视图,并且事实是,写入视图会直接修改基本数组(和其他重叠视图)。因此,数组不会随时随意更改其数据缓冲区。为了不中断视图之间的链接,阵列必须知道其数据缓冲区中的所有视图,这会增加很多管理开销,并且所有这些视图也必须更改其数据指针和元数据。而且,如果第一个数组本身是另一个数组的视图(例如一个切片),那么情况就更糟了。
我想我们可以就不值得达成共识,这就是为什么类型不能就地推广的原因。