Numpy

简介

Numpy 是一个基础的科学计算库,支持多维数组的数据类型以及复杂数组运算操作,并且还提供了许多有用的科学计算函数。

多维数组

多维数组是计算的基石

多维数组 numpy.ndarray 是 Numpy 中重要的数据类型,是科学计算的数据容器和基石。

多维数组含有多个维度,不同维度可以含有不同数量的元素,不过同一个多维数组中的元素类型必须保持一致。多维数组的维度数量称为阶(rank),每个维度用轴(axis)来指代,数组形状(shape)是用来记录数组每个维度元素数量的一个 tuple 对象。

下面通过一个示例,来看多维数组对象的一些常用属性:

import numpy as np

a = np.array([[1, 2, 3], [4, 5, 6]])

print(a.ndim)  # 返回一个整数,表示数组的维度数量
print(a.shape)  # 返回一个 tuple,表示数组中每个维度的元素数量
print(a.size)  # 返回一个整数,表示数组中含有的元素总数
print(a.dtype)  # 返回数组中元素的数据类型
print(a.itemsize)  # 返回数组中每个元素占用的字节数
print(a.data)  # 返回真正储存数组中元素的对象
2
(2, 3)
6
int32
4
<memory at 0x0000000004F5B7E0>

为什么说多维数组是科学计算的基石?

Numpy 为多维数组提供了许多数学运算操作,比如数组之间可以进行加减乘除等运算,并且通过 Broadcasting 机制(后面会介绍)可以将这些运算扩展到维度不匹配的数组之间。Numpy 还支持数组进行一些常规的线性代数运算,如向量内乘、矩阵相乘等。此外 Numpy 还提供了许多常用的数学函数,如 exp, log, sin, cos 等,并且这些函数可以直接作用于数组对象上。因此多维数组是数据的容器,是科学计算的基石。

创建数组

  • 由 Python 中的 listtuple 对象来创建
a = np.array([1, 2, 3])  # 创建一维数组
b = np.array([[1, 2], [3, 4]])  # 创建二维数组
c = np.array([(1, 2), (3, 4), (5, 6)])  # 使用 tuple 也可以创建数据

print(a.shape, b.shape, c.shape)
(3,) (2, 2) (3, 2)
  • 由 Numpy 中的一些函数来创建数组
print("zeros 函数创建元素内容为 0.0 的数组")
a = np.zeros(5)
print(a.shape)
print(a)
b = np.zeros((2, 3))
print(b.shape)
print(b)
zeros 函数创建元素内容为 0.0 的数组
(5,)
[0. 0. 0. 0. 0.]
(2, 3)
[[0. 0. 0.]
 [0. 0. 0.]]
print("ones 函数创建元素内容为 1.0 的数组")
c = np.ones(5)
print(c.shape)
print(c)
d = np.ones((2, 3))
print(d.shape)
print(d)
ones 函数创建元素内容为 1.0 的数组
(5,)
[1. 1. 1. 1. 1.]
(2, 3)
[[1. 1. 1.]
 [1. 1. 1.]]
print("full 函数创建指定内容的数组")
print(np.full(5, 3.14))
print(np.full((2, 3), np.pi))
full 函数创建指定内容的数组
[3.14 3.14 3.14 3.14 3.14]
[[3.14159265 3.14159265 3.14159265]
 [3.14159265 3.14159265 3.14159265]]
print("empty 函数创建元素内容为原来内存位置上随机数据的数组")
e = np.empty(5)
print(e.shape)
print(e)
f = np.empty((2, 3))
print(f.shape)
print(f)
empty 函数创建元素内容为原来内存位置上随机数据的数组
(5,)
[3.14 3.14 3.14 3.14 3.14]
(2, 3)
[[3.14159265 3.14159265 3.14159265]
 [3.14159265 3.14159265 3.14159265]]
