Python 金融编程第二版(二)(1)

简介: Python 金融编程第二版(二)

第四章:使用 NumPy 进行数值计算

计算机是无用的。它们只能给出答案。

巴勃罗·毕加索

介绍

本章介绍了 Python基本数据类型和数据结构。尽管 Python 解释器本身已经带来了丰富的数据结构,但 NumPy 和其他库以有价值的方式添加了这些数据结构。

本章组织如下:

数据数组

本节详细讨论了数组的概念,并说明了在 Python 中处理数据数组的基本选项。

NumPy 数据结构

本节致力于介绍 NumPy ndarray 类的特性和功能,并展示了该类对科学和金融应用的一些好处。

代码向量化

本节说明了,由于 NumPy 的数组类,向量化代码很容易实现,从而导致代码更紧凑,性能更好。

本章涵盖了以下数据结构:

对象类型 含义 用法/模型
ndarray(常规) n 维数组对象 大量数值数据的大数组
ndarray(记录) 二维数组对象 以列组织的表格数据

本章组织如下:

“数据数组”

本节讨论了使用纯 Python 代码处理数据数组的方法。

[待添加链接]

这是关于常规 NumPy ndarray 类的核心部分;它是几乎所有数据密集型 Python 使用案例中的主要工具。

[待添加链接]

这个简短的部分介绍了用于处理带有列的表格数据的结构化(或记录)ndarray 对象。

“代码的向量化”

在本节中,讨论了代码的向量化及其好处;该部分还讨论了在某些情况下内存布局的重要性。

数据数组

前一章表明 Python 提供了一些非常有用和灵活的通用数据结构。特别是,list  对象可以被认为是一个真正的工作马,具有许多方便的特性和应用领域。在一般情况下,使用这样一个灵活的(可变的)数据结构的代价在于相对较高的内存使用量,较慢的性能或两者兼有。然而,科学和金融应用通常需要对特殊数据结构进行高性能操作。在这方面最重要的数据结构之一是数组。数组通常以行和列的形式结构化其他(基本)相同数据类型的对象。

暂时假设我们仅使用数字,尽管这个概念也可以推广到其他类型的数据。在最简单的情况下,一维数组在数学上表示为向量,通常由float对象内部表示为实数的一行或一列元素组成。在更普遍的情况下,数组表示为i × j 矩阵的元素。这个概念在三维中也可以推广为i × j × k 立方体的元素以及形状为i × j × k × l × …的一般n维数组。

线性代数和向量空间理论等数学学科说明了这些数学结构在许多科学学科和领域中的重要性。因此,设计一个专门的数据结构类来方便和高效地处理数组可能是非常有益的。这就是PythonNumPy的作用所在,其ndarray类应运而生。在下一节介绍其强大的ndarray类之前,本节展示了两种处理数组的替代方法。

使用 Python 列表的数组

在转向NumPy之前,让我们首先用上一节介绍的内置数据结构构建数组。list对象特别适用于完成这项任务。一个简单的list已经可以被视为一维数组:

In [1]: v = [0.5, 0.75, 1.0, 1.5, 2.0]  # ①

list对象与数字。

由于list对象可以包含任意其他对象,它们也可以包含其他list对象。通过嵌套list对象,可以轻松构建二维和更高维的数组:

In [2]: m = [v, v, v]  # ①
        m  # ②
Out[2]: [[0.5, 0.75, 1.0, 1.5, 2.0],
         [0.5, 0.75, 1.0, 1.5, 2.0],
         [0.5, 0.75, 1.0, 1.5, 2.0]]

list对象与list对象…

… 得到一个数字矩阵。

我们还可以通过简单的索引选择行或通过双重索引选择单个元素(然而,选择整列并不那么容易):

In [3]: m[1]
Out[3]: [0.5, 0.75, 1.0, 1.5, 2.0]
In [4]: m[1][0]
Out[4]: 0.5

嵌套可以进一步推广到更一般的结构:

