Python:数据分析【1.1】
第1 章 NumPy 基础和应用
NumPy 是 Python 语言的一个第三方库,被广泛应用于数据分析领域。它实现了多维数组与矩阵的高效运算,还提供了大量的数学函数。用更高、更快、更强来描述 NumPy 并不为过, “更高”即开发效率高, “更快”即运行速度快, “更强”即数据处理方面的功能强大。毫不夸张地说, NumPy 是任何打算进入数据分析乃至机器学习、人工智能等领域的读者必须要学习并掌握的。
NumPy 的前身是一款名为 Numeric 的库, 由 Jim Hugunin 与其他协作者共同开发。 2005 年, Travis Oliphant 在 Numeric 中结合另一个同性质的库 Numarray 的特点,并加入了其他扩展而开发了 NumPy。
NumPy 是开源的,其最大的好处就是免费,因此其代码质量能够得到最大限度地保证——开源,意味着最大限度的安全。
NumPy 是数据分析“降龙十八掌”的第一招。
1.1 数组对象基础
“ndarray”是 NumPy 的核心功能,其含义为 n-dimensional array,即多维数组。在后面的叙述中,会经常用到“数组”这个词,就是指的 ndarray。数组是 NumPy 的一个重要数据结构,正如 Python 中“万物皆对象”原则,数组也是一个对象,这个对象具有自身的独特之处,具体表现在其属性和方法上。
1.初识数组对象( 1)使用 Jupyter Notebook
如果读者按部就班地跟随本书操作,那么已经打开了 Jupyter Notebook 界面。
执行如下操作。
In [1]: import numpy as np
np.__version__
· 10·
Out[1]: '1.13.0'
In[1]表示输入的内容。输入完毕,按住 Shift 键,再按 Enter 键,就会执行输入语句。如果有结果出来,就会在 Out[1]中显示。 In[1]中的数字是程序单元的序号。看一下笔者执行 In[1]的截图,如图 1-1-1 所示。
Out[1]的输出结果是当前 NumPy 的版本。或许读者所使用的版本跟笔者所演示的不同,这是很正常的。因为 NumPy 一直在发展,这也是我们使用它的重要原因。如果它的版本号不变化了,你还敢用吗?这又不是古董。当然,新旧版本会有一些差异,但读者对此不必太担心。一方面主体内容不会有太大变化(除非比较大的版本变化,比如升级为 2.xx.x),另一方面笔者在本书中各章节重点强调的不是掌握哪些知识,而是要掌握学习知识的方法,本书中的知识只不过是方法的载体罢了。再者, NumPy 有非常好的帮助文档,甚至在操作的时候,都会有非常友好的提示。
在 In[1]中,就是引入 NumPy。通常都用这种方式引入,请读者也用这种通常的方式——要获得自由,必须遵守规范——这种引入方式能够保证你跟别人快乐地一起玩耍,不至于弄翻友谊的小船。
为了认识数组对象,先要创建一个数组。下面就创建本书的第一个数组。
In [2]: data = np.array([1, 2, 3, 4, 5])
data
Out[2]: array([1, 2, 3, 4, 5])
In [3]: type(data)
Out[3]: numpy.ndarray
关于如何创建数组,后面会专门讲解,这里先来认识一下数组。
刚才所创建的数组,其类型为 numpy.ndarray,这个数组即为一个对象。既然如此,它就有一些属性和方法,所以 dir()在这里依然有效(如果读者不知道 dir()的作用,请查阅《跟老齐学Python:轻松入门》)。
In [4]: dir(data)
Out[4]: ['T',
'__abs__',
'__add__',
…… #省略很多内容
'transpose',
'var',
'view']
从 Out[4]的输出列表中,读者可以看到很多数组对象的属性和方法。除使用 dir()外,还有另外一个查看当前对象属性和方法的操作方式。
In [5]: data?
此时会显示如图 1-1-2 所示的内容。