print("zeros_like, ones_like, full_like, empty_like 这些函数按照其它数组的 shape 来创建新数组")
print(np.zeros_like(e))
print(np.ones_like(e))
print(np.full_like(e, 3.14))
print(np.empty_like(e))
zeros_like, ones_like, full_like, empty_like 这些函数按照其它数组的 shape 来创建新数组
[0. 0. 0. 0. 0.]
[1. 1. 1. 1. 1.]
[3.14 3.14 3.14 3.14 3.14]
[3.14 3.14 3.14 3.14 3.14]
print("arange 函数创建一维数组")
print(np.arange(10))
print(np.arange(5, 10))
print(np.arange(5, 10, 2))
print(np.arange(0, 1, 0.13))
arange 函数创建一维数组
[0 1 2 3 4 5 6 7 8 9]
[5 6 7 8 9]
[5 7 9]
[0.   0.13 0.26 0.39 0.52 0.65 0.78 0.91]
print("eye 函数创建单位矩阵")
print(np.eye(3))
eye 函数创建单位矩阵
[[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
print("random.rand 函数创建服从 0~1 均匀分布的随机数或数组")
print(np.random.rand())
print(np.random.rand(5))
print(np.random.rand(2, 3))  # 注:参数不是 tuple
random.rand 函数创建服从 0~1 均匀分布的随机数或数组
0.2590998410027371
[0.57327177 0.86796613 0.40592767 0.49559488 0.44319993]
[[0.43919482 0.38025582 0.45335883]
 [0.94173622 0.81884766 0.95223028]]
print("random.randn 函数创建服从 N(0, 1) 正态分布的随机数或数组")
print(np.random.randn())
print(np.random.randn(5))
print(np.random.randn(2, 3))
random.randn 函数创建服从 N(0, 1) 正态分布的随机数或数组
1.0812523964794132
[ 1.16836004 -0.73916035 -0.74210248 -0.5293441   0.09678252]
[[ 0.10269763 -2.16731007  0.09927973]
 [ 0.54190024  1.26060379  0.53431381]]
print("fromfunction 通过执行某个函数来创建数组")
x = np.fromfunction(lambda i, j: i + j, (3, 3), dtype=int)
print(x)
fromfunction 通过执行某个函数来创建数组
[[0 1 2]
 [1 2 3]
 [2 3 4]]

注意

通过 zeros, ones, empty 等函数创建数组时,元素的数据类型默认是浮点数(np.float64),如果想要指定其它数据类型,可以通过传递参数 dtype 来实现。

由于浮点数的精度在计算机上表示是近似的,通过 arange 函数创建一维数组的长度可能会有变化,如果想要创建指定长度的一维数组,就要使用函数 linspace

  • 由其它子数组来堆叠创建

利用堆叠操作,可以横向/纵向堆叠子数组来构造数组,参见函数 vstack, hstack 等。

重塑数组

所谓重塑数组指的是,在不改变数组中数据的同时改变数组的 shape。有的方法改变原数组的 shape,有的方法返回一个新的数组。

示例:

a = np.arange(12)

print(a)

print(a.reshape(3, 4))  # 改变 shape,返回新数组

print(a.reshape(-1, 6))  # 用“-1”自动计算维度大小

print(a)

a.resize(3, 4)  # 改变原数组的 shape

print(a)

print(a.T)  # 返回转置的新数组,等价于 a.transpose()

print(a.ravel())  # 返回一个新的一维数组
[ 0  1  2  3  4  5  6  7  8  9 10 11]
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]]
[ 0  1  2  3  4  5  6  7  8  9 10 11]
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
[[ 0  4  8]
 [ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]]
[ 0  1  2  3  4  5  6  7  8  9 10 11]

访问数组

slice 和整数索引

索引一维数组

语法:a[i],其中 a 是被索引的一维数组,i 是 slice 或者整数对象。

要点:跟索引普通 Python 序列对象(list, tuple)的语法是一样的。

示例:

a = np.arange(10)
print(a[3])
print(a[1:5])
print(a[:5])
print(a[::-1])
3
[1 2 3 4]
[0 1 2 3 4]
[9 8 7 6 5 4 3 2 1 0]

索引多维数组

语法:a[i, j],其中 a 是被索引的多维数组,ij 是 slice 或者整数对象。

要点:数组 a 每个维度都用一个 slice 或者整数进行索引,得到的结果是一个子数组。

示例:

a = np.arange(12).reshape(3, 4)

print(a[0:2, 2:4])  # 用 slice 索引

print(a[0:2, :])

print(a[0:2, 2])  # 用 slice 和整数索引,子数组的阶变小(一阶)

print(a[0:2, 2:3])  # 跟上式返回数据相同,但子数组阶不同

print(a[:, 2])

print(a[2, 2])  # 用整数索引,子数组的阶变小(0阶)

b = np.arange(30).reshape(2, 5, 3)
print(b[...,2])  # 等价于 b[:,:,2],用 ... 表示多个连续的 :
[[2 3]
 [6 7]]
[[0 1 2 3]
 [4 5 6 7]]