In [5]: v1 = [0.5, 1.5]
        v2 = [1, 2]
        m = [v1, v2]
        c = [m, m]  # ①
        c
Out[5]: [[[0.5, 1.5], [1, 2]], [[0.5, 1.5], [1, 2]]]
In [6]: c[1][1][0]
Out[6]: 1

立方数。

请注意,刚刚介绍的对象组合方式通常使用对原始对象的引用指针。这在实践中意味着什么?让我们看看以下操作:

In [7]: v = [0.5, 0.75, 1.0, 1.5, 2.0]
        m = [v, v, v]
        m
Out[7]: [[0.5, 0.75, 1.0, 1.5, 2.0],
         [0.5, 0.75, 1.0, 1.5, 2.0],
         [0.5, 0.75, 1.0, 1.5, 2.0]]

现在修改v对象的第一个元素的值,看看m对象会发生什么变化:

In [8]: v[0] = 'Python'
        m
Out[8]: [['Python', 0.75, 1.0, 1.5, 2.0],
         ['Python', 0.75, 1.0, 1.5, 2.0],
         ['Python', 0.75, 1.0, 1.5, 2.0]]

通过使用copy模块的deepcopy函数,可以避免这种情况:

In [9]: from copy import deepcopy
        v = [0.5, 0.75, 1.0, 1.5, 2.0]
        m = 3 * [deepcopy(v), ]  # ①
        m
Out[9]: [[0.5, 0.75, 1.0, 1.5, 2.0],
         [0.5, 0.75, 1.0, 1.5, 2.0],
         [0.5, 0.75, 1.0, 1.5, 2.0]]
In [10]: v[0] = 'Python'  # ②
         m  # ③
Out[10]: [[0.5, 0.75, 1.0, 1.5, 2.0],
          [0.5, 0.75, 1.0, 1.5, 2.0],
          [0.5, 0.75, 1.0, 1.5, 2.0]]

使用物理副本而不是引用指针。

因此,对原始对象的更改…

… 不再有任何影响。

Python 数组类