单击帮助文档界面右上角的两个小图标,可分别实现在新 Tab 中全屏查看和关闭当前文档这两个功能。
通过 In[5]看到的内容,是数组的官方文档,对数组对象做了详细说明,其中蕴含的信息非常丰富。如果读者有耐心,特别建议将上述内容进行详细浏览,即使不理解,也能够对数组对象有初步的印象,再结合本书的叙述,会对学习大有裨益。请特别留意 In[5]使用的方法,这是本书提倡的学习方法。
( 2)数组元素的类型
In[2]所创建的数组对象中的数字( 1, 2, 3, 4, 5)称为数组的元素,它们是数组这个数据结构中的具体内容。
In [6]: data.dtype Out[6]: dtype('int64')
通过数组对象的 dtype 属性可以得到组成数组的元素的类型。在 In[6]的操作中,可以得知数组 data 的元素类型是 int64,即 64 位整数。
数组的元素都有哪些类型?
在回答这个问题之前,必须要牢记:组成数组的元素必须是同一种类型。
这显然跟 Python 中的列表不同(建议读者在学习数组的同时, 不断跟以往的知识进行对比,特别是 Python 的列表)。
为了适应 NumPy 所要担负的计算工作,数组中元素的内置类型(已经定义好的类型,除此之外,还可以自定义元素的类型)主要有以下几种,如表 1-1-1 所示。


表 1-1-1 中的“字符编码”是每种类型对应的字符串的表示方法,这是为了兼容 NumPy 的
前身 Numeric 而设定的。虽然现在使用得越来越少了,但有的程序中还会出现,读者遇到时可
以查阅。
某个数组一旦建立,其元素类型是确定不能随意改变的。那么,在实际业务中如果遇到需
要修改元素类型的情况,应该如何操作?
In [7]: new_data = data.astype(np.float)
new_data
Out[7]: array([ 1., 2., 3., 4., 5.])
In [8]: new_data.dtype
Out[8]: dtype('float64')
In [9]: data, data.dtype
Out[9]: (array([1, 2, 3, 4, 5]), dtype('int64'))
astype()是数组对象的一个方法,它能够根据指定的类型(参数指定元素类型)新生成一个
数组,新数组 new_data 相对于旧数组 data 只有元素的类型不同。
( 3)数组的外貌
除 dtype 属性外,数组对象还有其他一些常用的属性,通过这些属性能够了解数组对象的
基本概况,比如数组的形状、维度等。
In [10]: a = np.array([1, 2, 3])
b = np.array([1.0, 2.0, 3.0])
a.dtype, b.dtype
Out[10]: (dtype('int64'), dtype('float64'))
In [10]创建了 a、 b 两个数组,这两个数组的差别在于创建的时候,列表中的元素类型不同。
那么,对两个数组分别输出 dtype 属性,得到的结果也不同,这是显然的。但从外形上看,这
两个数组还是有相同之处的。
In [11]: a.shape
Out[11]: (3,)
In [12]: b.shape
Out[12]: (3,)
shape 的英文含义是“形状”,这个属性返回的是一个元组( tuple),其中的元素是由整数构成的, 它们代表着该数组的形状——每个轴的元素数(关于“轴” 的概念, 请见后续讲解),“(3,)”
的含义是 0 轴上有 3 个元素。
In [13]: c = np.array([1.0, 2.0, 3.0, 4.0])
c.shape
Out[13]: (4,)
In[13]创建了一个数组 c,它的形状跟前面的数组 a、 b 不同, shape 属性的返回值为(4,),即
数组 c 的 0 轴上有 4 个元素。不管数组 a 还是数组 c,尽管两个数组在 0 轴上的元素数不同,但
它们都只有一个轴,即 0 轴,这种只有一个轴的数组被称为一维数组。对此,也有一个属性,
返回数组的维度。
In [14]: a.ndim
Out[14]: 1
观察 a、 c 两个数组, 它们的元素个数不同。 数组对象还有一个专门返回元素个数的属性 size,
相关演示如下。
In [15]: a.size
Out[15]: 3
In [16]: c.size
Out[16]: 4
NumPy 数组对象的常用属性如表 1-1-2 所示,请读者自行操作测试。