[2 6]
[[2]
 [6]]
[ 2  6 10]
10
[[ 2  5  8 11 14]
 [17 20 23 26 29]]

整数数组索引

索引数组的第一维

语法:a[i],其中 a 是被索引数组,i 是索引数组,它们都可能是一维或多维数组。

要点:索引数组中的下标总是引用被索引数组的第一维,因此结果数组的 shape 由索引数组的 shape 跟被索引数组的第一维共同决定。

示例:

print("被索引数组是一维数组")
a = np.arange(10)**2
print(a)
i = np.array([1, 1, 2, 2, 3, 3])
print(a[i])

j = np.array([[1, 2], [3, 4]])
print(a[j])
被索引数组是一维数组
[ 0  1  4  9 16 25 36 49 64 81]
[1 1 4 4 9 9]
[[ 1  4]
 [ 9 16]]
print("被索引数组是多维数组")
a = np.arange(12).reshape(3, 4)
print(a)
i = np.array([0, 1, 1, 0, 2])  # 数组中的下标引用被索引数组的第一维/行(即一维数组),因此结果是二维数组
print(a[i])
j = np.array([[0, 1], [1, 0]])  # 同样下标引用被索引数组的行,同时索引数组是二维的,因此结果是三维数组
print(a[j])
被索引数组是多维数组
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 4  5  6  7]
 [ 0  1  2  3]
 [ 8  9 10 11]]
[[[0 1 2 3]
  [4 5 6 7]]

 [[4 5 6 7]
  [0 1 2 3]]]

索引数组的多个维度

语法:a[i, j]a[[i, j]]a[(i, j)],其中 a 是被索引数组,ij 都是索引数组,i 索引 a 的第一维,j 索引 a 的第二维,以此类推有 a[i, j, k, l]

要点:ij 的 shape 必须相同;a[np.array([i, j])] 不等同于 a[i, j]

示例:

a = np.arange(12).reshape(3, 4)
print(a)
i = np.array([[0, 1], [1, 0]])
j = np.array([[1, 2], [2, 3]])
print(a[i, j])

print(a[i, 2])  # 相当于 a[i, np.array([[2, 2], [2, 2]])]
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
[[1 6]
 [6 3]]
[[2 6]
 [6 2]]

布尔数组索引

用单个布尔数组来索引

语法:a[b],其中 a 是被索引数组,b 是用来索引的布尔数组,且 b 的 shape 跟 a 的 shape 是相同的。

示例:

a = np.arange(12).reshape(3, 4)
print(a)
b = a > 4  # b 现在是一个布尔数组,跟 a 的 shape 相同
print(b)

print(a[b])  # 用 b 索引 a

a[b] = -1  # 对索引的元素赋值

print(a)
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
[[False False False False]
 [False  True  True  True]
 [ True  True  True  True]]
[ 5  6  7  8  9 10 11]
[[ 0  1  2  3]
 [ 4 -1 -1 -1]
 [-1 -1 -1 -1]]

用多个一维布尔数组来索引

语法:a[b1, b2],其中 a 是被索引数组,b1b2 都是一维布尔数组,并且其长度分别跟 a 的第一维和第二维长度一致。

示例:

a = np.arange(6).reshape(2, 3)
print(a)

b1 = np.array([True, False])
print(a[b1, :])  # 等价于 a[b1]

b2 = np.array([False, True, False])
print(a[:, b2])

print(a[b1, b2])  # 每个索引的布尔数组进行“与”运算来决定元素是否被选取
[[0 1 2]
 [3 4 5]]
[[0 1 2]]
[[1]
 [4]]
[1]

迭代数组

多维数组按照第一维来迭代:

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

for row in a:
    print(row)
[1 2]
[3 4]

多维数组按照元素来迭代:

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

for e in a.flat:
    print(e)
1
2
3
4

复制数组

关于多维数组对象的复制机制,不仅仅涉及到数组对象本身,还涉及到真正存储数组数据的对象。

  1. 不复制:不复制数组对象,也不复制存储数据的对象
a = np.array([1, 2, 3])

b = a

print(id(a), id(b))

print(a.shape)
b.shape = 3, 1
print(a.shape)

b[0] = -1
print(a[0])

def f(c):
    c *= 2

print(a)
f(a)
print(a)
83915200 83915200
(3,)
(3, 1)
[-1]
[[-1]
 [ 2]
 [ 3]]