Python 中有一个专用的array模块可用。正如您可以在文档页面上阅读到的(参见https://docs.python.org/3/library/array.html):

该模块定义了一种对象类型,可以紧凑地表示基本值的数组:字符、整数、浮点数。数组是序列类型,并且行为非常像列表,只是存储在其中的对象类型受到限制。类型在对象创建时通过使用类型代码(一个单个字符)来指定。

考虑以下代码,将一个list对象实例化为一个array对象。

In [11]: v = [0.5, 0.75, 1.0, 1.5, 2.0]
In [12]: import array
In [13]: a = array.array('f', v)  # ①
         a
Out[13]: array('f', [0.5, 0.75, 1.0, 1.5, 2.0])
In [14]: a.append(0.5)  # ②
         a
Out[14]: array('f', [0.5, 0.75, 1.0, 1.5, 2.0, 0.5])
In [15]: a.extend([5.0, 6.75])  # ②
         a
Out[15]: array('f', [0.5, 0.75, 1.0, 1.5, 2.0, 0.5, 5.0, 6.75])
In [16]: 2 * a  # ③
Out[16]: array('f', [0.5, 0.75, 1.0, 1.5, 2.0, 0.5, 5.0, 6.75, 0.5, 0.75, 1.0, 1.5, 2.0, 0.5, 5.0, 6.75])

使用float作为类型代码实例化array对象。

主要方法的工作方式类似于list对象的方法。

虽然“标量乘法”原理上可行,但结果不是数学上预期的;而是元素被重复。

尝试附加与指定数据类型不同的对象会引发TypeError

In [17]: # a.append('string') # ①
In [18]: a.tolist()  # ②
Out[18]: [0.5, 0.75, 1.0, 1.5, 2.0, 0.5, 5.0, 6.75]

仅能附加float对象;其他数据类型/类型代码会引发错误。

然而,如果需要这样的灵活性,array对象可以轻松转换回list对象。

array类的一个优点是它具有内置的存储和检索功能。

In [19]: f = open('array.apy', 'wb')  # ①
         a.tofile(f)  # ②
         f.close()  # ③
In [20]: with open('array.apy', 'wb') as f:  # ④
             a.tofile(f)  # ④
In [21]: !ls -n arr*  # ⑤
         -rw-r--r--@ 1 503  20  32 29 Dez 17:08 array.apy

打开一个用于写入二进制数据的磁盘上的文件。

array数据写入文件。

关闭文件。

或者,可以使用with上下文执行相同的操作。

这显示了磁盘上写入的文件。

与以前一样,从磁盘读取数据时,array对象的数据类型很重要。

In [22]: b = array.array('f')  # ①
In [23]: with open('array.apy', 'rb') as f:  # ②
             b.fromfile(f, 5)  # ③
In [24]: b  # ④
Out[24]: array('f', [0.5, 0.75, 1.0, 1.5, 2.0])
In [25]: b = array.array('d')  # ⑤
In [26]: with open('array.apy', 'rb') as f:
             b.fromfile(f, 2)  # ⑥
In [27]: b  # ⑦
Out[27]: array('d', [0.0004882813645963324, 0.12500002956949174])

使用类型代码float创建一个新的array对象。

打开文件以读取二进制数据…

…并在b对象中读取五个元素。

使用类型代码double创建一个新的array对象。

从文件中读取两个元素。

类型代码的差异导致“错误”的数字。

常规 NumPy 数组

显然,使用list对象构成数组结构有些作用。但这并不是真正方便的方式,而且list类并没有为此特定目标而构建。它的范围更广泛,更一般。array类已经稍微更专业一些,提供了一些有用的特性来处理数据数组。然而,某种“高度”专业化的类因此可能真的对处理数组类型的结构非常有益。

基础知识

这样一个专门的类就是numpy.ndarray类,它的特定目标是方便且高效地处理n维数组,即以高性能的方式。这个类的基本处理最好通过示例来说明:

In [28]: import numpy as np  # ①
In [29]: a = np.array([0, 0.5, 1.0, 1.5, 2.0])  # ②
         a
Out[29]: array([ 0. ,  0.5,  1. ,  1.5,  2. ])
In [30]: type(a)  # ②
Out[30]: numpy.ndarray
In [31]: a = np.array(['a', 'b', 'c'])  # ③
         a
Out[31]: array(['a', 'b', 'c'],
               dtype='<U1')
In [32]: a = np.arange(2, 20, 2)  # ④
         a
Out[32]: array([ 2,  4,  6,  8, 10, 12, 14, 16, 18])
In [33]: a = np.arange(8, dtype=np.float)  # ⑤
         a
Out[33]: array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.])
In [34]: a[5:]  # ⑥
Out[34]: array([ 5.,  6.,  7.])
In [35]: a[:2]  # ⑥
Out[35]: array([ 0.,  1.])

导入numpy包。

通过list对象中的浮点数创建一个ndarray对象。

通过list对象中的字符串创建一个ndarray对象。

np.arange的工作方式类似于range

然而,它接受附加输入dtype参数。

对于一维的ndarray对象,索引的工作方式与平常一样。

ndarray类的一个重要特性是内置方法的多样性。例如:

In [36]: a.sum()  # ①
Out[36]: 28.0
In [37]: a.std()  # ②
Out[37]: 2.2912878474779199
In [38]: a.cumsum()  # ③
Out[38]: array([  0.,   1.,   3.,   6.,  10.,  15.,  21.,  28.])

所有元素的总和。

元素的标准偏差。

所有元素的累积和(从索引位置 0 开始)。

另一个重要特性是对ndarray对象定义的(向量化的)数学运算

In [39]: l = [0., 0.5, 1.5, 3., 5.]
         2 * l  # ①
