《Python数据分析基础教程:NumPy学习指南(第2版)》笔记2:第二章 NumPy基础1——数据类型

第二章 NumPy基础1

本章示例代码中的输入和输出均来自IPython会话。

2.1 NumPy数组对象

NumPy中的ndarray是一个多维数组对象,该对象由两部分组成:

  • 实际的数据;
  • 描述这些数据的元数据。

大部分的数组操作仅仅修改修改元数据部分,而不改变底层的实际数据

在第1章中,我们已经知道如何使用arange函数创建数组。实际上,当时创建的数组只是包含一组数字的一维数组,而ndarray支持更高的维度。
NumPy数组一般是同质的(但有一种特殊的数组类型例外,它是异质的),即数组中的所有元素类型必须是一致的。这样有一个好处:如果我们知道数组中的元素均为同一类型,该数组所需的存储空间就很容易确定下来。

与Python中一样,NumPy数组的下标也是从0开始的。数组元素的数据类型用专门的对象表示。

我们再次用arange函数创建数组,并获取其数据类型:

In [1]: import numpy as np
In [2]: a = np.arange(5)
In [3]: a.dtype
Out[3]: dtype('int32')

数组a的数据类型为int32(在我的机器上是这样),当然如果你使用64位的Python,得到的结果可能是int64。不论是哪种情形,该数组的数据类型都是整数(64位或32位)。

除了数据类型,数组的维度也是重要的属性。
第1章中的例子演示了怎样创建一个向量(即一维的NumPy数组)。向量在数学中很常用,但大部分情况下,我们需要更高维的对象。先来确定一下刚刚所创建向量的维度:

In [4]: a
Out[4]: array([0, 1, 2, 3, 4])
In [5]: a.shape
Out[5]: (5,)

正如你所看到的,这是一个包含5个元素的向量,取值分别为0~4的整数。数组的shape属性返回一个元组(tuple),元组中的元素即为NumPy数组每一个维度上的大小。上面例子中的数组是一维的,因此元组中只有一个元素。

2.2 动手实践:创建多维数组

既然我们已经知道如何创建向量,现在可以试着创建多维的NumPy数组,并查看其维度了。
(1) 创建一个多维数组。
(2) 显示该数组的维度。

In [6]: m = np.array([np.arange(2),np.arange(2)])
In [7]: m
Out[7]:
array([[0, 1],
       [0, 1]])
In [8]: m.shape
Out[8]: (2, 2)

我们将arange函数创建的数组作为列表元素,把这个列表作为参数传给array函数,从而创建了一个2×2的数组,而且没有出现任何报错信息。

array函数可以依据给定的对象生成数组。给定的对象应是类数组,如Python中的列表。在上面的例子中,我们传给array函数的对象是一个NumPy数组的列表。像这样的类数组对象是array函数的唯一必要参数,其余的诸多参数均为有默认值的可选参数。

问题1 ndarray对象的维度属性是以下列哪种方式存储的?
(1) 逗号隔开的字符串
(2) Python列表(list)
(3) Python元组(tuple)

2.2.1选取数组元素

有时候,我们需要选取数组中的某个特定元素。首先还是创建一个2×2的多维数组:

In [9]: a = np.array([[1,2],[3,4]])
In [10]: a
Out[10]:
array([[1, 2],
       [3, 4]])

在创建这个多维数组时,我们给array函数传递的对象是一个嵌套的列表。现在来依次选取该数组中的元素。记住,数组的下标是从0开始的。

In [11]: a[0,0]
Out[11]: 1
In [12]: a[0,1]
Out[12]: 2
In [13]: a[1,0]
Out[13]: 3
In [14]: a[1,1]
Out[14]: 4

是的,从数组中选取元素就是这么简单。对于数组a,只需要用a[m,n]选取各数组元素,其
中m和n为元素下标,对应的位置如下表所示。

在这里插入图片描述

2.2.2 NumPy数据类型

Python支持的数据类型有整型、浮点型以及复数型,但这些类型不足以满足科学计算的需求,因此NumPy添加了很多其他的数据类型。在实际应用中,我们需要不同精度的数据类型,它们占用的内存空间也是不同的。在NumPy中,**大部分数据类型名是以数字结尾的,这个数字表示其在内存中占用的位数。**下面的表格(整理自NumPy用户手册)列出了NumPy中支持的数据类型。
在这里插入图片描述
每一种数据类型均有对应的类型转换函数:

