盘一盘 Python 系列 2 - NumPy (下)(三)

简介: 盘一盘 Python 系列 2 - NumPy (下)(三)

本文首发于“生信补给站”公众号 https://mp.weixin.qq.com/s/0-9zUTxZC6qefyjLyw1SSA



本节介绍四大类数组计算,具体有


  1. 元素层面 (element-wise) 计算
  2. 线性代数 (linear algebra) 计算
  3. 元素整合 (element aggregation) 计算
  4. 广播机制 (broadcasting) 计算


5.1 元素层面计算



Numpy 数组元素层面计算包括:


  1. 二元运算 (binary operation):加减乘除
  2. 数学函数:倒数、平方、指数、对数
  3. 比较运算 (comparison)


先定义两个数组 arr1 和 arr2。


arr1 = np.array([[1., 2., 3.], [4., 5., 6.]])arr2 = np.ones((2,3)) * 2print( arr1 )print( arr2 )
[[1. 2. 3.]
[4. 5. 6.]]
[[2. 2. 2.]
[2. 2. 2.]]


加、减、乘、除


print( arr1 + arr2 + 1 )print( arr1 - arr2 )print( arr1 * arr2 )print( arr1 / arr2 )
[[4. 5. 6.]
 [7. 8. 9.]]
[[-1. 0. 1.]
 [ 2. 3. 4.]]
[[ 2. 4. 6.]
 [ 8. 10. 12.]]
[[0.5 1. 1.5]
 [2. 2.5 3. ]]


倒数、平方、指数、对数



print( 1 / arr1 )print( arr1 ** 2 )print( np.exp(arr1) )print( np.log(arr1) )
[[1. 0.5 0.33333333]
[0.25 0.2 0.16666667]]
[[ 1. 4. 9.]
[16. 25. 36.]]
[[ 2.71828183 7.3890561 20.08553692]
[ 54.59815003 148.4131591 403.42879349]]
[[0. 0.69314718 1.09861229]
[1.38629436 1.60943791 1.79175947]]


比较



arr1 > arr2arr1 > 3
array([[False, False, True],
       [ True, True, True]])
array([[False, False, False],
       [ True, True, True]])


从上面结果可知


  • 「数组和数组间的二元运算」都是在元素层面上进行的
  • 「作用在数组上的数学函数」都是作用在数组的元素层面上的。
  • 「数组和数组间的比较」都是在元素层面上进行的


但是在「数组和标量间的比较」时,python 好像先把 3 复制了和 arr1 形状一样的数组 [[3,3,3], [3,3,3]],然后再在元素层面上作比较。上述这个复制标量的操作叫做「广播机制」,是 NumPy 里最重要的一个特点,在下一节会详细讲到。



5.2 线性代数计算



在机器学习、金融工程和量化投资的编程过程中,因为运行速度的要求,通常会向量化 (vectorization) 而涉及大量的线性代数运算,尤其是矩阵之间的乘积运算。


但是,在 NumPy 默认不采用矩阵运算,而是数组 (ndarray) 运算。矩阵只是二维,而数组可以是任何维度,因此数组运算更通用些。


如果你非要二维数组 arr2d 进项矩阵运算,那么可以通过调用以下函数来实现:


  • A = np.mat(arr2d)
  • A = np.asmatrix(arr2d)


下面我们分别对「数组」和「矩阵」从创建、转置、求逆和相乘四个方面看看它们的同异。


创建

创建数组 arr2d 和矩阵 A,注意它们的输出有 array 和 matrix 的关键词。



arr2d = np.array([[1,2],[3,1]])arr2d
array([[1, 2],
       [3, 1]])




A = np.asmatrix(arr2d)A
matrix([[1, 2],
        [3, 1]])


转置

数组用 arr2d.T 操作或 arr.tranpose() 函数,而矩阵用 A.T 操作。主要原因就是 .T 只适合二维数据,上贴最后也举了个三维数组在轴 1 和轴 2 之间的转置,这时就需要用函数 arr2d.tranpose(1, 0, 2) 来实现了。


print( arr2d.T )print( arr2d.transpose() )print( A.T )
[[1 3]
 [2 1]]
