Python 金融交易实用指南(一)(4)https://developer.aliyun.com/article/1523862
计算 ndarray 元素的累积和
要计算累积总和,NumPy 提供了np.cumsum(...)
方法。np.cumsum(...)
方法如下所示,找到 ndarray 中元素的累积总和:
np.cumsum(arr)
输出提供了每个附加元素后的累积和,如下所示:
array([ 0.24344963, -0.28838798, 0.80068144, -0.91076403, -0.94271656, -0.11596474, -2.36583764, 0.23856117, 0.14406333])
注意累积和和求和之间的差异。累积和是一个累加的数组,而求和是一个单个数字。
将axis=
参数应用于cumsum
方法的效果类似,如以下代码片段所示:
np.cumsum(arr, axis=1)
这将按行进行,并生成以下数组输出:
array([[ 0.24344963, -0.28838798, 0.80068144], [-1.71144547, -1.743398 , -0.91664617], [-2.24987291, 0.35452591, 0.26002807]])
查找 ndarray 中的 NaN 值
在 NumPy 中,缺失或未知值通常使用Not a Number (NaN)值表示。对于许多数值方法,必须将这些值删除或替换为插值。
首先,让我们将第二行设置为np.nan
,如下所示:
arr[1, :] = np.nan; arr
新的 ndarray 具有 NaN 值,如以下代码片段所示:
array([[ 0.64296696, -1.35386668, -0.63063743], [ nan, nan, nan], [-0.19093967, -0.93260398, -1.58520989]])
np.isnan(...)
ufunc 找到 ndarray 中的值是否为 NaN,如下所示:
np.isnan(arr)
输出是一个 ndarray,其中存在 NaN 的地方为True
值,不存在 NaN 的地方为False
值,如下所示的代码片段所示:
array([[False, False, False], [ True, True, True], [False, False, False]])
查找两个 ndarray 的 x1>x2 的真值
布尔 ndarray 是获取感兴趣的值的索引的有效方式。使用布尔 ndarray 比逐个遍历矩阵元素要高效得多。
让我们按照以下方式构建另一个具有随机值的arr1
ndarray:
arr1 = np.random.randn(9).reshape((3,3)); arr1
结果是一个 3 x 3 的 ndarray,如下所示的代码片段中所示:
array([[ 0.32102068, -0.51877544, -1.28267292], [-1.34842617, 0.61170993, -0.5561239 ], [ 1.41138027, -2.4951374 , 1.30766648]])
类似地,让我们构建另一个arr2
ndarray,如下所示:
arr2 = np.random.randn(9).reshape((3,3)); arr2
输出如下所示:
array([[ 0.33189432, 0.82416396, -0.17453351], [-1.59689203, -0.42352094, 0.22643589], [-1.80766151, 0.26201455, -0.08469759]])
np.greater(...)
函数是一个二进制 ufunc,当 ndarray 中的左值大于 ndarray 中的右值时生成True
值。该函数如下所示:
np.greater(arr1, arr2)
输出是如前所述的True
和False
值的 ndarray,如我们在这里所见:
array([[False, False, False], [ True, True, False], [ True, False, True]])
>
中缀操作符,如下段代码片段所示,是numpy.greater(...)
的简写:
arr1 > arr2
输出相同,如我们在这里所见:
array([[False, False, False], [ True, True, False], [ True, False, True]])
对 ndarray 进行任何和所有的布尔运算
除了关系运算符外,NumPy 还支持其他方法来测试矩阵值上的条件。
以下代码生成一个 ndarray,对满足条件的元素返回True
,否则返回False
:
arr_bool = (arr > -0.5) & (arr < 0.5); arr_bool
输出如下所示:
array([[False, False, True], [False, False, False], [False, True, True]])
以下numpy.ndarray.any(...)
方法在任何元素为True
时返回True
,否则返回False
:
arr_bool.any()
在这里,我们至少有一个元素为True
,因此输出为True
,如下所示:
True
再次,它接受常见的axis=
参数并且表现如预期,如我们在这里所见:
arr_bool.any(axis=1)
并且按行执行的操作生成如下所示:
array([True, False, True])
以下numpy.ndarray.all(...)
方法在所有元素都为True
时返回True
,否则返回False
:
arr_bool.all()
这返回了以下内容,因为并非所有元素都为True
:
False
它还接受axis=
参数,如下所示:
arr_bool.all(axis=1)
再次,每行至少有一个False
值,因此输出为False
,如下所示:
array([False, False, False])
对 ndarray 进行排序
在排序的 ndarray 中查找元素比处理 ndarray 的所有元素更快。
让我们生成一个 1D 随机数组,如下所示:
arr1D = np.random.randn(10); arr1D
ndarray 包含以下数据:
array([ 1.14322028, 1.61792721, -1.01446969, 1.26988026, -0.20110113, -0.28283051, 0.73009565, -0.68766388, 0.27276319, -0.7135162 ])
np.sort(...)
方法非常简单,如下所示:
np.sort(arr1D)
输出如下所示:
array([-1.01446969, -0.7135162 , -0.68766388, -0.28283051, -0.20110113, 0.27276319, 0.73009565, 1.14322028, 1.26988026, 1.61792721])
让我们检查原始 ndarray,看看它是否被numpy.sort(...)
操作修改了,如下所示:
arr1D
以下输出显示原始数组未改变:
array([ 1.14322028, 1.61792721, -1.01446969, 1.26988026, -0.20110113, -0.28283051, 0.73009565, -0.68766388, 0.27276319, -0.7135162 ])
以下np.argsort(...)
方法创建一个表示每个元素在排序数组中位置的索引数组:
np.argsort(arr1D)
此操作的输出生成以下数组:
array([2, 9, 7, 5, 4, 8, 6, 0, 3, 1])
NumPy ndarray 还具有numpy.ndarray.sort(...)
方法,该方法可以就地对数组进行排序。该方法在下面的代码片段中说明:
arr1D.sort() np.argsort(arr1D)
调用sort()
后,我们调用numpy.argsort(...)
来确保数组已排序,这将生成以下数组,确认了该行为:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
在 ndarray 中搜索
在 ndarray 上满足某个条件的元素的索引是一种基本操作。
首先,我们从一个具有连续值的 ndarray 开始,如下所示:
arr1 = np.array(range(1, 11)); arr1
这将创建以下 ndarray:
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
我们根据第一个 ndarray 创建了第二个 ndarray,不过这次第二个 ndarray 中的值乘以了1000
,如下面的代码片段所示:
arr2 = arr1 * 1000; arr2
然后,我们知道arr2
包含以下数据:
array([ 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000])
我们定义另一个 ndarray,其中包含 10 个随机的True
和False
值,如下所示:
cond = np.random.randn(10) > 0; cond
cond
ndarray 中的值显示如下:
array([False, False, True, False, False, True, True, True, False, True])
np.where(...)
方法允许我们根据条件是 True
还是 False
从一个 ndarray 或另一个中选择值。以下代码将生成一个 ndarray,当 cond
数组中对应的元素为 True
时,从 arr1
中选择值;否则,从 arr2
中选择值:
np.where(cond, arr1, arr2)
返回的数组如下所示:
array([1000, 2000, 3, 4000, 5000, 6, 7, 8, 9000, 10])
ndarray 的文件操作
大多数 NumPy 数组都是从文件中读取的,在处理后,再写回文件。
文本文件的文件操作
文本文件的主要优点是它们可读性强,并且与任何自定义软件兼容。
让我们从以下随机数组开始:
arr
此数组包含以下数据
array([[-0.50566069, -0.52115534, 0.0757591 ], [ 1.67500165, -0.99280199, 0.80878346], [ 0.56937775, 0.36614928, -0.02532004]])
numpy.savetxt(...)
方法以文本格式将 ndarray 保存到磁盘。
以下示例使用了 fmt='%0.2lf'
格式字符串并指定了逗号分隔符:
np.savetxt('arr.csv', arr, fmt='%0.2lf', delimiter=',')
让我们检查当前目录中写入磁盘的 arr.csv
文件,如下所示:
!cat arr.csv
逗号分隔值 (CSV) 文件包含以下数据:
-0.51,-0.52,0.08 1.68,-0.99,0.81 0.57,0.37,-0.03
numpy.loadtxt(...)
方法从文本文件加载 ndarray 到内存中。在这里,我们显式指定了 delimiter=','
参数,如下所示:
arr_new = np.loadtxt('arr.csv', delimiter=','); arr_new
从文本文件中读入的 ndarray 包含以下数据:
array([[-0.51, -0.52, 0.08], [ 1.68, -0.99, 0.81], [ 0.57, 0.37, -0.03]])
二进制文件的文件操作
二进制文件对于计算机处理来说效率更高——它们保存和加载更快,比文本文件更小。但是,它们的格式可能不受其他软件支持。
numpy.save(...)
方法将 ndarray 存储为二进制格式,如下代码片段所示:
np.save('arr', arr) !cat arr.npy
arr.npy
文件的输出如下:
numpy.save(...)
方法会自动为其创建的二进制文件分配 .npy
扩展名。
numpy.load(...)
方法,如下代码片段所示,用于读取二进制文件:
arr_new = np.load('arr.npy'); arr_new
新读入的 ndarray 如下所示:
array([[-0.50566069, -0.52115534, 0.0757591 ], [ 1.67500165, -0.99280199, 0.80878346], [ 0.56937775, 0.36614928, -0.02532004]])
二进制文件格式的另一个优点是,数据可以以极高的精度存储,特别是在处理浮点值时,这在某些情况下在文本文件中并不总是可能的,因为在某些情况下会有一些精度损失。
让我们通过运行以下代码检查旧的 arr
ndarray 和新读入的 arr_new
数组是否完全匹配:
arr == arr_new
这将生成以下数组,如果元素相等则包含 True
,否则包含 False
:
array([[ True, True, True], [ True, True, True], [ True, True, True]])
因此,我们看到每个元素都完全匹配。
概要
在本章中,我们学习了如何在 Python 中创建任意维度的矩阵,如何访问矩阵的元素,如何对矩阵进行基本的线性代数运算,以及如何保存和加载矩阵。
使用 NumPy 矩阵是任何数据分析的主要操作,因为向量运算经过机器优化,因此比 Python 列表上的操作要快得多——通常快 5 到 100 倍。回测任何算法策略通常包括处理庞大的矩阵,而速度差异可以转化为节省的小时或天数时间。
在下一章中,我们将介绍第二重要的用于数据分析的库:Pandas,它是建立在 NumPy 基础上的。NumPy 提供了对基于数据框架的数据操作的支持(数据框架是 Excel 工作表的 Python 版本——即,一个二维数据结构,其中每列都有自己的类型)。