【发布时间】:2016-11-04 10:25:07
【问题描述】:
您能否帮助了解原生 int 类型与 numpy.int32 或 numpy.int64 类型之间的主要区别(如果有)是什么?
【问题讨论】:
您能否帮助了解原生 int 类型与 numpy.int32 或 numpy.int64 类型之间的主要区别(如果有)是什么?
【问题讨论】:
有几个主要区别。首先是 python 整数是灵活大小的(至少在 python 3.x 中)。这意味着它们可以增长以适应任意数量的任意大小(当然,在内存限制范围内)。另一方面,numpy 整数是固定大小的。这意味着它们可以保持最大值。这是由整数中的字节数定义的(int32 vs. int64),更多的字节包含更大的数字,以及数字是有符号还是无符号(int32 vs. uint32), unsigned 可以容纳更大的数字,但不能容纳负数。
那么,您可能会问,为什么要使用固定大小的整数?原因是现代处理器具有用于对固定大小的整数进行数学运算的内置工具,因此对它们的计算要快得多、快得多、快得多。事实上,当数字足够小时,python 在幕后使用固定大小的整数,只有当数字太大时才切换到速度较慢、大小灵活的整数。
固定大小值的另一个优点是它们可以放置到相同类型的大小一致的相邻内存块中。这是 numpy 数组用于存储数据的格式。 numpy 所依赖的库能够对这种格式的数据进行极快的计算,实际上现代 CPU 具有用于加速这种计算的内置功能。使用可变大小的 Python 整数,这种计算是不可能的,因为没有办法说块应该有多大,也没有数据格式的一致性。
话虽如此,numpy 实际上能够制作 Python 整数数组。但它们不是包含值的数组,而是包含对保存实际 python 整数的其他内存片段的引用的数组。这不能以同样的方式加速,所以即使所有的python整数都在固定的整数大小范围内,它仍然不会被加速。
Python 2 并非如此。在 Python 2 中,Python 整数是固定整数,因此可以直接转换为 numpy 整数。对于可变长度整数,Python 2 具有 long 类型。但这令人困惑,并且认为这种混乱不值得提高性能,尤其是当需要性能的人无论如何都会使用 numpy 或类似的东西时。
【讨论】:
查看差异的另一种方法是询问这两种对象有哪些方法。
在 Ipython 中,我可以使用 tab complete 来查看方法:
In [1277]: x=123; y=np.int32(123)
int 方法和属性:
In [1278]: x.<tab>
x.bit_length x.denominator x.imag x.numerator x.to_bytes
x.conjugate x.from_bytes x.real
int'运营商'
In [1278]: x.__<tab>
x.__abs__ x.__init__ x.__rlshift__
x.__add__ x.__int__ x.__rmod__
x.__and__ x.__invert__ x.__rmul__
x.__bool__ x.__le__ x.__ror__
...
x.__gt__ x.__reduce_ex__ x.__xor__
x.__hash__ x.__repr__
x.__index__ x.__rfloordiv__
np.int32 方法和属性(或属性)。有些相同,但更多,基本上都是ndarray:
In [1278]: y.<tab>
y.T y.denominator y.ndim y.size
y.all y.diagonal y.newbyteorder y.sort
y.any y.dtype y.nonzero y.squeeze
...
y.cumsum y.min y.setflags
y.data y.nbytes y.shape
y.__ 方法看起来很像 int 方法。他们可以做同样的数学运算。
In [1278]: y.__<tab>
y.__abs__ y.__getitem__ y.__reduce_ex__
y.__add__ y.__gt__ y.__repr__
...
y.__format__ y.__rand__ y.__subclasshook__
y.__ge__ y.__rdivmod__ y.__truediv__
y.__getattribute__ y.__reduce__ y.__xor__
y 在许多方面与 0d 数组相同。不完全相同,但很接近。
In [1281]: z=np.array(123,dtype=np.int32)
np.int32 是我在索引该类型的数组时得到的:
In [1300]: A=np.array([0,123,3])
In [1301]: A[1]
Out[1301]: 123
In [1302]: type(A[1])
Out[1302]: numpy.int32
我必须使用item 删除所有numpy 包装。
In [1303]: type(A[1].item())
Out[1303]: int
作为numpy 用户,np.int32 是带有numpy 包装器的int。或者相反,ndarray 的单个元素。通常我不会注意 A[0] 是否给了我“本机”int 或 numpy 等价物。对比一些新用户,我很少用np.int32(123);我会改用np.array(123)。
A = np.array([1,123,0], np.int32)
不包含 3 个np.int32 对象。相反,它的数据缓冲区是 3*4=12 字节长。数组开销将其解释为 1d 中的 3 个整数。 view 向我展示了具有不同解释的相同数据缓冲区:
In [1307]: A.view(np.int16)
Out[1307]: array([ 1, 0, 123, 0, 0, 0], dtype=int16)
In [1310]: A.view('S4')
Out[1310]: array([b'\x01', b'{', b''], dtype='|S4')
只有当我索引单个元素时,我才会得到一个np.int32 对象。
列表L=[1, 123, 0]不同;它是一个指针列表 - 指向内存中其他位置的 int 对象的指针。对于 dtype=object 数组也是如此。
【讨论】:
我认为最大的区别在于 numpy 类型与它们的 C 对应物兼容。一方面,这意味着 numpy ints 可能会溢出...
>>> np.int32(2**32)
0
这就是为什么您可以创建一个整数数组并将数据类型指定为 np.int32 的原因。然后,Numpy 将分配一个足够大的数组来保存指定数量的 32 位整数,然后当您需要这些值时,它会将 C 整数转换为 np.int32(这非常快)。能够从 np.int32 和 C-int 来回转换的好处还包括节省大量内存。 Python 对象通常很大:
>>> sys.getsizeof(1)
24
np.int32 一点也不小:
>>> sys.getsizeof(np.int32(1))
28
但请记住,大多数时候当我们使用 numpy 数组时,我们只使用只占用 4 个字节(而不是 24 个字节)的 C 整数。在处理数组中的标量值时,我们只需要使用np.int32。
【讨论】:
24 和28 的尺寸吗?