[[-2]
 [ 4]
 [ 6]]
  1. 浅复制:复制数组对象,但共享存储数据的对象
a = np.array([1, 2, 3])

b = a.view()

print(id(a), id(b))

print(a.shape)
b.shape = 3, 1
print(a.shape)

b[0] = -1
print(a[0])

a[:] = 0  # slice 本身就是一种浅复制,因此可以改变数据
print(a)
83915120 83915040
(3,)
(3,)
-1
[0 0 0]
  1. 深复制:复制数组对象,并复制存储数据的对象
a = np.array([1, 2, 3])

b = a.copy()

print(id(a), id(b))

b[0] = -1
print(a[0])
83915360 83915440
1

数组拆分和合并

在处理数据时,我们经常需要将大的数组拆分成若干个小的,或者将小的数组堆叠成一个大的,Numpy 提供了一些函数用于数组的拆分和合并。

  • 数组合并
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
print(a)
print(b)

print(np.hstack((a, b)))  # 横向堆叠
print(np.vstack((a, b)))  # 纵向堆叠

print(np.tile(a, 2))  # 重复数组
print(np.tile(a, (2, 2)))  # 重复数组
[[1 2]
 [3 4]]
[[5 6]
 [7 8]]
[[1 2 5 6]
 [3 4 7 8]]
[[1 2]
 [3 4]
 [5 6]
 [7 8]]
[[1 2 1 2]
 [3 4 3 4]]
[[1 2 1 2]
 [3 4 3 4]
 [1 2 1 2]
 [3 4 3 4]]
  • 数组拆分
a = np.arange(16).reshape(4, 4)

print(a)
print(np.vsplit(a, 2))  # row-wise 二等分
print(np.hsplit(a, 2))  # column-wise 二等分
print(np.vsplit(a, [3])) # row-wise 二分但不等分
print(np.vsplit(a, [2, 3, 5]))  # row-wise 多个分割点

b = np.arange(8).reshape(2, 2, 2)
print(b)
print(np.vsplit(b, 2))  # 第一维二等分,等价于 np.split(b, 2, axis=0)
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]
 [12 13 14 15]]
[array([[0, 1, 2, 3],
       [4, 5, 6, 7]]), array([[ 8,  9, 10, 11],
       [12, 13, 14, 15]])]
[array([[ 0,  1],
       [ 4,  5],
       [ 8,  9],
       [12, 13]]), array([[ 2,  3],
       [ 6,  7],
       [10, 11],
       [14, 15]])]
[array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]]), array([[12, 13, 14, 15]])]
[array([[0, 1, 2, 3],
       [4, 5, 6, 7]]), array([[ 8,  9, 10, 11]]), array([[12, 13, 14, 15]]), array([], shape=(0, 4), dtype=int32)]
[[[0 1]
  [2 3]]

 [[4 5]
  [6 7]]]
[array([[[0, 1],
        [2, 3]]]), array([[[4, 5],
        [6, 7]]])]

数组运算

Numpy 重载了许多 Python 中的运算符,以支持数组运算,同时也提供了许多计算函数可以直接作用于数组。

常见运算

以下运算都是 element-wise 的,也即运算操作会分别作用于各个元素上。

a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])

print(a+b)
print(np.add(a, b))

print(a-b)
print(np.subtract(a, b))

print(a*b)
print(np.multiply(a, b))

print(a/b)
print(np.divide(a, b))

print(a>3)  # 返回布尔数组

print(a**2)

a += 1  # 数组 a 将被修改
b += 2  # 数组 b 将被修改
print(a)
print(b)
[[ 6  8]
 [10 12]]
[[ 6  8]
 [10 12]]
[[-4 -4]
 [-4 -4]]
[[-4 -4]
 [-4 -4]]
[[ 5 12]
 [21 32]]
[[ 5 12]
 [21 32]]
[[0.2        0.33333333]
 [0.42857143 0.5       ]]
[[0.2        0.33333333]
 [0.42857143 0.5       ]]
[[False False]
 [False  True]]
[[ 1  4]
 [ 9 16]]
[[2 3]
 [4 5]]
[[ 7  8]
 [ 9 10]]

矩阵乘和向量乘

Numpy 重载的运算符 * 并不表示线性代数中的矩阵乘和向量乘,因此提供了函数 dot 来表示。

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

print(np.dot(a, b))  # vector inner product

x = np.array([[1, 2, 3], [4, 5, 6]])
y = np.array([[1, 2], [3, 4], [5, 6]])