[[1 3]
 [2 1]]
[[1 3]
 [2 1]]


求逆

数组用 np.linalg.inv() 函数,而矩阵用 A.I 和 A**-1 操作。



print( np.linalg.inv(arr2d) )print( A.I )print( A**-1 )
[[-0.2 0.4]
 [ 0.6 -0.2]]
[[-0.2 0.4]
 [ 0.6 -0.2]]
[[-0.2 0.4]
 [ 0.6 -0.2]]


相乘

相乘是个很模棱两可的概念


  • 数组相乘是在元素层面进行,
  • 矩阵相乘要就是数学定义的矩阵相乘 (比如第一个矩阵的列要和第二个矩阵的行一样)


看个例子,「二维数组」相乘「一维数组」,「矩阵」相乘「向量」,看看有什么有趣的结果。


首先定义「一维数组」arr 和 「向量」b:




arr = np.array([1,2])b = np.asmatrix(arr).Tprint( arr.shape, b.shape )
(2,) (2, 1)


由上面结果看出, arr 的形状是 (2,),只含一个元素的元组只说明 arr 是一维,数组是不分行数组或列数组的。而 b 的形状是 (2,1),显然是列向量。


相乘都是用 * 符号,



print( arr2d*arr )print( A*b )
[[1 4]
 [3 2]]
[[5]
 [5]]


由上面结果可知,


  • 二维数组相乘一维数组得到的还是个二维数组,解释它需要用到「广播机制」,这是下节的重点讨论内容。现在大概知道一维数组 [1 2] 第一个元素 1 乘上 [1 3] 得到 [1 3],而第二个元素 2 乘上 [2 1] 得到 [4 2]。


  • 而矩阵相乘向量的结果和我们学了很多年的线代结果很吻合。



再看一个例子,「二维数组」相乘「二维数组」,「矩阵」相乘「矩阵」



print( arr2d*arr2d )print( A*A )
[[1 4]
 [9 1]]
[[7 4]
 [6 7]]


由上面结果可知,


  • 虽然两个二维数组相乘得到二维数组,但不是根据数学上矩阵相乘的规则得来的,而且由元素层面相乘得到的。两个 [[1 2], [3,1]] 的元素相乘确实等于 [[1 4], [9,1]]。


  • 而矩阵相乘矩阵的结果和我们学了很多年的线代结果很吻合。


问题来了,那么怎么才能在数组上实现「矩阵相乘向量」和「矩阵相乘矩阵」呢?用点乘函数 dot()。



print( np.dot(arr2d,arr) )print( np.dot(arr2d,arr2d) )
[5 5]
[[7 4]
 [6 7]]


结果对了,但还有一个小小的差异


  • 矩阵相乘列向量的结果是个列向量,写成 [[5],[5]],形状是 (2,1)
  • 二维数组点乘一维数组结果是个一维数组,写成 [5, 5],形状是 (2,)


由此我们来分析下 NumPy 里的 dot() 函数,计算数组和数组之间的点乘结果。



点乘函数


本节的内容也来自〖张量 101〗,通常我们也把 n 维数组称为张量,点乘左右两边最常见的数组就是


  • 向量 (1D) 和向量 (1D)
  • 矩阵 (2D) 和向量 (1D)
  • 矩阵 (2D) 和矩阵 (2D)


分别看看三个简单例子。


例一np.dot(向量, 向量) 实际上做的就是内积,即把两个向量每个元素相乘,最后再加总。点乘结果 10 是个标量 (0D 数组),形状 = ()。



x = np.array( [1, 2, 3] )y = np.array( [3, 2, 1] )z = np.dot(x,y)print( z.shape )print( z )
()
10



例二np.dot(矩阵, 向量) 实际上做的就是普通的矩阵乘以向量。点乘结果是个向量 (1D 数组),形状 = (2, )。



x = np.array( [1, 2, 3] )y = np.array( [[3, 2, 1], [1, 1, 1]] )z = np.dot(y,x)print( z.shape )print( z )
(2,)
[10 6]