在 Python 中,当我们需要求助于文档的时候,就会使用 help(),这种方法在这里依然可以使用,比如 help(a.dtype)。当然,在 Jupyter 中,还可以使用“a.dtype?”查看文档,建议读者试一试。
2.创建数组
虽然已经对数据有了一点点了解,但终究是走马观花地看了看外貌。好比找伴侣,外貌固然重要,但门当户对也要强调,所以要看出身。数组的出身,就源于其创建方法。
( 1)创建数组的基本方法
np.array()是创建数组的基本方法,虽然前面已经使用了这个方法,但为了窥其全貌,还要看一看完整的文档说明。
In [17]: np.array?
Docstring:
array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0)
Create an array.
Parameters
‐‐‐‐‐‐‐‐‐‐
y object : array_like
An array, any object exposing the array interface, an object whose __array__
method returns an array, or any (nested) sequence.
y dtype : data‐type, optional
The desired data‐type for the array. If not given, then the type will be
determined as the minimum type required to hold the objects in the sequence. This argument
can only be used to 'upcast' the array. For downcasting, use the .astype(t) method.
y copy : bool, optional
If true (default), then the object is copied. Otherwise, a copy will only
be made if __array__ returns a copy, if obj is a nested sequence, or if a copy is needed
to satisfy any of the other requirements (`dtype`, `order`, etc.).
y order : {'K', 'A', 'C', 'F'}, optional
Specify the memory layout of the array. If object is not an array, the newly
created array will be in C order (row major) unless 'F' is specified, in which case it
will be in Fortran order (column major). If object is an array the following holds.
===== ========= ===================================================
order no copy copy=True
===== ========= ===================================================
'K' unchanged F & C order preserved, otherwise most similar order
'A' unchanged F order if input is F and not C, otherwise C order
'C' C order C order
'F' F order F order
===== ========= ===================================================
When ``copy=False`` and a copy is made for other reasons, the result is the
same as if ``copy=True``, with some exceptions for `A`, see the Notes section. The default
order is 'K'.
y subok : bool, optional
If True, then sub‐classes will be passed‐through, otherwise the returned array
will be forced to be a base‐class array (default).
y ndmin : int, optional
Specifies the minimum number of dimensions that the resulting array should
have. Ones will be pre‐pended to the shape as needed to meet this requirement.
Returns
‐‐‐‐‐‐‐
out : ndarray
An array object satisfying the specified requirements.
因为篇幅所限,这里仅列出文档内容的一部分,并且为了便于阅读,进行了重新排版。
能够耐心地阅读文档,是一项必要的修炼,也是笔者特别强调的。如果读者已经明白此道理并可以实行,必将掌握本书的要诀。在这里演示这种重要的学习方法,后续可能就一带而过,不再演示了,但并不意味着不重要。
下面通过若干示例,说明用 np.array()创建数组的方法——这是基本方法。
In [18]: a = np.array([1, 2, 3, 4]) #①
b = np.array([1, 2, 3, 4], dtype=float) ②
a
Out[18]: array([1, 2, 3, 4])
In [19]: a.dtype
Out[19]: dtype('int64')
In [20]: b
Out[20]: array([ 1., 2., 3., 4.])
In [21]: b.dtype
Out[21]: dtype('float64')
比较 In[18]中①和②两种创建数组的方式,向 array()传入的参数都是[1, 2, 3, 4],差别在于②中声明了元素的类型(dtype=float),分别用 a、 b 两个数组的 dtype 属性查看其元素类型(如Out[19]和 Out[21]所示),数组 a 的元素类型是整数,数组 b 的元素类型为浮点数。
在 Python 的列表中,我们已经了解了嵌套列表,即列表中的元素还是列表。在创建数组的时候,如果我们传入的是嵌套列表,则得到的就是一个多维数组,来看示例。
In [22]: da = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
da
Out[22]: array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
在 In[22]中向 np.array()传入了[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], 注意这个嵌套列表的各
个元素的长度必须一样。同时,因为数组的元素类型必须一致,所以列表中的元素类型也必须
相同(如果没有类型的特别声明, NumPy 会自行推断元素类型。比如上述列表中如果有某个数
是浮点数,则 NumPy 会将该数组元素类型设定为浮点数)。如果元素参差不齐,也不会报错,
只不过得不到我们预想的数组对象。
In [23]: np.array([[1, 2, 3], [5, 6, 7, 8], [11, 12]])
Out[23]: array([list([1, 2, 3]), list([5, 6, 7, 8]), list([11, 12])], dtype=object)
虽然 In[23]也建立了数组,但从 Out[23]中可以看出,与 Out[22]的结果大不一样, Out[22]
才是我们将来会在数据分析中用到的所谓的二维数组。
In [24]: da.shape
Out[24]: (3, 4)
In [25]: da.size
Out[25]: 12
In [26]: da.ndim
Out[26]: 2
In [27]: a.shape #In[18]建立的数组 a = np.array([1, 2, 3, 4])
Out[27]: (4,)
In [28]: a.size
Out[28]: 4
In [29]: a.ndim
Out[29]: 1
In[18]中所创建的数组 a 是一维数组, In[22]中所创建的数组 da 是二维数组,上面的操作分别显示了两个数组的几个属性值。特别要关注 Out[24]的结果, da.shape 的返回值是一个元组,这个元组的第 0 个(注意,在编程语言中,计数都是从 0 开始的)数字“3”表示数组 da 在 0轴方向上的元素是 3 个,第 1 个数字“4”表示数组 da 在 1 轴方向上的元素是 4 个,整个数组的元素为 3×4 个,即 da.size 的结果( Out[25])。数组 da 有 0 轴和 1 轴两个轴,即有两个维度,我们就说 da 是二维数组, da.ndim 返回的就是维度数 2,这个值也是 Out[24]的元组的长度。
下面以二维数组为例说明数组的“轴”,如图 1-1-3 所示。

