在上一节中,我们介绍了 ndarray 对象的常用属性,其中包含了 dtype 数据类型, Numpy 作为科学计算计算的基础包,它的数据类型会比 Python 内置的数据类型表达的更为清晰,在本节除了介绍 ndarray 数据数据类型外,还讲解一些有关它一些基本操作,比如设置 dtype 的方式等。
dtype 表明了 ndarray 的数据类型,它属于 nadarry 数据的描述性信息,Numpy 能够与其他系统的数据灵活交互依赖于 dtype 实现。在 Numpy 中 对于 整数 int 又分为 有符号(int32)和无符号(uint32)的整数,有符号取值范围包含负数,而无符号不包含,比如 int 的取值范围是整数(-128 to 127)而无符号则是(0 to 255);对于 float 类型分为半精度浮点数,标准单精度浮点数与标准双精度浮点数。
Numpy 中数据类型命名有一定的规则,比如 int64 或者 int32,它是以类型名与数组中每个元素位数构成,若系统中一个元素由 8 个字节组成,那么它就是 64 位(1byte= 8bits);若一个元素由 4 字节组成,那么就是 32 位。不过在一般的情况下,我们只需要关心数据的数据类型,至于数据以多少位存储,属于细枝末节的事情了。了解了命名规则后,我们就来看一下 Numpy 的基本数据类型:
类型名称 | 类型代码 | 类型标识符 | 备注描述 |
---|---|---|---|
布尔值 | ? | bool_ | 布尔值,存储 True或者 False。 |
有符号整数型 | i1/i2/i4/i8 | int8/int16/int32/int64 | 用来表示有符号的整数分别8/16/32/64。 |
无符号整数型 | u1/u2/u4/u8 | uint8/uint16/uint32/uint64 | 用来表示无符号的整数分别8/16/32/64。 |
浮点型 | f2/f4/f8/f16或f | float16/float32/float64/float128 | 用来表示浮点数,位数代表浮点的精度。 |
复数型 | c8/c16/c32或者D | complex64/complex128/complex256 | 基于32/64/128位浮点数的复数。 |
字节串型 | S | string_ | 'S10'表示生成一个长度为10个字节串类型 |
object对象型 | O | object | Python object类型。 |
unicode类型 | U | unicode_或str | 'U10'生成一个长度为10的unicode字符串类型。 |
Python 自身虽然支持整型、浮点型和复数型,但对于科学计算来说,还远远不够。现实中,我们仍然需要更多的数据类型,来满足在精度和存储大小方面的各种不同的要求。为此,NumPy 提供了上述表格中丰富的数据类型。上述 NumPy 跟数学运算有关的数据类型的名称都以数字结尾,这个数字指示了该类型的数组中数值元素所占用的二进制位数。
在 Numpy 中完成数据类型之间转换可以使用 astype 方法,它使用示例如下所示:
In [1]: import numpy as np
In [2]: data=np.arange(2,6,1)
In [3]: data
Out[3]: array([2, 3, 4, 5])
#使用reshape进行变维操作生成二维数组
In [4]: data.reshape(2,2)
Out[4]:
array([[2, 3],
[4, 5]])
In [5]: data.dtype
Out[5]: dtype('int32')
#设置为int64
In [6]: data.astype(np.int64)
Out[6]: array([2, 3, 4, 5], dtype=int64)
#设置为 float32,增加了小数点
In [7]: data1=data.astype(np.float32)
In [8]: data1
Out[8]: array([2., 3., 4., 5.], dtype=float32)
In [9]: num_str=np.array([0,'9.6','12'],dtype=np.bool_)
#0代表False
In [10]: num_str
Out[10]: array([False, True, True])
我们还可以直接适应 dtype 属性完成 Numpy 数据类型的转化,如下所示:
ln [11]: import numpy as np
In [12]: a=np.array([1,2,3,4,5,6,8])
In [13]: a.dtype
Out[13]: dtype('int32')
In [14]: a.dtype='float32'
In [15]: a.dtype
Out[15]: dtype('float32')
使用 astype 方式总是会生成新的数组,在内存上表现为接受数组变量的内存地址指向了新生成的数组。我们也可以直接使用类型代码进行转化,如下所示:
In [15]: num_str=np.array([0,'9.6','12'],dtype='?')
In [16]: num_str
Out[16]: array([False, True, True])
In [17]: num_str=np.array([0,'9.6','12'],dtype='S')
In [18]: num_str
Out[18]: array([b'0', b'9.6', b'12'], dtype='|S3')
In [19]: num_str=np.array(['3.2','9.6','12'])
In [20]: num_str
Out[20]: array(['3.2', '9.6', '12'], dtype='<U3')
In [21]: num_str=np.array(['a','c','s'])
In [22]: num_str
Out[22]: array(['a', 'c', 's'], dtype='<U1')
大家一定看到了上面 <U3 的类型代码,一定也会产生疑惑,这代表什么意思,其实它表示就是小端字节序的含义,如果是>则代表大端字节序。那么这到底是什么意思呢?其实计算机硬件有两种储存方式数据的方式即大端字节序和小端字节序。
在一个 32 位的 CPU 中“字长”为 32 个 bit,也就是 4 个 byte。在这样的 CPU 中,总是以 4 字节对齐的方式来读取或写入内存,那么同样这 4个 字节的数据是以什么顺序保存在内存中的呢?例如,现在我们要向内存地址为 a 的地方写入数据 0x0A0B0C0D,那么这 4 个字节分别落在哪个地址的内存上呢?这就涉及到字节序的问题了。大小端字节序就是表明是数字在内存中是以怎样的方式进行存储的。
举例来说,数值 0x2211 使用两个字节储存:高位字节是 0x22,低位字节是 0x11。
那为什会存在自己序呢,这和计算机内部的结构有关,这里不做深究,大家明白简单了解即可:计算机电路先处理低位字节,效率比较高,因为计算都是从低位开始的。所以,计算机的内部处理都是小端字节序。但是,人类还是习惯读写大端字节序。所以,除了计算机的内部处理,其他的场合几乎都是大端字节序,比如网络传输和文件储存等,也就是只有读取操作的时候,才必须区分字节序,其他情况都不用考虑它。
所以当在 Numpy 中遇到的时候,要理解它们的含义,如下所示:
本节关于 Numpy 数据类型的知识就讲解到此,这些会与你之前学习的 Python 数据类型有所区别,希望各位小伙伴多加理解与体悟。