例三np.dot(矩阵, 矩阵) 实际上做的就是普通的矩阵乘以矩阵。点乘结果是个矩阵 (2D 数组),形状 = (2, 3)。






x = np.array( [[1, 2, 3], [1, 2, 3], [1, 2, 3]] )y = np.array( [[3, 2, 1], [1, 1, 1]] )z = np.dot(y,x)print( z.shape )print( z )
(2, 3)
[[ 6 12 18]
[ 3 6 9]]


从例二和例三看出,当 x 第二个维度的元素 (x.shape[1]) 和 y 第一个维度的元素 (y.shape[0]) 个数相等时,np.dot(X, Y) 才有意义,点乘得到的结果形状 = (X.shape[0], y.shape[1])。


上面例子都是低维数组 (维度 ≤ 2) 的点乘运算,接下来我们看两个稍微复杂的例子。



例四:当 x 是 3D 数组,y 是 1D 数组,np.dot(x, y) 是将 x 和 y 最后一维的元素相乘并加总。此例 x 的形状是 (2, 3, 4),y 的形状是 (4, ),因此点乘结果的形状是 (2, 3)。






x = np.ones( shape=(2, 3, 4) )y = np.array( [1, 2, 3, 4] )z = np.dot(x,y)print( z.shape )print( z )
(2, 3)
[[10. 10. 10]
[10. 10. 10]]



例五:当 x 是 3D 数组,y 是 2D 数组,np.dot(x, y) 是将 x 的最后一维和 y 的倒数第二维的元素相乘并加总。此例 x 的形状是 (2, 3, 4),y 的形状是 (4, 2),因此点乘结果的形状是 (2, 3, 2)。


x = np.random.normal( 0, 1, size=(2, 3, 4) )y = np.random.normal( 0, 1, size=(4, 2) )z = np.dot(x,y)print( z.shape )print( z )
(2, 3, 2)
[[[ 2.11753451 -0.27546168]
  [-1.23348676 0.42524653]
  [-4.349676 -0.3030879 ]]
 [[ 0.15537744, 0.44865273]
  [-3.09328194, -0.43473885]
  [ 0.27844225, -0.48024693]]]


例五的规则也适用于 nD 数组和 mD 数组 (当 m ≥ 2 时) 的点乘。


5.3 元素整合计算



在数组中,元素可以以不同方式整合 (aggregation)。拿求和 (sum) 函数来说,我们可以对数组


  • 所有的元素求和
  • 在某个轴 (axis) 上的元素求和


先定义数组



arr = np.arange(1,7).reshape((2,3))arr
array([[1, 2, 3],
       [4, 5, 6]])


不难看出它是一个矩阵,分别对全部元素、跨行 (across rows)、跨列 (across columns) 求和:


print( 'The total sum is', arr.sum() )print( 'The sum across rows is', arr.sum(axis=0) )print( 'The sum across columns is', arr.sum(axis=1) )
The total sum is 21
The sum across rows is [5 7 9]
The sum across columns is [ 6 15]


分析上述结果:


  • 1, 2, 3, 4, 5, 6 的总和是 21
  • 跨行求和 = [1 2 3] + [4 5 6] = [5 7 9]
  • 跨列求和 = [1+2+3 4+5+6] = [6 15]


行和列这些概念对矩阵 (二维矩阵) 才适用,高维矩阵还是要用轴 (axis) 来区分每个维度。让我们抛弃「行列」这些特殊概念,拥抱「轴」这个通用概念来重看数组 (一到四维) 把。



规律:n 维数组就有 n 层方括号。最外层方括号代表「轴 0」即 axis=0,依次往里方括号对应的 axis 的计数加 1。


严格来说,numpy 打印出来的数组可以想象带有多层方括号的一行数字。比如二维矩阵可想象成


   [[1, 2, 3],[4, 5, 6]]


三维矩阵可想象成


   [[[1,2,3], [4,5,6]], [[7,8,9], [10,11,12]]]


由于屏幕的宽度不够,我们才把它们写成一列列的,如下


   [ [ [1, 2, 3]

        [4, 5, 6] ] 

     [ [7, 8, 9] 

        [10, 11, 12] ] ]