Out[39]: [0.0, 0.5, 1.5, 3.0, 5.0, 0.0, 0.5, 1.5, 3.0, 5.0]
In [40]: a
Out[40]: array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.])
In [41]: 2 * a  # ②
Out[41]: array([  0.,   2.,   4.,   6.,   8.,  10.,  12.,  14.])
In [42]: a ** 2  # ③
Out[42]: array([  0.,   1.,   4.,   9.,  16.,  25.,  36.,  49.])
In [43]: 2 ** a  # ④
Out[43]: array([   1.,    2.,    4.,    8.,   16.,   32.,   64.,  128.])
In [44]: a ** a  # ⑤
Out[44]: array([  1.00000000e+00,   1.00000000e+00,   4.00000000e+00,
                  2.70000000e+01,   2.56000000e+02,   3.12500000e+03,
                  4.66560000e+04,   8.23543000e+05])

list对象的“标量乘法”导致元素的重复。

相比之下,使用ndarray对象实现了适当的标量乘法,例如。

这个计算每个元素的平方值。

这解释了ndarray的元素作为幂。

这个计算每个元素的自身的幂。

NumPy包的另一个重要功能是通用函数。它们在一般情况下对ndarray对象以及基本 Python 数据类型进行操作。然而,当将通用函数应用于 Python float对象时,需要注意与math模块中相同功能的性能降低。

In [45]: np.exp(a)  # ①
Out[45]: array([  1.00000000e+00,   2.71828183e+00,   7.38905610e+00,
                  2.00855369e+01,   5.45981500e+01,   1.48413159e+02,
                  4.03428793e+02,   1.09663316e+03])
In [46]: np.sqrt(a)  # ②
Out[46]: array([ 0.        ,  1.        ,  1.41421356,  1.73205081,  2.        ,
                 2.23606798,  2.44948974,  2.64575131])
In [47]: np.sqrt(2.5)  # ③
Out[47]: 1.5811388300841898
In [48]: import math  # ④
In [49]: math.sqrt(2.5)  # ④
Out[49]: 1.5811388300841898
In [50]: # math.sqrt(a) # ⑤
In [51]: %timeit np.sqrt(2.5)  # ⑥
         703 ns ± 17.9 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [52]: %timeit math.sqrt(2.5)  # ⑦
         107 ns ± 1.48 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

逐个元素计算指数值。

计算每个元素的平方根。

计算 Python float对象的平方根。

相同的计算,这次使用math模块。

math.sqrt不能直接应用于ndarray对象。

将通用函数np.sqrt应用于 Python float对象……

……比使用math.sqrt函数的相同操作慢得多。

多维度

切换到多维度是无缝的,并且到目前为止呈现的所有特征都适用于更一般的情况。特别是,索引系统在所有维度上保持一致:

In [53]: b = np.array([a, a * 2])  # ①
         b
Out[53]: array([[  0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.],
                [  0.,   2.,   4.,   6.,   8.,  10.,  12.,  14.]])
In [54]: b[0]  # ②
Out[54]: array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.])
In [55]: b[0, 2]  # ③
Out[55]: 2.0
In [56]: b[:, 1]  # ④
Out[56]: array([ 1.,  2.])
In [57]: b.sum()  # ⑤
Out[57]: 84.0
In [58]: b.sum(axis=0)  # ⑥
Out[58]: array([  0.,   3.,   6.,   9.,  12.,  15.,  18.,  21.])
In [59]: b.sum(axis=1)  # ⑦
Out[59]: array([ 28.,  56.])

用一维数组构造二维ndarray对象。

选择第一行。

选择第一行的第三个元素;在括号内,索引由逗号分隔。

选择第二列。

计算所有值的总和。

沿第一个轴计算总和,即按列计算。

沿第二轴计算总和,即按行计算。

有多种方法可以初始化(实例化)ndarray对象。一种方法如前所述,通过np.array。然而,这假定数组的所有元素已经可用。相比之下,也许我们希望首先实例化ndarray对象,以便在执行代码期间生成的结果后来填充它们。为此,我们可以使用以下函数:

In [60]: c = np.zeros((2, 3), dtype='i', order='C')  # ①
         c
Out[60]: array([[0, 0, 0],
                [0, 0, 0]], dtype=int32)