print(np.dot(x, y))  # matrix product: 2x3 * 3x2 = 2x2
print(np.dot(y, x))  # matrix product: 3x2 * 2x3 = 3x3

print(np.dot(a, y))  # vector * matrix: 3 * 3x2 = 2

print(np.dot(x, a))  # matrix * vector: 2x3 * 3 = 2

x = np.array([1, 2, 3])
y = np.array([5, 6])

print(x.reshape(3, 1) * y)  # vector outer product: 利用 Broadcasting 实现向量外乘
print(y.reshape(2, 1) * x)
32
[[22 28]
 [49 64]]
[[ 9 12 15]
 [19 26 33]
 [29 40 51]]
[22 28]
[14 32]
[[ 5  6]
 [10 12]
 [15 18]]
[[ 5 10 15]
 [ 6 12 18]]

常用数学函数

a = 5*np.random.randn(3, 4) + 2
print(a)

print(np.sign(a))
print(np.absolute(a))
print(np.square(a))
print(np.sqrt(np.absolute(a)))
print(np.sin(np.arange(0, 2*np.pi, 0.1)))
print(np.exp(np.array([1, 2, 3])))
print(np.log(np.array([1, 2, 3])))
[[ 7.57556324  3.27540796 -4.8518763  -0.18195222]
 [-4.98060659  0.40808876 -6.15233458  4.63298471]
 [-2.22108839  1.41171191  5.69111694  8.5515381 ]]
[[ 1.  1. -1. -1.]
 [-1.  1. -1.  1.]
 [-1.  1.  1.  1.]]
[[7.57556324 3.27540796 4.8518763  0.18195222]
 [4.98060659 0.40808876 6.15233458 4.63298471]
 [2.22108839 1.41171191 5.69111694 8.5515381 ]]
[[5.73891584e+01 1.07282973e+01 2.35407037e+01 3.31066093e-02]
 [2.48064420e+01 1.66536437e-01 3.78512207e+01 2.14645474e+01]
 [4.93323362e+00 1.99293052e+00 3.23888120e+01 7.31288038e+01]]
[[2.75237411 1.80980882 2.20269751 0.42655857]
 [2.23172727 0.63881825 2.48039    2.15243692]
 [1.49033164 1.18815484 2.3856062  2.9243013 ]]
[ 0.          0.09983342  0.19866933  0.29552021  0.38941834  0.47942554
  0.56464247  0.64421769  0.71735609  0.78332691  0.84147098  0.89120736
  0.93203909  0.96355819  0.98544973  0.99749499  0.9995736   0.99166481
  0.97384763  0.94630009  0.90929743  0.86320937  0.8084964   0.74570521
  0.67546318  0.59847214  0.51550137  0.42737988  0.33498815  0.23924933
  0.14112001  0.04158066 -0.05837414 -0.15774569 -0.2555411  -0.35078323
 -0.44252044 -0.52983614 -0.61185789 -0.68776616 -0.7568025  -0.81827711
 -0.87157577 -0.91616594 -0.95160207 -0.97753012 -0.993691   -0.99992326
 -0.99616461 -0.98245261 -0.95892427 -0.92581468 -0.88345466 -0.83226744
 -0.77276449 -0.70554033 -0.63126664 -0.55068554 -0.46460218 -0.37387666
 -0.2794155  -0.1821625  -0.0830894 ]
[ 2.71828183  7.3890561  20.08553692]
[0.         0.69314718 1.09861229]

更多关于常用数学函数,参考文档

作用于轴的函数

Numpy 提供的某些函数可以作用于数组的指定轴。之前有提到 Numpy 中用轴来指代维度,某些函数可以通过指定轴来指定该函数将作用于哪个维度进行计算。

示例:

a = np.arange(12).reshape(3, 4)
print(a)

print(a.sum())  # 作用于整个数组
print(a.sum(axis=0))  # 作用于第一抽,即数组行
print(a.sum(axis=1))  # 作用于第二轴,即数组列

print(a.min())  # 作用于整个数组
print(a.min(axis=0))  # 作用于数组行
print(a.min(axis=1))  # 作用于数组列

print(a.argmin())  # 作用于整个数组
print(a.argmin(axis=0))  # 作用于数组行
print(a.argmin(axis=1))  # 作用于数组列
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
66
[12 15 18 21]
[ 6 22 38]
0
[0 1 2 3]
[0 4 8]
0
[0 0 0 0]
[0 0 0]