但在你脑海里,应该把它们想成一整行。这样会便于你理解如何按不同轴做整合运算。


有了轴的概念,我们再来看看 sum() 求和函数。

相关文章
|
10天前
|
机器学习/深度学习 数据采集 数据挖掘
解锁 Python 数据分析新境界:Pandas 与 NumPy 高级技巧深度剖析
Pandas 和 NumPy 是 Python 中不可或缺的数据处理和分析工具。本文通过实际案例深入剖析了 Pandas 的数据清洗、NumPy 的数组运算、结合两者进行数据分析和特征工程,以及 Pandas 的时间序列处理功能。这些高级技巧能够帮助我们更高效、准确地处理和分析数据,为决策提供支持。
25 2
|
16天前
|
存储 数据处理 Python
Python科学计算:NumPy与SciPy的高效数据处理与分析
【10月更文挑战第27天】在科学计算和数据分析领域,Python凭借简洁的语法和强大的库支持广受欢迎。NumPy和SciPy作为Python科学计算的两大基石,提供了高效的数据处理和分析工具。NumPy的核心功能是N维数组对象(ndarray),支持高效的大型数据集操作;SciPy则在此基础上提供了线性代数、信号处理、优化和统计分析等多种科学计算工具。结合使用NumPy和SciPy,可以显著提升数据处理和分析的效率,使Python成为科学计算和数据分析的首选语言。
26 3
|
18天前
|
数据采集 数据可视化 数据处理
如何使用Python实现一个交易策略。主要步骤包括:导入所需库(如`pandas`、`numpy`、`matplotlib`)
本文介绍了如何使用Python实现一个交易策略。主要步骤包括:导入所需库(如`pandas`、`numpy`、`matplotlib`),加载历史数据,计算均线和其他技术指标,实现交易逻辑,记录和可视化交易结果。示例代码展示了如何根据均线交叉和价格条件进行开仓、止损和止盈操作。实际应用时需注意数据质量、交易成本和风险管理。
38 5
|
17天前
|
存储 机器学习/深度学习 算法
Python科学计算:NumPy与SciPy的高效数据处理与分析
【10月更文挑战第26天】NumPy和SciPy是Python科学计算领域的两大核心库。NumPy提供高效的多维数组对象和丰富的数学函数,而SciPy则在此基础上提供了更多高级的科学计算功能,如数值积分、优化和统计等。两者结合使Python在科学计算中具有极高的效率和广泛的应用。
33 2
|
1月前
|
机器学习/深度学习 数据采集 算法
探索Python科学计算的边界:NumPy、Pandas与SciPy在大规模数据分析中的高级应用
【10月更文挑战第5天】随着数据科学和机器学习领域的快速发展,处理大规模数据集的能力变得至关重要。Python凭借其强大的生态系统,尤其是NumPy、Pandas和SciPy等库的支持,在这个领域占据了重要地位。本文将深入探讨这些库如何帮助科学家和工程师高效地进行数据分析,并通过实际案例来展示它们的一些高级应用。
49 0
探索Python科学计算的边界:NumPy、Pandas与SciPy在大规模数据分析中的高级应用
|
1月前
|
机器学习/深度学习 算法 数据挖掘
【Python篇】深度探索NumPy(下篇):从科学计算到机器学习的高效实战技巧1
【Python篇】深度探索NumPy(下篇):从科学计算到机器学习的高效实战技巧
50 5
|
1月前
|
机器学习/深度学习 算法 数据可视化
【Python篇】深度探索NumPy(下篇):从科学计算到机器学习的高效实战技巧2
【Python篇】深度探索NumPy(下篇):从科学计算到机器学习的高效实战技巧
39 1
|
1月前
|
数据挖掘 索引 Python
Python数据分析篇--NumPy--进阶
Python数据分析篇--NumPy--进阶
16 0
|
1月前
|
数据挖掘 索引 Python
Python数据分析篇--NumPy--入门
Python数据分析篇--NumPy--入门
33 0
|
6月前
|
Python
python相关库的安装:pandas,numpy,matplotlib,statsmodels
python相关库的安装:pandas,numpy,matplotlib,statsmodels
166 0