In [61]: c = np.ones((2, 3, 4), dtype='i', order='C')  # ②
         c
Out[61]: array([[[1, 1, 1, 1],
                 [1, 1, 1, 1],
                 [1, 1, 1, 1]],
                [[1, 1, 1, 1],
                 [1, 1, 1, 1],
                 [1, 1, 1, 1]]], dtype=int32)
In [62]: d = np.zeros_like(c, dtype='f16', order='C')  # ③
         d
Out[62]: array([[[ 0.0,  0.0,  0.0,  0.0],
                 [ 0.0,  0.0,  0.0,  0.0],
                 [ 0.0,  0.0,  0.0,  0.0]],
                [[ 0.0,  0.0,  0.0,  0.0],
                 [ 0.0,  0.0,  0.0,  0.0],
                 [ 0.0,  0.0,  0.0,  0.0]]], dtype=float128)
In [63]: d = np.ones_like(c, dtype='f16', order='C')  # ③
         d
Out[63]: array([[[ 1.0,  1.0,  1.0,  1.0],
                 [ 1.0,  1.0,  1.0,  1.0],
                 [ 1.0,  1.0,  1.0,  1.0]],
                [[ 1.0,  1.0,  1.0,  1.0],
                 [ 1.0,  1.0,  1.0,  1.0],
                 [ 1.0,  1.0,  1.0,  1.0]]], dtype=float128)
In [64]: e = np.empty((2, 3, 2))  # ④
         e
Out[64]: array([[[  0.00000000e+000,  -4.34540174e-311],
                 [  2.96439388e-323,   0.00000000e+000],
                 [  0.00000000e+000,   1.16095484e-028]],
                [[  2.03147708e-110,   9.67661175e-144],
                 [  9.80058441e+252,   1.23971686e+224],
                 [  4.00695466e+252,   8.34404939e-309]]])
In [65]: f = np.empty_like(c)  # ④
         f
Out[65]: array([[[0, 0, 0, 0],
                 [9, 0, 0, 0],
                 [0, 0, 0, 0]],
                [[0, 0, 0, 0],
                 [0, 0, 0, 0],
                 [0, 0, 0, 0]]], dtype=int32)
In [66]: np.eye(5)  # ⑤
Out[66]: array([[ 1.,  0.,  0.,  0.,  0.],
                [ 0.,  1.,  0.,  0.,  0.],
                [ 0.,  0.,  1.,  0.,  0.],
                [ 0.,  0.,  0.,  1.,  0.],
                [ 0.,  0.,  0.,  0.,  1.]])
In [67]: g = np.linspace(5, 15, 15) # ⑥
         g
Out[67]: array([  5.        ,   5.71428571,   6.42857143,   7.14285714,
                  7.85714286,   8.57142857,   9.28571429,  10.        ,
                 10.71428571,  11.42857143,  12.14285714,  12.85714286,
                 13.57142857,  14.28571429,  15.        ])

用零预先填充的ndarray对象。

用 1 预先填充的ndarray对象。

相同,但采用另一个ndarray对象来推断形状。

ndarray对象不预先填充任何内容(数字取决于内存中存在的位)。

创建一个由 1 填充对角线的方阵作为ndarray对象。

创建一个一维ndarray对象,其中数字之间的间隔均匀分布;所使用的参数是startendnum(元素数量)。

使用所有这些函数,我们可以提供以下参数:

shape

要么是一个int,一个``int+s序列,或者是对另一个+numpy.ndarray的引用

dtype(可选)

一个dtype——这些是NumPy特定的numpy.ndarray对象的数据类型

order(可选)

存储元素在内存中的顺序:C表示C风格(即,逐行),或F表示Fortran风格(即,逐列)

在这里,NumPy如何通过ndarray类专门构建数组的方式,与基于list的方法进行比较变得明显:

  • ndarray对象具有内置的维度(轴)。
  • ndarray对象是不可变的,其形状是固定的。
  • 它仅允许单一数据类型numpy.dtype)用于整个数组。