In [15]: np.float64(42)
Out[15]: 42.0
In [17]: np.int8(42.0)
Out[17]: 42
In [18]: np.bool(42)
C:\Users\administrator\AppData\Local\Programs\Python\Python37\Scripts\ipython:1: Deprecatio
nWarning: `np.bool` is a deprecated alias for the builtin `bool`. To silence thi
s warning, use `bool` by itself. Doing this will not modify any behavior and is
safe. If you specifically wanted the numpy scalar type, use `np.bool_` here.
Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdo
cs/release/1.20.0-notes.html#deprecations
Out[18]: True
In [20]: np.float(True)
C:\Users\administrator\AppData\Local\Programs\Python\Python37\Scripts\ipython:1: Deprecatio
nWarning: `np.float` is a deprecated alias for the builtin `float`. To silence t
his warning, use `float` by itself. Doing this will not modify any behavior and
is safe. If you specifically wanted the numpy scalar type, use `np.float64` here
.
Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdo
cs/release/1.20.0-notes.html#deprecations
Out[20]: 1.0

注:在1.20版本中np.boolnp.float都是对应系统函数的别名

在NumPy中,许多函数的参数中可以指定数据类型,通常这个参数是可选的:

In [23]: np.arange(7, dtype=np.uint16)
Out[23]: array([0, 1, 2, 3, 4, 5, 6], dtype=uint16)

需要注意的是,复数是不能转换为整数的,这将触发TypeError错误:

In [24]: np.int(42.0+1.j)
C:\Users\administrator\AppData\Local\Programs\Python\Python37\Scripts\ipython:1: Deprecatio
nWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this
warning, use `int` by itself. Doing this will not modify any behavior and is saf
e. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to
 specify the precision. If you wish to review your current use, check the releas
e note link for additional information.
Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdo
cs/release/1.20.0-notes.html#deprecations
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-24-4b5b3467cc1e> in <module>
----> 1 np.int(42.0+1.j)

TypeError: can't convert complex to int

同样,复数也不能转换为浮点数。不过,浮点数却可以转换为复数,例如complex(1.0)。注意,有j的部分为复数的虚部。

2.2.3数据类型对象

数据类型对象是numpy.dtype类的实例。如前所述,NumPy数组是有数据类型的,更确切地说,NumPy数组中的每一个元素均为相同的数据类型。数据类型对象可以给出单个数组元素在内存中占用的字节数,即dtype类的itemsize属性:

In [25]: a.dtype.itemsize
Out[25]: 4

2.2.4字符编码

NumPy可以使用字符编码来表示数据类型,这是为了兼容NumPy的前身Numeric。我不推荐使用字符编码,但有时会用到,因此下面还是列出了字符编码的对应表。读者应该优先使用dtype对象来表示数据类型,而不是这些字符编码。

在这里插入图片描述
下面的代码创建了一个单精度浮点数数组:

In [26]: np.arange(7, dtype='f')
Out[26]: array([0., 1., 2., 3., 4., 5., 6.], dtype=float32)

与此类似,还可以创建一个复数数组:

In [28]: np.arange(7, dtype='D')
Out[28]: array([0.+0.j, 1.+0.j, 2.+0.j, 3.+0.j, 4.+0.j, 5.+0.j, 6.+0.j])

2.2.5 自定义数据类型

我们有很多种自定义数据类型的方法,以浮点型为例。

  • 可以使用Python中的浮点数类型
In [3]: np.dtype(float)
Out[3]: dtype('float64')
  • 可以使用字符编码来指定单精度浮点数类型:
In [4]: np.dtype('f')
Out[4]: dtype('float32')
  • 可以使用字符编码来指定双精度浮点数类型:
In [5]: np.dtype('d')
Out[5]: dtype('float64')
  • 还可以将两个字符作为参数传给数据类型的构造函数。此时,第一个字符表示数据类型,第二个字符表示该类型在内存中占用的字节数(2、 4、 8分别代表精度为16、 32、 64位的浮点数):
In [6]: np.dtype('f2')
Out[6]: dtype('float16')
  • 完整的NumPy数据类型列表可以在sctypeDict.keys()中找到:
In [7]: np.sctypeDict.keys()
Out[7]: dict_keys(['?', 0, 'byte', 'b', 1, 'ubyte', 'B', 2, 'short', 'h', 3, 'ushort', 'H', 4, 'i', 5, 'uint', 'I', 6, 'intp', 'p', 9, 'uintp', 'P', 10, 'long', 'l', 7, 'L', 8, 'longlong', 'q', 'ulonglong', 'Q', 'half', 'e', 23, 'f', 11, 'double', 'd', 12, 'longdouble', 'g', 13, 'cfloat', 'F', 14, 'cdouble', 'D', 15, 'clongdouble', 'G', 16, 'O', 17, 'S', 18, 'unicode', 'U', 19, 'void', 'V', 20, 'M', 21, 'm', 22, 'bool8', 'b1', 'int64', 'i8', 'uint64', 'u8', 'float16', 'f2', 'float32', 'f4', 'float64', 'f8', 'complex64', 'c8', 'complex128', 'c16', 'object0', 'bytes0', 'str0', 'void0', 'datetime64', 'M8', 'timedelta64', 'm8', 'Bytes0', 'Datetime64', 'Str0', 'Uint64', 'int32', 'i4', 'uint32', 'u4', 'int16', 'i2', 'uint16', 'u2', 'int8', 'i1', 'uint8', 'u1', 'complex_', 'int0', 'uint0', 'single', 'csingle', 'singlecomplex', 'float_', 'intc', 'uintc', 'int_', 'longfloat', 'clongfloat', 'longcomplex', 'bool_', 'bytes_', 'string_', 'str_', 'unicode_', 'object_', 'int', 'float', 'complex', 'bool', 'object', 'str', 'bytes', 'a'])