不过从直觉也许你会感到困惑,如二维数组的轴如下所示:

axis 0 → [[1, 2]
       [3, 4]]
         ↑
        axis 1

因此 sum(a, axis=0) 似乎应该分别求每行的和,结果为 [3, 7],但事实上求出的结果却是 [4, 6]。也即为 sum 函数指定 axis=0 后,是对每列分别求和。该如何理解这种反直觉的行为呢?将函数中指定的轴,想象成为数组在计算时将要坍缩(collapse)的方向,如 sum(a, axis=0) 表示在求和计算时,数组将沿着行的方向坍缩,也即每列值进行求和。

Broadcasting

Numpy 提供了 Broadcasting 机制,允许不同 shape 的数组之间进行运算。具体来说,有时我们想要将低阶数组和高阶数组进行运算,Broadcasting 机制使得这类运算可以实现。

假设我们想要将一个行向量加到另外一个矩阵的每个行中,如果没有 Broadcasting 机制,我们要这样做:

a = np.array([[1, 2, 3], [4, 5, 6]])
x = np.array([-1, -1, -1])

xx = np.tile(x, (2, 1))  # 堆叠向量 x 以构造矩阵 2x3
b = a + xx
print(b)
[[0 1 2]
 [3 4 5]]

但利用 Broadcasting 机制,这样的计算变得十分简洁:

b = a + x
print(b)
[[0 1 2]
 [3 4 5]]

从上例可以看出,尽管 a.shape 等于 (2, 3)x.shape 等于 (3, ),但利用 Broadcasting 机制,不同阶的数组之间可以进行运算。

类似的将一个列添加到矩阵中所有列的方法如下:

a = np.array([[1, 2, 3], [4, 5, 6]])
x = np.array([-1, -2])

print(a + x.reshape(2, 1))
[[0 1 2]
 [2 3 4]]

详解 Broadcasting 机制

摘录自 http://cs231n.github.io/python-numpy-tutorial/#numpy-broadcasting 的解释:

Broadcasting two arrays together follows these rules:

  1. If the arrays do not have the same rank, prepend the shape of the lower rank array with 1s until both shapes have the same length.
  2. The two arrays are said to be compatible in a dimension if they have the same size in the dimension, or if one of the arrays has size 1 in that dimension.
  3. The arrays can be broadcast together if they are compatible in all dimensions.
  4. After broadcasting, each array behaves as if it had shape equal to the elementwise maximum of shapes of the two input arrays.
  5. In any dimension where one array had size 1 and the other array had size greater than 1, the first array behaves as if it were copied along that dimension

更多关于 Broadcasting 机制,参见文档

Universal Functions

Numpy 中支持 Broadcasting 机制的计算函数叫做 universal functions,Numpy 提供的大多数常见数学函数都是 universal 的,参见文档

线性代数

Numpy 提供了一个子库 linalg 和一些函数,专门用来处理常见的线性代数运算问题。

示例

a = np.array([[1.0, 2.0], [3.0, 4.0]])
print(a)

print(np.dot(a, a))  # 矩阵相乘

print(a.transpose())  # 矩阵转置

print(np.trace(a))  # 矩阵 trace

print(np.linalg.inv(a))  # 逆矩阵

print(np.linalg.det(a))  # 矩阵 determinant

print(np.linalg.norm(np.array([1, 2, 2])))  # 向量模

print(np.linalg.norm(np.array([[1, 2], [3, 4]])))  # 矩阵模

y = np.array([[5.0], [7.0]])
print(np.linalg.solve(a, y))  # 解线性方程组

w, v = np.linalg.eig(a)  # 矩阵特征分解
print(w)
print(v)

u, s, vh = np.linalg.svd(a, full_matrices=True)  # 矩阵奇异值分解
print(u)
print(s)
print(vh)
[[1. 2.]
 [3. 4.]]
[[ 7. 10.]
 [15. 22.]]
[[1. 3.]
 [2. 4.]]
5.0
[[-2.   1. ]
 [ 1.5 -0.5]]
-2.0000000000000004
3.0
5.477225575051661
[[-3.]
 [ 4.]]
[-0.37228132  5.37228132]
[[-0.82456484 -0.41597356]
 [ 0.56576746 -0.90937671]]
[[-0.40455358 -0.9145143 ]
 [-0.9145143   0.40455358]]
[5.4649857  0.36596619]
[[-0.57604844 -0.81741556]
 [ 0.81741556 -0.57604844]]
Next