对于此数组,从外向内看,第一层就是 0 轴,在这个轴方向上有 3 个元素([ 1, 2, 3, 4], [ 5,
6, 7, 8], [ 9, 10, 11, 12]),编号依次为 0、 1、 2(我们熟知的索引);再深入第二层,即每个列表元素,每个列表元素都是由 4 个整数构成的,那么这一层就是第二个轴,即 1 轴,这个轴方向上的索引依次是 0、 1、 2、 3。
通过图 1-1-3 可知, 0 轴和 1 轴组成了一个二维坐标,数组中的每个元素在这个坐标中都可
以用 0 轴和 1 轴的索引唯一锁定,类似我们在数学中学习过的坐标系中的点可以用一组坐标唯
一表示。
在对二维数组理解的基础上,也可以建立三维数组、四维数组乃至更多维的数组,读者可
以自行尝试一番。
注意,数组中的“维度”,跟我们在数学、物理学科中对空间“维度”的定义是有区别的。
比如,我们生活的空间,用物理术语称为“三维空间”,即可以使用由 X、 Y、 Z 三个坐标轴组
成的坐标系描述空间的任何一点。假设在这个坐标系中有一点 A,该点表示为 A(3, 4, 5),并且
有一条从坐标原点指向 A 点的有向线段, 此即为一个矢量, 此矢量可以表示为 OA i j k = + + 3 4 5
uuur r
r r
。
但是,这个矢量如果用数组表示,则为 a = np.array([3, 4, 5]),显然这个数组 a 的维度依然是 1,
不是 3。此区别请读者注意。
读者还要注意一点,不要误以为写成一行的就是一维,请看下面的操作。
In [30]: db = np.array([1, 2, 3, 4, 5, 6, 7, 8], ndmin=2)
db
Out[30]: array([[1, 2, 3, 4, 5, 6, 7, 8]])
In [31]: db.shape
Out[31]: (1, 8)
· 17·
In [32]: db.ndim
Out[32]: 2
仔细观察 Out[30]的输出结果,虽然只有一行,但其本质是一个嵌套,只不过第一层(0 轴)
只有一个元素( [1, 2, 3, 4, 5, 6, 7, 8])。对比操作,更好理解。
In [33]: dc = np.array([1, 2, 3, 4, 5, 6, 7, 8])
dc
Out[33]: array([1, 2, 3, 4, 5, 6, 7, 8])
In [34]: dc.shape
Out[34]: (8,)
In [35]: dc.ndim
Out[35]: 1
形成 dc 和 db 两个数组差别的原因在于 In[30]和 In[33]创建数组的时候, ndmin 参数的值不同,其值规定了该数组所应具有的最小维度数。
前面的示例中都是以列表为 np.array()的 object 参数的引用对象,而在其文档说明中很明确地指出 object 参数所引用的对象是 array_like(类数组,可以是列表、元组等可迭代序列,也可以是数组、矩阵),列表是类数组对象,其他符合此条件的对象当然也可以,比如下面的示例。
In [36]: a
Out[36]: array([1, 2, 3, 4])
In [37]: de = np.array(a, dtype=complex)
de
Out[37]: array([ 1.+0.j, 2.+0.j, 3.+0.j, 4.+0.j])
In [38]: de.dtype
Out[38]: dtype('complex128')
这次我们直接使用了一个数组, 并且将元素类型设置为 dtype=complex, 输出结果如 Out[37]所示。如果读者认真阅读了 np.array()的帮助文档,会发现还可以使用矩阵创建数组,矩阵是本书后续要讲解的内容。
使用 np.array()创建数组是一种最基本的方法,此外还有别的方式——不同的方式有不同的用途,都有存在的必要。
( 2)用函数创建数组
假设要创建一个数组,它有 100 个整数(也可以更多),并且这些整数具有某种规律,如果还用前面的方法,就要写一个含有 100 个整数(或者更多)的列表,这显然有点不优雅了。程序员是不愿意做这种事情的,这类事情都应该由程序来完成,所以就有了专门用来创建数组的函数,通过专门的函数可以创建有特征的数组。
In [39]: np.zeros((2, 10))
Out[39]: array([[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
np.zeros()能够创建一个完全由 0 组成的数组, (2, 10)是以元组形式声明该数组的形状,即 0
轴元素个数为 2, 1 轴元素个数为 10。当然,还有其他参数,读者可以使用“np.zeros?”方法查
看文档中的参数列表和说明,下面仅显示来自文档的部分内容,目的是针对性地解释部分参数
的含义。
zeros(shape, dtype=float, order='C')
Return a new array of given shape and type, filled with zeros.
Parameters
‐‐‐‐‐‐‐‐‐‐
shape : int or sequence of ints
Shape of the new array, e.g., ``(2, 3)`` or ``2``.
dtype : data‐type, optional
The desired data‐type for the array, e.g., `numpy.int8`. Default is
`numpy.float64`.
order : {'C', 'F'}, optional
Whether to store multidimensional data in C‐ or Fortran‐contiguous
(row‐ or column‐wise) order in memory.
请关注一个参数 order='C',在 np.array()的参数中也有 order。这个参数用于声明本数组元素
在数据存储区的排列格式,一般认为有两种格式,一种是根据行排列,另外一种是根据列排列。
根据行排列是 C 语言的存储格式,所以在 NumPy 中就称为“C 语言格式”,即 order='C';根据
列排列是 Fortran 语言的存储格式,所以有 order='F'的设置。默认情况下,使用 order='C'。
用于创建数组的函数还有好几个,下面先以表格的形式列出来,再进行说明,如表 1-1-3
所示。

为了能够对以上诸函数有所了解,还是建议读者阅读其文档。下面所讲述的内容,纯粹是为了辅助理解文档。要提醒读者注意,这里的说明肯定不如文档中描述的严谨,如有不当之处请以文档所述为准。
① 同一种元素的数组
在 np.zeros((2, 10))中传入了参数(2, 10), 它声明了即将创建的数组的形状, 通常用元组表示。
注意观察如下操作。
In [40]: np.ones((6,))
Out[40]: array([ 1., 1., 1., 1., 1., 1.])
In [41]: np.ones(6)
Out[41]: array([ 1., 1., 1., 1., 1., 1.])
以上两种不同形式的参数,创建了相同的数组。 “(6,)”毫无疑问是一个元组,表示该数组
的形状,只有在一维数组的时候,才可以用 6 来替代“(6,)”,但是笔者不推荐这样写,还是严
格按照统一规范写代码比较好。
既然 np.zeros()的参数是数组的形状,就有了如下操作。
In [42]: da
Out[42]: array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12]])
In [43]: da.shape
Out[43]: (3, 4)
In [44]: np.ones(da.shape)
Out[44]: array([[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.]])
实现上面同样结果的操作,还可以使用 np.ones_like()函数。
In [45]: np.ones_like(da)
Out[45]: array([[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]])
In [46]: np.ones_like(da, dtype=np.float)
Out[46]: array([[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.],
[ 1., 1., 1., 1.]])
问题只有一个,但解决方法有多个。 NumPy 提供了多种函数可以实现同一种操作,以便我
们在实践中根据客观需要选用。
利用 np.ones()、 np.zeros()、 np.empty()得到的是元素为 0、 1 或空的特殊数组,那么,是否
能得到元素是其他数值的数组呢?
In [47]: df = 6.4 * np.ones_like(da)
df
Out[47]: array([[ 6.4, 6.4, 6.4, 6.4],
[ 6.4, 6.4, 6.4, 6.4],
[ 6.4, 6.4, 6.4, 6.4]])
In [47]中使用 6.4 这个浮点数乘以元素为 1 的数组,结果是 6.4 与每个元素相乘,最终得到的元素都是 6.4 的数组。像 6.4 这样的数,我们称为“标量”,而后面的数组 np.ones_like(da)则被称为“矢量”。关于运算问题,后面会详细介绍,请保持你的耐心。
In [48]: np.full(da.shape, 6.4)
Out[48]: array([[ 6.4, 6.4, 6.4, 6.4],
[ 6.4, 6.4, 6.4, 6.4],
[ 6.4, 6.4, 6.4, 6.4]])
又看到解决问题的方法不止一种了——真实世界就是这样, 方法不是标准的, 会有很多选择。建议读者自行查看 np.full()和 np.full_like()方法的帮助文档。
② 对角线独特的数组
np.eye()、 np.identity()和 np.diag()都能够创建对角线元素比较特殊而其他部分的元素为 0 的数组。
In [49]: np.eye(4, dtype=int)
Out[49]: array([[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]])
In [50]: np.eye(4, dtype=int, k=1)
Out[50]: array([[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
[0, 0, 0, 0]])
In [51]: np.eye(4, dtype=int, k=‐1)
Out[51]: array([[0, 0, 0, 0],
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0]])
np.eye()不仅能够创建对角线元素为 1 的 n×n 的二维数组(这种 n×n 的数组常常被形象地称为“方阵”,甚至有的资料直接称之为矩阵。而对角线都是 1,在数学上称为单位矩阵),还能够根据 k 值调整“对角线”位置——设置任何一个斜线方向为等效对角线(显然这是比喻的说法)。而 np.identity()所创建的就是一个不能调整“对角线”的单位矩阵(对角线元素是 1 的 n×n的二维数组)。
In [52]: np.identity(4)
Out[52]: array([[ 1., 0., 0., 0.],
[ 0., 1., 0., 0.],
[ 0., 0., 1., 0.],
[ 0., 0., 0., 1.]])
np.diag()比上述两个方法更灵活一些,从函数名称上看,也能知道这个函数是正宗操作对
角线(Diagonal line)的函数,所以,读者在自己写程序的时候,也要注意命名的规范。让阅读
代码的人能够望文生义,这才是最好的命名。
In [53]: np.diag([1, 2, 3, 4])
Out[53]: array([[1, 0, 0, 0],
[0, 2, 0, 0],
[0, 0, 3, 0],
[0, 0, 0, 4]])
这个二维数组的对角线是由[1, 2, 3, 4]中的元素所指定的,并且 NumPy 自动根据对角线的
个数确定数组各轴的元素数。与 np.eye()类似, np.diag()也可以调整对角线的位置。
In [54]: np.diag([1, 2, 3, 4], k=1)
Out[54]: array([[0, 1, 0, 0, 0],
[0, 0, 2, 0, 0],
[0, 0, 0, 3, 0],
[0, 0, 0, 0, 4],
[0, 0, 0, 0, 0]])
果然灵活。不仅如此,在下面的示例中还展现了其另一个作用。
In [55]: de = np.arange(16).reshape((4,4))
de
Out[55]: array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
In [56]: np.diag(de)
Out[56]: array([ 0, 5, 10, 15])
In [57]: np.diag(de, k=‐1)
Out[57]: array([ 4, 9, 14])
In[55]创建了一个二维数组( np.arange()方法参考表 1-1-3, reshape()方法后续会讲解),在In[56]中以该数组为参数传入 np.diag()中,得到了 de 数组的对角线元素组成的新数组。同理,在 In[57]中,调整了对角线位置,也得到由其元素组成的新数组。
( 3)元素是等差和等比的数组
np.arange()是一个类似 Python 中的 range()的函数,通过它创建的是一维数组,数组的元素符合等差数列,即后一个元素值与前一个元素值的差等于指定的步长值。
In [58]: np.arange(1, 100, 3)
Out[58]: array([ 1, 4, 7, 10, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46, 49,
52, 55, 58, 61, 64, 67, 70, 73, 76, 79, 82, 85, 88, 91, 94, 97])
np.linspace()也可以得到由等差数列的数值组成的数组,但是,与上述 np.arange()有很大
不同。
In [59]: np.linspace(1, 10, 4)
Out[59]: array([ 1., 4., 7., 10.])
In [59]规定该等差数列的开始值是 1,结束值是 10。但是,不同于 Python 中常规的“前包
括,后不包括”的原则(参考 np.arange(10)的结果),这里的结束值也包括在数列之中(其实有
一个参数 endpoint=True 来调控是否包括末尾的值,这个参数的默认值是 True,详情可以通过
“np.linspace?”方法查看文档)。最后的 4,不是步长值,而是这个数列总共应该有的数值个数,
或者说是数列的长度。
请参考函数的完整表述,理解上述说明: np.linspace(start, stop, num=50, endpoint=True,
retstep=False, dtype=None)。
np.logspace()在理解上较前面两个函数不那么直接了, 所以先看示例, 通过示例说明其作用。
In [60]: np.logspace(2, 3, num=4)
Out[60]: array([ 100. , 215.443469, 464.15888336, 1000. ])
先看 In [60]输入的参数, 2 表示开始值, 3 表示结束值, 4 表示数量,即共有 4 个数。再看
返回的结果, 100 显然是 102, 1000 则是 103,或者 2 是以 10 为底的 100 的对数,那么以 10 为
底的 215.443469 的对数是多少?
In [61]: import math
math.log10(215.443469)
math.log10(464.15888336)
Out[61]: (2.333333333326906, 2.666666666665471)
看到上面的计算结果不难得知, Out[60]中的数组各个元素的以 10 为底的对数分别是[2, 7/3,
8/3, 3],这个数列是以 1/3 为步长值均匀分布的,所以 np.logspace()返回的是在对数尺度上均匀
间隔分布的数值。
如果从 np.logspace(2, 3, num=4)的参数进行理解, 2 和 3 是两个对数结果, 4 是对数个数,
其完整的函数格式为:
np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)
默认底是 10.0 (base=10.0), 可以根据需要修改。 再看返回结果中的元素数字, 分别是[106/3,
107/3, 108/3, 109/3],即得到的其实是一个等比数列。总结一句, np.logspace()返回的是由等比数列
元素组成的数组,等比数列的开始值是 basestart,结束值是 baseend(视 endpoint=True 而定是否包
含结束值)。
更多推荐
所有评论(0)