相反,array类只共享允许唯一数据类型(类型代码,dtype)的特性。

order参数的作用在本章稍后讨论。表 4-1 提供了numpy.dtype对象的概述(即,NumPy允许的基本数据类型)。

表 4-1。NumPy dtype 对象

dtype 描述 示例
t 位域 t4 (4 位)
b 布尔 b(true 或 false)
i 整数 i8 (64 位)
u 无符号整数 u8 (64 位)
f 浮点数 f8 (64 位)
c 复数浮点数 c16 (128 位)
O 对象 0 (对象指针)
S, a 字符串 S24 (24 个字符)
U Unicode U24 (24 个 Unicode 字符)
V 其他 V12 (12 字节数据块)

元信息

每个ndarray对象都提供访问一些有用属性的功能。

In [68]: g.size  # ①
Out[68]: 15
In [69]: g.itemsize  # ②
Out[69]: 8
In [70]: g.ndim  # ③
Out[70]: 1
In [71]: g.shape  # ④
Out[71]: (15,)
In [72]: g.dtype  # ⑤
Out[72]: dtype('float64')
In [73]: g.nbytes  # ⑥
Out[73]: 120

元素的数量。

用于表示一个元素所使用的字节数。

维度的数量。

ndarray对象的形状。

元素的dtype

内存中使用的总字节数。

重塑和调整大小

虽然ndarray对象默认是不可变的,但有多种选项可以重塑和调整此类对象。一般情况下,第一个操作只是提供相同数据的另一个视图,而第二个操作一般会创建一个新的(临时)对象。

In [74]: g = np.arange(15)
In [75]: g
Out[75]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14])
In [76]: g.shape  # ①
Out[76]: (15,)
In [77]: np.shape(g) # ①
Out[77]: (15,)
In [78]: g.reshape((3, 5))  # ②
Out[78]: array([[ 0,  1,  2,  3,  4],
                [ 5,  6,  7,  8,  9],
                [10, 11, 12, 13, 14]])
In [79]: h = g.reshape((5, 3))  # ③
         h
Out[79]: array([[ 0,  1,  2],
                [ 3,  4,  5],
                [ 6,  7,  8],
                [ 9, 10, 11],
                [12, 13, 14]])
In [80]: h.T  # ④
Out[80]: array([[ 0,  3,  6,  9, 12],
                [ 1,  4,  7, 10, 13],
                [ 2,  5,  8, 11, 14]])
In [81]: h.transpose()  # ④
Out[81]: array([[ 0,  3,  6,  9, 12],
                [ 1,  4,  7, 10, 13],
                [ 2,  5,  8, 11, 14]])

原始ndarray对象的形状。

重塑为两个维度(内存视图)。

创建新对象。

ndarray对象的转置。

在重塑操作期间,ndarray对象中的元素总数保持不变。在调整大小操作期间,此数字会更改,即它要么减少(“向下调整”),要么增加(“向上调整”)。

In [82]: g
Out[82]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14])
In [83]: np.resize(g, (3, 1))  # ①
Out[83]: array([[0],
                [1],
                [2]])
In [84]: np.resize(g, (1, 5))  # ①
Out[84]: array([[0, 1, 2, 3, 4]])
In [85]: np.resize(g, (2, 5))  # ①
Out[85]: array([[0, 1, 2, 3, 4],
                [5, 6, 7, 8, 9]])
In [86]: n = np.resize(g, (5, 4))  # ②
         n
Out[86]: array([[ 0,  1,  2,  3],
                [ 4,  5,  6,  7],
                [ 8,  9, 10, 11],
                [12, 13, 14,  0],
                [ 1,  2,  3,  4]])

两个维度,向下调整。

两个维度,向上调整。

堆叠是一种特殊操作,允许水平或垂直组合两个ndarray对象。但是,“连接”维度的大小必须相同。

In [87]: h
Out[87]: array([[ 0,  1,  2],
                [ 3,  4,  5],
                [ 6,  7,  8],
                [ 9, 10, 11],
                [12, 13, 14]])
