在安装 NumPy 并使一些代码正常工作之后,该介绍 NumPy 的基础知识了。
我们将在本章中介绍的主题如下:
- 数据类型
- 数组类型
- 类型转换
- 数组创建
- 索引
- 切片
- 形状操作
在开始之前,让我对本章中的代码示例进行一些说明。 本章中的代码段显示了几个 IPython 会话的输入和输出。 回想一下,在第 1 章, “NumPy 快速入门”中引入了 IPython,它是科学计算选择的交互式 Python shell。 IPython 的优点是--pylab
开关可以导入许多科学计算 Python 包,包括 NumPy,并且不需要显式调用print()
函数来显示变量值。 其他功能还包括轻松的并行计算和 Web 浏览器中持久工作表形式的笔记本界面。
但是,本书随附的源代码是使用import
和print
语句的常规 Python 代码。
NumPy 具有一个名为ndarray
的多维数组对象。 它由两部分组成:
- 实际数据
- 一些描述数据的元数据
大多数数组操作都保持原始数据不变。 更改的唯一方面是元数据。
在上一章中,我们已经学习了如何使用arange()
函数创建数组。 实际上,我们创建了一个包含一组数字的一维数组。 ndarray
对象可以具有多个维度。
NumPy 数组通常是同质的(“实战时间 – 创建记录数据类型”部分中介绍了一种异类的特殊数组类型)—数组中的项目必须是同一类型。 好处是,如果我们知道数组中的项目属于同一类型,则很容易确定数组所需的存储大小。
NumPy 数组从 0 开始索引,就像在 Python 中一样。 数据类型由特殊对象表示。 我们将在本章中全面讨论这些对象。
让我们再次使用arange()
函数创建一个数组。 使用以下代码获取数组的数据类型:
In: a = arange(5)
In: a.dtype
Out: dtype('int64')
数组a
的数据类型为int64
(至少在我的机器上),但是如果使用 32 位 Python,则可能会得到int32
作为输出。 在这两种情况下,我们都处理整数(64 位或 32 位)。 除了数组的数据类型外,了解其形状也很重要。
在第 1 章, “NumPy 快速入门”中,我们演示了如何创建向量(实际上是一维 NumPy 数组)。 向量通常用于数学中,但是大多数时候,我们需要更高维的对象。 确定我们在几分钟前创建的向量的形状。 以下代码是创建向量的示例:
In [4]: a
Out[4]: array([0, 1, 2, 3, 4])
In: a.shape
Out: (5,)
如您所见,向量具有五个元素,其值范围从0
到4
。 数组的shape
属性是一个元组,在这种情况下为 1 个元素的元组,其中包含每个维度的长度。
Python 中的元组是一个不变的(不能更改)值序列。 创建元组后,不允许我们更改元组元素的值或追加新元素。 这使元组比列表更安全,因为您不能偶然对其进行突变。 元组的常见用例是作为函数的返回值。 有关更多示例,请查看第 3 章的“元组介绍”部分,可在 diveintopython.net 上获得。
既然我们知道如何创建向量,就可以创建多维 NumPy 数组了。 创建数组后,我们将再次想要显示其形状:
-
创建一个
2x2
数组:In: m = array([arange(2), arange(2)]) In: m Out: array([[0, 1], [0, 1]])
-
显示数组形状:
In: m.shape Out: (2, 2)
我们使用值得信赖和喜爱的arange()
和array()
函数创建了一个2 x 2
的数组。 没有任何警告,array()
函数出现在舞台上。
array()
函数根据您提供给它的对象创建一个数组。 该对象必须是类似数组的,例如 Python 列表。 在前面的示例中,我们传入了一个数组列表。 该对象是array()
函数的唯一必需参数。 NumPy 函数倾向于具有许多带有预定义默认值的可选参数。 在 IPython shell 中使用此处提供的help()
函数查看此函数的文档:
In [1]: help(array)
或使用以下速记:
In [2]: array?
当然,您可以在此示例中将array
替换为您感兴趣的另一个 NumPy 函数。
Q1. ndarray
的形状如何存储?
- 它存储在逗号分隔的字符串中。
- 它存储在列表中。
- 它存储在元组中。
现在创建一个三乘三的数组应该不难 。 试试看,检查数组形状是否符合预期。
我们有时需要选择数组的特定元素。 我们将看一下如何执行此操作,但是,首先,再次创建一个2 x 2
数组:
In: a = array([[1,2],[3,4]])
In: a
Out:
array([[1, 2],
[3, 4]])
这次是通过将列表列表传递给array()
函数来创建数组的。 现在,我们将逐一选择矩阵的每个项目。 请记住,索引从0:
开始编号
In: a[0,0]
Out: 1
In: a[0,1]
Out: 2
In: a[1,0]
Out: 3
In: a[1,1]
Out: 4
如您所见,选择数组的元素非常简单。 对于数组a
,我们只使用符号a[m,n]
,其中m
和n
是数组中该项的索引(数组的维数比本示例中的还要多)。 此屏幕快照显示了一个简单的数组示例:
Python 具有整数类型,浮点类型和复杂类型; 但是,这还不足以进行科学计算,因此,NumPy 拥有更多的数据类型 ,它们的精度取决于存储要求。
整数代表整数,例如 -1、0 和 1。浮点数对应于数学中使用的实数,例如分数或无理数,例如pi
。 由于计算机的工作方式,我们能够精确地表示整数,但是浮点数是近似值。 复数可以具有通常用i
或j
表示的虚部。 根据定义,i
是 -1 的平方根。 例如,2.5 + 3.7i
是一个复数(有关更多信息,请参阅这里)。
在实践中,我们甚至需要更多具有不同精度的类型,因此,该类型的内存大小也有所不同。 大多数 NumPy 数值类型都以数字结尾。 该数字表示与该类型关联的位的数目。 下表(根据 NumPy 用户指南改编)概述了 NumPy 数值类型:
类型 | 描述 |
---|---|
bool |
布尔(True 或False )存储为位 |
inti |
平台整数(通常为int32 或int64 ) |
int8 |
字节(-128 至 127) |
int16 |
整数(-32768 至 32767) |
int32 |
整数(-2 ** 31 到2 ** 31 -1 ) |
int64 |
整数(-2 ** 63 到2 ** 63 -1 ) |
uint8 |
无符号整数(0 到 255) |
uint16 |
无符号整数(0 到 65535) |
uint32 |
无符号整数(0 到2 ** 32-1 ) |
uint64 |
无符号整数(0 到2 ** 64-1 ) |
float16 |
半精度浮点数:符号位,5 位指数,10 位尾数 |
float32 |
单精度浮点数:符号位,8 位指数,23 位尾数 |
float64 或float |
双精度浮点数:符号位,11 位指数,52 位尾数 |
complex64 |
复数,由两个 32 位浮点数表示(实部和虚部) |
complex128 或complex |
复数,由两个 64 位浮点数表示(实部和虚部) |
对于浮点类型,我们可以使用此处提供的finfo()
函数来请求信息:
In: finfo(float16)
Out: finfo(resolution=0.0010004, min=-6.55040e+04, max=6.55040e+04, dtype=float16)
对于每种数据类型,都有一个对应的转换函数:
In: float64(42)
Out: 42.0
In: int8(42.0)
Out: 42
In: bool(42)
Out: True
In: bool(0)
Out: False
In: bool(42.0)
Out: True
In: float(True)
Out: 1.0
In: float(False)
Out: 0.0
许多函数都有一个数据类型参数,该参数通常是可选的:
In: arange(7, dtype=uint16)
Out: array([0, 1, 2, 3, 4, 5, 6], dtype=uint16)
重要的是要知道您不允许将复数转换为整数或浮点数。 尝试执行触发TypeError
的 ,如以下屏幕截图所示:
将复数转换为浮点数也是如此。
Python 中的异常是一种异常情况,我们通常会尝试避免这种情况。 TypeError
是 Python 内置的异常,当我们为参数指定错误的类型时发生。
j
部分是复数的虚数系数。 但是,您可以将浮点数转换为复数,例如complex(1.0)
。
数据类型对象是numpy.dtype
类。 再次,数组具有数据类型。 确切地说,NumPy 数组中的每个元素都具有相同的数据类型。 数据类型对象可以告诉您数据的大小(以字节为单位)。 以字节为单位的大小由dtype
类的itemsize
属性给出:
In: a.dtype.itemsize
Out: 8
包括字符代码是为了与数字向后兼容。 数字是 NumPy 的前身。 虽然不建议使用,但此处提供代码,因为它们会在多个位置出现。 相反,我们应该使用dtype
对象。 下表显示了字符代码:
类型 | 字符码 |
---|---|
整数 | i |
无符号整数 | u |
单精度浮点 | f |
双精度浮点 | d |
布尔型 | b |
复数 | D |
字符串 | S |
Unicode | U |
无 | V |
查看以下代码以创建单精度浮点数数组:
In: arange(7, dtype='f')
Out: array([ 0., 1., 2., 3., 4., 5., 6.], dtype=float32)
同样,这将创建一个复数数组。
In: arange(7, dtype='D')
Out: array([ 0.+0.j, 1.+0.j, 2.+0.j, 3.+0.j, 4.+0.j, 5.+0.j, 6.+0.j])
Python 类具有函数,如果它们属于一个类,则这些函数称为方法。 其中某些方法是特殊的, 用于创建新对象。 这些专门方法称为构造器。
您可以在这个页面上阅读有关 Python 类的更多信息。
我们有多种创建数据类型的方法。 以浮点数据为例:
-
使用通用的 Python 浮点数:
In: dtype(float) Out: dtype('float64')
-
用字符代码指定一个单精度浮点数:
In: dtype('f') Out: dtype('float32')
-
使用双精度浮点字符代码:
In: dtype('d') Out: dtype('float64')
-
我们可以给数据类型构造器一个两个字符的代码。 第一个字符表示类型,第二个字符是一个数字,用于指定类型中的字节数(数字 2、4 和 8 对应于 16、32 和 64 位浮点数):
In: dtype('f8') Out: dtype('float64')
可以使用sctypeDict.keys()
函数找到所有完整数据类型名称的列表:
In: sctypeDict.keys()
Out: [0, …
'i2',
'int0']
dtype
类具有许多有用的属性。 例如,通过dtype
的属性获取有关数据类型的字符代码的信息:
In: t = dtype('Float64')
In: t.char
Out: 'd'
dtype
属性对应于数组元素的对象类型:
In: t.type
Out: <type 'numpy.float64'>
dtype
类的str
属性给出了数据类型的字符串表示形式。 它以代表字节序的字符开头(如果合适),然后是一个字符代码,后跟一个与每个数组项所需的字节数相对应的数字。 字节序在这里指 ,即在 32 位或 64 位字中对字节进行排序的方式。 按照大端顺序,最高有效字节先存储,由>
指示。 以低字节序排列,最低有效字节先存储,由<
指示:
In: t.str
Out: '<f8'
记录数据类型是一种异构数据类型,可以认为它代表电子表格或数据库中的一行。 为了提供记录数据类型的示例,我们将为商店股票创建一条记录。 记录包含商品名称,40 个字符的字符串,商店中商品的数量(由 32 位整数表示)以及最后由 32 位浮点数表示的价格。 这些连续的步骤显示了如何创建记录数据类型:
-
创建记录:
In: t = dtype([('name', str_, 40), ('numitems', int32), ('price', float32)]) In: t Out: dtype([('name', '|S40'), ('numitems', '<i4'), ('price', '<f4')])
-
查看类型(我们也可以查看字段的类型):
In: t['name'] Out: dtype('|S40')
如果不为array()
函数提供数据类型,则将假定它正在处理浮点数。 现在要创建数组,我们实际上必须指定数据类型; 否则,我们将获得TypeError
:
In: itemz = array([('Meaning of life DVD', 42, 3.14), ('Butter', 13, 2.72)], dtype=t)
In: itemz[1]
Out: ('Butter', 13, 2.7200000286102295)
我们创建了一个记录数据类型,它是一个异构数据类型。 该记录包含一个名称,该名称为字符串,数字为整数,以及以浮点数表示的价格。 该示例的代码可以在本书代码捆绑中的record.py
文件中找到。
一维 NumPy 数组的切片就像 Python 列表的切片一样工作。 从索引3
到7
中选择一个数组 ,该数组提取元素3
至6
:
In: a = arange(9)
In: a[3:7]
Out: array([3, 4, 5, 6])
通过步骤 2 从索引0
到7
中选择元素,如下所示:
In: a[:7:2]
Out: array([0, 2, 4, 6])
同样,与 Python 中一样,使用负索引并使用以下代码片段反转数组:
In: a[::-1]
Out: array([8, 7, 6, 5, 4, 3, 2, 1, 0])
ndarray
类支持在多个维度上切片。 为了方便 ,我们一次用省略号指代许多尺寸。
-
为了说明这一点,请使用
arange()
函数创建一个数组并调整其形状:In: b = arange(24).reshape(2,3,4) In: b.shape Out: (2, 3, 4) In: b Out: array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]])
数组
b
具有24
元素,其值从0
至23
,我们将其重构为2×3×4
的三维数组。 我们可以将其可视化为一个两层楼的架构,每层有 12 个房间,3 行和 4 列(或者我们可以将其视为包含工作表,行和列的电子表格)。 您可能已经猜到了,reshape()
函数会更改数组的形状。 我们给它一个整数元组,对应于新的形状。 如果维度与数据不兼容,则会引发异常。 -
我们可以使用其三个坐标(即楼层,列和行)选择一个房间。 例如,可以表示行和第一列中的房间(我们可以有 0 层,房间 0,这只是一个惯例)。 由以下各项组成:
In: b[0,0,0] Out: 0
-
如果我们不在乎楼层,但仍然想要第一列和第一行,则将第一个索引替换为
a:
(冒号),因为我们只需要指定楼层号并省略其他指标:In: b[:,0,0] Out: array([ 0, 12])
选择此代码中的第一层:
In: b[0] Out: array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]])
我们也可以这样写:
In: b[0, :, :] Out: array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]])
省略号(...)替换了多个冒号,因此,前面的代码等效于此:
In: b[0, ...] Out: array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]])
此外,在第一层获得第二行:
In: b[0,1] Out: array([4, 5, 6, 7])
-
带有步长的切片:此外,还要选择此选择的每隔一个元素:
In: b[0,1,::2] Out: array([4, 6])
-
带有省略号的切片:如果我们要选择第二列中两层的所有房间,而不管是哪一行,请键入以下代码:
In: b[...,1] Out: array([[ 1, 5, 9], [13, 17, 21]])
同样,通过编写以下代码段,选择第二行中的所有房间,而不管楼层和列如何:
In: b[:,1] Out: array([[ 4, 5, 6, 7], [16, 17, 18, 19]])
如果我们要在第一层第二栏中选择房间,请输入以下内容:
In: b[0,:,1] Out: array([1, 5, 9])
-
使用负索引:如果我们要选择第一层,最后一列,然后输入以下代码段:
In: b[0,:,-1] Out: array([ 3, 7, 11])
如果我们要选择一楼的房间,则将最后一列颠倒过来,然后输入以下代码片段:
In: b[0,::-1, -1] Out: array([11, 7, 3])
选择该片的第二个元素,如下所示:
In: b[0,::2,-1] Out: array([ 3, 11])
反转一维数组的命令将起始放到末尾,如下所示:
In: b[::-1] Out: array([[[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]], [[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]])
我们使用几种不同的方法对多维 NumPy 数组进行了切片。 该示例的代码可以在本书代码捆绑中的slicing.py
文件中找到。
我们已经了解了reshape()
函数。 另一个重复执行的任务是将数组展平。 展平多维 NumPy 数组时,结果是具有相同数据的一维数组。
-
展开(
ravel
):使用ravel()
函数完成:In: b Out: array([[[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]]) In: b.ravel() Out: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23])
-
展开(
flatten
):适当的命名函数flatten()
与ravel()
相同,但flatten()
总是分配新的内存,而ravel()
可能会返回数组的视图。 视图是共享数组的一种方法,但是您需要对视图小心 ,因为修改视图会影响基础数组,因此会影响其他视图。 数组副本更安全; 但是,它使用更多的内存:In: b.flatten() Out: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23])
-
使用元组设置形状:除了
reshape()
函数外,我们还可以直接使用元组设置形状,如下所示:In: b.shape = (6,4) In: b Out: array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]])
如您所见,这将直接更改数组。 现在,我们有了一个六乘四的数组。
-
转置:在线性代数中,转置矩阵很常见。
线性代数是数学的一个分支,其中涉及矩阵。 矩阵是向量的二维等效项,并且包含矩形或正方形网格中的数字。 转置矩阵需要以使矩阵行变为矩数组的方式翻转矩阵,反之亦然。 可汗学院开设了关于线性代数的课程,其中包括矩阵中的转置矩阵。
我们也可以使用以下代码来做到这一点:
In: b.transpose() Out: array([[ 0, 4, 8, 12, 16, 20], [ 1, 5, 9, 13, 17, 21], [ 2, 6, 10, 14, 18, 22], [ 3, 7, 11, 15, 19, 23]])
-
调整大小:
resize()
方法的作用与reshape()
函数相同,但是修改了它在数组上执行的操作:In: b.resize((2,12)) In: b Out: array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]])
我们使用ravel()
函数,flatten()
函数,reshape()
函数和resize()
方法操纵 NumPy 数组的形状,如下表所示:
函数 | 描述 |
---|---|
ravel() |
此函数返回一维数组,其数据与输入数组相同,并不总是返回副本 |
flatten() |
这是ndarray 的方法,它会展平数组并始终返回数组的副本 |
reshape() |
此函数修改数组的形状 |
resize() |
此函数更改数组的形状,并在必要时添加输入数组的副本 |
该示例的代码在本书代码捆绑的shapemanipulation.py
文件中。
数组可以水平,深度或垂直堆叠。 为此,我们可以使用vstack()
,dstack()
,hstack()
,column_stack()
,row_stack()
和concatenate()
函数。
首先,设置一些数组:
In: a = arange(9).reshape(3,3)
In: a
Out:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In: b = 2 * a
In: b
Out:
array([[ 0, 2, 4],
[ 6, 8, 10],
[12, 14, 16]])
-
水平堆叠:从水平堆叠开始,形成一个
ndarray
对象的元组,并将其提供给hstack()
函数,如下所示:In: hstack((a, b)) Out: array([[ 0, 1, 2, 0, 2, 4], [ 3, 4, 5, 6, 8, 10], [ 6, 7, 8, 12, 14, 16]])
使用
concatenate()
函数可以达到以下效果(此处的axis
参数等效于笛卡尔坐标系中的轴,并且对应于数组尺寸):In: concatenate((a, b), axis=1) Out: array([[ 0, 1, 2, 0, 2, 4], [ 3, 4, 5, 6, 8, 10], [ 6, 7, 8, 12, 14, 16]])
此图显示了
concatenate()
函数的水平堆叠: -
垂直堆叠:通过垂直堆叠,再次形成元组。 这次,它被赋予
vstack()
函数,如下所示:In: vstack((a, b)) Out: array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 0, 2, 4], [ 6, 8, 10], [12, 14, 16]])
concatenate()
函数在将轴设置为 0 时产生相同的结果。这是axis
参数的默认值:In: concatenate((a, b), axis=0) Out: array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 0, 2, 4], [ 6, 8, 10], [12, 14, 16]])
下图显示了具有
concatenate()
函数的垂直堆叠: -
深度堆叠:另外,使用
dstack()
和元组的深度堆叠,沿第三个轴(深度)堆叠了数组的列表。 例如,将图像数据的二维数组彼此堆叠在一起:In: dstack((a, b)) Out: array([[[ 0, 0], [ 1, 2], [ 2, 4]], [[ 3, 6], [ 4, 8], [ 5, 10]], [[ 6, 12], [ 7, 14], [ 8, 16]]])
-
列堆叠:使用
column_stack()
函数按列将一维数组堆叠如下:In: oned = arange(2) In: oned Out: array([0, 1]) In: twice_oned = 2 * oned In: twice_oned Out: array([0, 2]) In: column_stack((oned, twice_oned)) Out: array([[0, 0], [1, 2]])
二维数组以
hstack()
的方式堆叠:In: column_stack((a, b)) Out: array([[ 0, 1, 2, 0, 2, 4], [ 3, 4, 5, 6, 8, 10], [ 6, 7, 8, 12, 14, 16]]) In: column_stack((a, b)) == hstack((a, b)) Out: array([[ True, True, True, True, True, True], [ True, True, True, True, True, True], [ True, True, True, True, True, True]], dtype=bool)
是的,您猜对了! 我们用
==
运算符比较了两个数组。==
运算符用于比较 Python 对象是否相等。 当应用于 NumPy 数组时,运算符将执行逐元素比较。 有关 Python 比较运算符的更多信息,请查看这里。 -
行堆叠:NumPy 当然也具有执行行堆叠的函数。 它称为
row_stack()
,对于一维数组,它只是将行中的数组堆叠为二维数组:In: row_stack((oned, twice_oned)) Out: array([[0, 1], [0, 2]])
二维数组的
row_stack()
函数结果等于vstack()
函数结果:In: row_stack((a, b)) Out: array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 0, 2, 4], [ 6, 8, 10], [12, 14, 16]]) In: row_stack((a,b)) == vstack((a, b)) Out: array([[ True, True, True], [ True, True, True], [ True, True, True], [ True, True, True], [ True, True, True], [ True, True, True]], dtype=bool)
我们水平,深度和垂直堆叠数组。 我们使用了vstack()
,dstack()
,hstack()
,column_stack()
,row_stack()
和concatenate()
函数,如下表所示:
此示例的代码在本书的代码包的stacking.py
文件中。
可以在垂直,水平或深度方向拆分数组。 涉及的函数是hsplit()
,vsplit()
,dsplit()
和split()
。 我们既可以拆分为相同形状的数组,也可以指示拆分之后应该发生的位置。
以下步骤演示了数组的拆分:
-
水平分割:随后的代码将数组沿水平轴分割为三个大小和形状相同的片段:
In: a Out: array([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) In: hsplit(a, 3) Out: [array([[0], [3], [6]]), array([[1], [4], [7]]), array([[2], [5], [8]])]
将它与带有附加参数
axis=1
的split()
函数调用进行比较:In: split(a, 3, axis=1) Out: [array([[0], [3], [6]]), array([[1], [4], [7]]), array([[2], [5], [8]])]
-
垂直分割:
vsplit()
沿垂直轴分割:In: vsplit(a, 3) Out: [array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]
split()
函数和axis=0
也沿垂直轴分割:In: split(a, 3, axis=0) Out: [array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]
-
深度分割:
dsplit()
函数毫不奇怪地是深度拆分。 分割前先创建一个排列为 3 的数组:In: c = arange(27).reshape(3, 3, 3) In: c Out: array([[[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8]], [[ 9, 10, 11], [12, 13, 14], [15, 16, 17]], [[18, 19, 20], [21, 22, 23], [24, 25, 26]]]) In: dsplit(c, 3) Out: [array([[[ 0], [ 3], [ 6]], [[ 9], [12], [15]], [[18], [21], [24]]]), array([[[ 1], [ 4], [ 7]], [[10], [13], [16]], [[19], [22], [25]]]), array([[[ 2], [ 5], [ 8]], [[11], [14], [17]], [[20], [23], [26]]])]
我们使用hsplit()
,vsplit()
,dsplit()
和split()
函数拆分数组。 这些功能拆分的轴是不同的。 该示例的代码在本书代码捆绑的splitting.py
文件中。
除了shape
,和dtype
属性外,ndarray
还有许多其他属性,如下表所示:
-
ndim
属性提供了维度数:In: b Out: array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]]) In: b.ndim Out: 2
-
size
属性包含元素数。 如下所示:In: b.size Out: 24
-
itemsize
属性提供数组中每个元素的字节数:In: b.itemsize Out: 8
-
如果需要数组所需的字节总数,可以查看
nbytes
。 这只是itemsize
和size
属性的乘积:In: b.nbytes Out: 192 In: b.size * b.itemsize Out: 192
-
T
属性具有transpose()
函数的相同效果,如下所示:In: b.resize(6,4) In: b Out: array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]) In: b.T Out: array([[ 0, 4, 8, 12, 16, 20], [ 1, 5, 9, 13, 17, 21], [ 2, 6, 10, 14, 18, 22], [ 3, 7, 11, 15, 19, 23]])
-
如果数组的等级低于 2,我们将只获得数组的视图:
In: b.ndim Out: 1 In: b.T Out: array([0, 1, 2, 3, 4])
NumPy 中的复数用
j.
表示。例如,创建具有复数的数组,如以下代码所示:In: b = array([1.j + 1, 2.j + 3]) In: b Out: array([ 1.+1.j, 3.+2.j])
-
real
属性为我们提供了数组的实部,或者如果数组仅包含实数,则为数组本身:In: b.real Out: array([ 1., 3.])
-
imag
属性包含数组的虚部:In: b.imag Out: array([ 1., 2.])
-
如果数组包含复数,则数据类型也将自动变为复数:
In: b.dtype Out: dtype('complex128') In: b.dtype.str Out: '<c16'
-
flat
属性返回一个numpy.flatiter
对象。 这是获取flatiter
的唯一方法-我们无权访问flatiter
构造器。 平面迭代器使我们能够像遍历平面数组一样遍历数组,如以下示例所示:In: b = arange(4).reshape(2,2) In: b Out: array([[0, 1], [2, 3]]) In: f = b.flat In: f Out: <numpy.flatiter object at 0x103013e00> In: for item in f: print item .....: 0 1 2 3
可以直接通过
flatiter
对象获取元素:In: b.flat[2] Out: 2
并且,还可以直接获取多个元素:
In: b.flat[[1,3]] Out: array([1, 3])
flat
属性是可设置的。 设置flat
属性的值会导致覆盖整个数组的值:In: b.flat = 7 In: b Out: array([[7, 7], [7, 7]])
或者,它也可能导致覆盖所选元素的值:
In: b.flat[[1,3]] = 1 In: b Out: array([[7, 1], [7, 1]])
下图显示了
ndarray
类的不同类型的属性:
使用tolist()
函数将 NumPy 数组转换为 Python 列表:
-
转换为列表:
In: b Out: array([ 1.+1.j, 3.+2.j]) In: b.tolist() Out: [(1+1j), (3+2j)]
-
函数
astype()
将数组转换为指定类型的数组:In: b Out: array([ 1.+1.j, 3.+2.j]) In: b.astype(int) /usr/local/bin/ipython:1: ComplexWarning: Casting complex values to real discards the imaginary part #!/usr/bin/python Out: array([1, 3])
从 NumPy 复杂类型(而不是普通的 Python 版本)转换为
int
时,我们将丢失虚部。astype()
函数还接受类型名称作为字符串。In: b.astype('complex') Out: array([ 1.+1.j, 3.+2.j])
这次我们不会显示任何警告,因为我们使用了正确的数据类型。
我们将 NumPy 数组转换为列表和不同数据类型的数组。 该示例的代码在本书代码捆绑的arrayconversion.py
文件中。
在本章中,您学习了很多有关 NumPy 的基础知识:数据类型和数组。 数组有几个描述它们的属性。 您了解到这些属性之一是数据类型,在 NumPy 中,数据类型由完整的对象表示。
就像 Python 列表一样,可以以高效的方式对 NumPy 数组进行切片和索引。 NumPy 数组具有处理多个维度的附加功能。
数组的形状可以通过多种方式进行操作-堆叠,调整大小,调整形状和拆分。 本章演示了许多用于形状处理的便捷函数。
了解了基础知识之后,是时候进入第 3 章,“熟悉常用函数”了,其中包括了基本函数。 统计和数学函数。