本文讨论NumPy中常用的一些高级方法。大家需要对各个函数与其输出的结果进行关联,总结相应的规律,这对大家的数学和逻辑思维有一定的要求。
本章节主要内容包括:
- 堆叠
- 拆分
- 广播
几个阵列可以沿不同的轴堆叠在一起。
示例代码如下:
import numpy as np
a = np.array([[1, 2],
[3, 4]])
b = np.array([[5, 6],
[7, 8]])
print("垂直堆叠:\n", np.vstack((a, b)))
print("\n水平堆叠:\n", np.hstack((a, b)))
print("\n连接到第2轴:\n", np.concatenate((a, b), 1))
c = [5, 6]
print("\n列堆叠:\n", np.column_stack((a, c)))
输出:
垂直堆叠:
[[1 2]
[3 4]
[5 6]
[7 8]]
水平堆叠:
[[1 2 5 6]
[3 4 7 8]]
连接到第2轴:
[[1 2 5 6]
[3 4 7 8]]
列堆叠:
[[1 2 5]
[3 4 6]]
对于拆分,常见的有以下功能:
示例代码如下:
import numpy as np
a = np.array([[1, 3, 5, 7, 9, 11],
[2, 4, 6, 8, 10, 12]])
# 沿水平轴拆分
print("沿水平轴分为三部分:\n", np.hsplit(a, 3))
# 沿垂直轴拆分
print("\n沿垂直轴分为两部分:\n", np.vsplit(a, 2))
输出:
沿水平轴分为两部分:
[array([[1,3,5],
[2,4,6]]),数组([[7,9,11],
[8,10,12]])]
沿垂直轴分为2部分:
[array([[1,3,5,7,9,11]]),array([[2,4,6,8,10,12]])]
NumPy的广播用于在算术运算期间处理具有不同形状的数组。受某些约束的影响,较小的阵列在较大的阵列上“广播”,以便它们具有兼容的形状。
广播提供了一种矢量化数组操作的方法,以便在C(而不是Python)中进行循环,它可以在不制作不必要的数据副本的情况下实现这一点,并且实现高效。另外,广播也有一个缺点,因为它会导致内存使用效率低下,从而减慢计算速度。
NumPy操作通常是逐个元素完成的,这需要两个数组具有完全相同的形状。当阵列的形状满足某些约束时,Numpy的广播规则放宽了这种约束。
广播规则:为了进行广播,操作中两个数组的尾轴大小必须相同,或者其中一个必须为1。
让我们看一些例子:
A(2-D array): 4 x 3
B(1-D array): 3
Result : 4 x 3
A(4-D array): 7 x 1 x 6 x 1
B(3-D array): 3 x 1 x 5
Result : 7 x 3 x 6 x 5
但这将是一个不匹配:
A: 4 x 3
B: 4
当在操作中组合数组和标量值时,会发生最简单的广播示例。 请看下面给出的例子:
import numpy as np
a = np.array([1.0, 2.0, 3.0])
# Example 1
b = 2.0
print(a * b)
# Example 2
c = [2.0, 2.0, 2.0]
print(a * c)
输出:
[2. 4. 6.]
[2. 4. 6.]
我们可以将在算术运算期间被拉伸的标量b想象成具有与a相同形状的数组。b中的新元素,如上图所示,只是原始标量的副本。 Numpy足够聪明,可以使用原始标量值,而无需实际制作副本,以便广播操作尽可能保持内存和计算效率。因为Example 1在乘法期间移动较少的内存(b是标量,而不是数组),所以使用numpy带有一百万个元素的阵列,比Example 2快大约10%!下图使概念更加清晰:
在上面的例子中,标量b被拉伸成具有与a相同形状的阵列,因此形状与逐个元素的乘法兼容。
现在,让我们看一个两个数组都被拉伸的例子。
import numpy as np
a = np.array([0.0, 10.0, 20.0, 30.0])
b = np.array([0.0, 1.0, 2.0])
print("a:", a)
print("a[:, np.newaxis]\n", a[:, np.newaxis])
print("a[:, np.newaxis] + b:\n", a[:, np.newaxis] + b)
输出:
[[0. 1. 2.]
[10. 11. 12.]
[20. 21. 22.]
[30. 31. 32.]]
在某些情况下,广播会拉伸两个阵列以形成大于任一初始阵列的输出阵列。
Numpy具有支持本机日期时间功能的数据类型,数据类型为“datetime64”,因为“datetime”已被Python中的日期时间库所占用。
请看下面的示例:
import numpy as np
# 创建日期
today = np.datetime64('2019-04-18')
print("日期是:", today)
print("年份是:", np.datetime64(today, 'Y'))
# 创建月份日期
dates = np.arange('2019-02', '2019-03', dtype='datetime64[D]')
print("\n2019年2月的日期:\n", dates)
print("今天是二月:", today in dates)
# 计算日期
dur = np.datetime64('2020-01-01') - np.datetime64('2019-01-01')
print("\n天数:", dur)
print("周数:", np.timedelta64(dur, 'W'))
# 日期排序
a = np.array(['2020-02-12', '2019-01-13', '2019-05-22'], dtype='datetime64')
print("\n按日期排序的日期:", np.sort(a))
输出:
日期是: 2019-04-18
年份是: 2019
2019年2月的日期:
['2019-02-01' '2019-02-02' '2019-02-03' '2019-02-04' '2019-02-05'
'2019-02-06' '2019-02-07' '2019-02-08' '2019-02-09' '2019-02-10'
'2019-02-11' '2019-02-12' '2019-02-13' '2019-02-14' '2019-02-15'
'2019-02-16' '2019-02-17' '2019-02-18' '2019-02-19' '2019-02-20'
'2019-02-21' '2019-02-22' '2019-02-23' '2019-02-24' '2019-02-25'
'2019-02-26' '2019-02-27' '2019-02-28']
今天是二月: False
天数: 365 days
周数: 52 weeks
按日期排序的日期: ['2019-01-13' '2019-05-22' '2020-02-12']
NumPy的线性代数模块提供了在任何numpy数组上应用线性代数的各种方法。
你可以找到:
请看下面的示例,演示了我们如何使用NumPy来执行一些矩阵运算。
import numpy as np
A = np.array([[6, 1, 1],
[4, -2, 5],
[2, 8, 7]])
print("矩阵A的矩阵等级:", np.linalg.matrix_rank(A))
print("\n矩阵A对角线的总和:", np.trace(A))
print("\n矩阵A的行列式:", np.linalg.det(A))
print("\n矩阵A的逆:\n", np.linalg.inv(A))
print("\n矩阵A提高到幂2:\n", np.linalg.matrix_power(A, 2))
输出:
矩阵A的矩阵等级: 3
矩阵A对角线的总和: 11
矩阵A的行列式: -306.0
矩阵A的逆:
[[ 0.17647059 -0.00326797 -0.02287582]
[ 0.05882353 -0.13071895 0.08496732]
[-0.11764706 0.1503268 0.05228758]]
矩阵A提高到幂2:
[[42 12 18]
[26 48 29]
[58 42 91]]
让我们假设我们想要求解这个线性方程组:
x + 2*y = 8
3*x + 4*y = 18
使用linalg.solve函数来计算上面这个线性方程,如下所示:
import numpy as np
# 系数
a = np.array([[1, 2], [3, 4]])
# 常数
b = np.array([8, 18])
print("线性方程的解:", np.linalg.solve(a, b))
输出:
线性方程的解:[2. 3.]
可见方程式的解正是x=2, y=3
。
最后,我们来看一个示例,如何使用最小二乘法执行线性回归。
线性回归它是最小化从每个数据点到线的距离的平方和的线。因此,给定n对数据(xi,yi),我们要查找的参数是w1和w2,它们最小化了错误:
下面的例子会使用到matplotlib库,未安装的先安装再使用。
pip install matplotlib
示例如下
import numpy as np
import matplotlib.pyplot as plt
# x坐标
x = np.arange(0, 9)
A = np.array([x, np.ones(9)])
# 线性生成序列
y = [19, 20, 20.5, 21.5, 22, 23, 23, 25.5, 24]
# 求回归线参数
w = np.linalg.lstsq(A.T, y)[0]
# 绘制线条
line = w[0]*x + w[1] # 回归线
plt.plot(x, line, 'r-')
plt.plot(x, y, 'o')
plt.show()
输出:
对于绘制的代码我们将有专门介绍Matplotlib的章节再作解释。
NumPy是一个广泛使用的通用库,它是许多其他计算库的核心,如scipy、scikit-learn、tensorflow、matplotlib、opencv等。对NumPy有基本的了解有助于有效地处理其他更高级别的库。
若有疑问,欢迎联系作者(微信:lixu1770105)。