In [8]: np.sctypeDict.items()
Out[8]: dict_items([('?', <class 'numpy.bool_'>), (0, <class 'numpy.bool_'>), ('byte', <class 'numpy.int8'>), ('b', <class 'numpy.int8'>), (1, <class 'numpy.int8'>), ('ubyte', <class 'numpy.uint8'>), ('B', <class 'numpy.uint8'>), (2, <class 'numpy.uint8'>), ('short', <class 'numpy.int16'>), ('h', <class 'numpy.int16'>), (3, <class 'numpy.int16'>), ('ushort', <class 'numpy.uint16'>), ('H', <class 'numpy.uint16'>), (4, <class 'numpy.uint16'>), ('i', <class 'numpy.intc'>), (5, <class 'numpy.intc'>), ('uint', <class 'numpy.uint32'>), ('I', <class 'numpy.uintc'>), (6, <class 'numpy.uintc'>), ('intp', <class 'numpy.int64'>), ('p', <class 'numpy.int64'>), (9, <class 'numpy.int64'>), ('uintp', <class 'numpy.uint64'>), ('P', <class 'numpy.uint64'>), (10, <class 'numpy.uint64'>), ('long', <class 'numpy.int32'>), ('l', <class 'numpy.int32'>), (7, <class 'numpy.int32'>), ('L', <class 'numpy.uint32'>), (8, <class 'numpy.uint32'>), ('longlong', <class 'numpy.int64'>), ('q', <class 'numpy.int64'>), ('ulonglong', <class 'numpy.uint64'>), ('Q', <class 'numpy.uint64'>), ('half', <class 'numpy.float16'>), ('e', <class 'numpy.float16'>), (23, <class 'numpy.float16'>), ('f', <class 'numpy.float32'>), (11, <class 'numpy.float32'>), ('double', <class 'numpy.float64'>), ('d', <class 'numpy.float64'>), (12, <class 'numpy.float64'>), ('longdouble', <class 'numpy.longdouble'>), ('g', <class 'numpy.longdouble'>), (13, <class 'numpy.longdouble'>), ('cfloat', <class 'numpy.complex128'>), ('F', <class 'numpy.complex64'>), (14, <class 'numpy.complex64'>), ('cdouble', <class 'numpy.complex128'>), ('D', <class 'numpy.complex128'>), (15, <class 'numpy.complex128'>), ('clongdouble', <class 'numpy.clongdouble'>), ('G', <class 'numpy.clongdouble'>), (16, <class 'numpy.clongdouble'>), ('O', <class 'numpy.object_'>), (17, <class 'numpy.object_'>), ('S', <class 'numpy.bytes_'>), (18, <class 'numpy.bytes_'>), ('unicode', <class 'numpy.str_'>), ('U', <class 'numpy.str_'>), (19, <class 'numpy.str_'>), ('void', <class 'numpy.void'>), ('V', <class 'numpy.void'>), (20, <class 'numpy.void'>), ('M', <class 'numpy.datetime64'>), (21, <class 'numpy.datetime64'>), ('m', <class 'numpy.timedelta64'>), (22, <class 'numpy.timedelta64'>), ('bool8', <class 'numpy.bool_'>), ('b1', <class 'numpy.bool_'>), ('int64', <class 'numpy.int64'>), ('i8', <class 'numpy.int64'>), ('uint64', <class 'numpy.uint64'>), ('u8', <class 'numpy.uint64'>), ('float16', <class 'numpy.float16'>), ('f2', <class 'numpy.float16'>), ('float32', <class 'numpy.float32'>), ('f4', <class 'numpy.float32'>), ('float64', <class 'numpy.float64'>), ('f8', <class 'numpy.float64'>), ('complex64', <class 'numpy.complex64'>), ('c8', <class 'numpy.complex64'>), ('complex128', <class 'numpy.complex128'>), ('c16', <class 'numpy.complex128'>), ('object0', <class 'numpy.object_'>), ('bytes0', <class 'numpy.bytes_'>), ('str0', <class 'numpy.str_'>), ('void0', <class 'numpy.void'>), ('datetime64', <class 'numpy.datetime64'>), ('M8', <class 'numpy.datetime64'>), ('timedelta64', <class 'numpy.timedelta64'>), ('m8', <class 'numpy.timedelta64'>), ('Bytes0', <class 'numpy.bytes_'>), ('Datetime64', <class 'numpy.datetime64'>), ('Str0', <class 'numpy.str_'>), ('Uint64', <class 'numpy.uint64'>), ('int32', <class 'numpy.int32'>), ('i4', <class 'numpy.int32'>), ('uint32', <class 'numpy.uint32'>), ('u4', <class 'numpy.uint32'>), ('int16', <class 'numpy.int16'>), ('i2', <class 'numpy.int16'>), ('uint16', <class 'numpy.uint16'>), ('u2', <class 'numpy.uint16'>), ('int8', <class 'numpy.int8'>), ('i1', <class 'numpy.int8'>), ('uint8', <class 'numpy.uint8'>), ('u1', <class 'numpy.uint8'>), ('complex_', <class 'numpy.complex128'>), ('int0', <class 'numpy.int64'>), ('uint0', <class 'numpy.uint64'>), ('single', <class 'numpy.float32'>), ('csingle', <class 'numpy.complex64'>), ('singlecomplex', <class 'numpy.complex64'>), ('float_', <class 'numpy.float64'>), ('intc', <class 'numpy.intc'>), ('uintc', <class 'numpy.uintc'>), ('int_', <class 'numpy.int32'>), ('longfloat', <class 'numpy.longdouble'>), ('clongfloat', <class 'numpy.clongdouble'>), ('longcomplex', <class 'numpy.clongdouble'>), ('bool_', <class 'numpy.bool_'>), ('bytes_', <class 'numpy.bytes_'>), ('string_', <class 'numpy.bytes_'>), ('str_', <class 'numpy.str_'>), ('unicode_', <class 'numpy.str_'>), ('object_', <class 'numpy.object_'>), ('int', <class 'numpy.int32'>), ('float', <class 'numpy.float64'>), ('complex', <class 'numpy.complex128'>), ('bool', <class 'numpy.bool_'>), ('object', <class 'numpy.object_'>), ('str', <class 'numpy.str_'>), ('bytes', <class 'numpy.bytes_'>), ('a', <class 'numpy.bytes_'>)])