In [88]: np.hstack((h, 2 * h))  # ①
Out[88]: array([[ 0,  1,  2,  0,  2,  4],
                [ 3,  4,  5,  6,  8, 10],
                [ 6,  7,  8, 12, 14, 16],
                [ 9, 10, 11, 18, 20, 22],
                [12, 13, 14, 24, 26, 28]])
In [89]: np.vstack((h, 0.5 * h))  # ②
Out[89]: array([[  0. ,   1. ,   2. ],
                [  3. ,   4. ,   5. ],
                [  6. ,   7. ,   8. ],
                [  9. ,  10. ,  11. ],
                [ 12. ,  13. ,  14. ],
                [  0. ,   0.5,   1. ],
                [  1.5,   2. ,   2.5],
                [  3. ,   3.5,   4. ],
                [  4.5,   5. ,   5.5],
                [  6. ,   6.5,   7. ]])

水平堆叠两个ndarray对象。

垂直堆叠两个ndarray对象。

另一个特殊操作是将多维ndarray对象展平为一维对象。可以选择是按行(C顺序)还是按列(F顺序)进行展平。

In [90]: h
Out[90]: array([[ 0,  1,  2],
                [ 3,  4,  5],
                [ 6,  7,  8],
                [ 9, 10, 11],
                [12, 13, 14]])
In [91]: h.flatten()  # ①
Out[91]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14])
In [92]: h.flatten(order='C')  # ①
Out[92]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14])
In [93]: h.flatten(order='F')  # ②
Out[93]: array([ 0,  3,  6,  9, 12,  1,  4,  7, 10, 13,  2,  5,  8, 11, 14])
In [94]: for i in h.flat:  # ③
             print(i, end=',')
         0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,
In [95]: for i in h.ravel(order='C'):  # ④
             print(i, end=',')
         0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,
In [96]: for i in h.ravel(order='F'):  # ④
             print(i, end=',')
         0,3,6,9,12,1,4,7,10,13,2,5,8,11,14,

平铺的默认顺序是C

F顺序展平。

flat属性提供了一个平坦的迭代器(C顺序)。

ravel()方法是flatten()的另一种选择。


Python 金融编程第二版(二)(2)https://developer.aliyun.com/article/1559403

相关文章
|
3天前
|
存储 分布式计算 数据可视化
Python 金融编程第二版(四)(2)
Python 金融编程第二版(四)
13 0
|
3天前
|
存储 SQL 数据可视化
Python 金融编程第二版(四)(1)
Python 金融编程第二版(四)
9 0
|
3天前
|
存储 数据可视化 API
Python 金融编程第二版(三)(5)
Python 金融编程第二版(三)
8 1
|
1天前
|
设计模式 存储 Python
Python元类大揭秘:从理解到应用,一步步构建你的编程帝国
【7月更文挑战第6天】Python元类是创建类的对象的基石,允许控制类的生成过程。通过自定义元类,可在类定义时动态添加方法或改变行为。
11 0
|
3天前
|
存储 机器学习/深度学习 关系型数据库
Python 金融编程第二版(四)(5)
Python 金融编程第二版(四)
8 0
|
3天前
|
存储 SQL 数据库
Python 金融编程第二版(四)(4)
Python 金融编程第二版(四)
8 0
|
3天前
|
SQL 存储 数据库
Python 金融编程第二版(四)(3)
Python 金融编程第二版(四)
8 0
|
2月前
|
人工智能 安全 Java
Python 多线程编程实战:threading 模块的最佳实践
Python 多线程编程实战:threading 模块的最佳实践
176 5
|
2月前
|
安全 调度 Python
什么是Python中的事件驱动编程?如何使用`asyncio`模块实现异步事件处理?
【2月更文挑战第4天】【2月更文挑战第9篇】什么是Python中的事件驱动编程?如何使用`asyncio`模块实现异步事件处理?
|
2月前
|
缓存 分布式计算 自然语言处理
Python语言的函数编程模块
Python语言的函数编程模块