2.2.6 dtype类的属性

dtype类有很多有用的属性。例如,我们可以获取数据类型的字符编码:

In [11]: t = np.dtype('float64')
In [12]: t.char
Out[12]: 'd'

type属性对应于数组元素的数据类型:

In [13]: t.type
Out[13]: numpy.float64

str属性可以给出数据类型的字符串表示,该字符串的首个字符表示字节序(endianness),后面如果还有字符的话,将是一个字符编码,接着一个数字表示每个数组元素存储所需的字节数。
这里,字节序是指位长为32或64的字(word)存储的顺序,包括大端序(big-endian)和小端序(little-endian)。大端序是将最高位字节存储在最低的内存地址处,用>表示;与之相反,小端序是将最低位字节存储在最低的内存地址处,用<表示:

In [14]: t.str
Out[14]: '<f8'

2.3 动手实践:创建自定义数据类型

自定义数据类型是一种异构数据类型,可以当做用来记录电子表格或数据库中一行数据的结构。作为示例,我们将创建一个存储商店库存信息的数据类型。其中,我们用一个长度为40个字符的字符串来记录商品名称,用一个32位的整数来记录商品的库存数量,最后用一个32位的单精度浮点数来记录商品价格。下面是具体的步骤。

  • (1) 创建数据类型:
In [15]: t = np.dtype([('name', np.str_, 40), ('numitems',np.int32), ('price',np.fl
    ...: oat32)])
In [16]: t
Out[16]: dtype([('name', '<U40'), ('numitems', '<i4'), ('price', '<f4')])
  • (2) 查看数据类型(也可以查看某一字段的数据类型) :
In [21]: t['name']
Out[21]: dtype('<U40')

**在用array函数创建数组时,如果没有在参数中指定数据类型,将默认为浮点数类型。**而现在,我们想要创建自定义数据类型的数组,就必须在参数中指定数据类型,否则将触发TypeError错误:

In [24]:  itemz = np.array([('Meaning of life DVD', 42, 3.14), ('Butter', 13, 2.72)], dtype=t)
In [25]: itemz[1]
Out[25]: ('Butter', 13, 2.72)

刚才做了些什么我们创建了一种自定义的异构数据类型,该数据类型包括一个用字符串记录的名字、一个用整数记录的数字以及一个用浮点数记录的价格。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值