1 构造方法
1. 使用list构建:
>>> import numpy as np
>>> arr = np.array([1, 2, 3])
>>> print(arr, arr.dtype)
[1 2 3] int32
从例子中,我们可以看到,使用dtype来查看数组中元素的类型。
2. 创建一个全0/全1的数组
>>> zero_arr = np.zeros((2, 3))
>>> print(zero_arr)
[[0. 0. 0.]
[0. 0. 0.]]
>>> one_arr = np.ones((2, 3))
>>> print(one_arr)
[[1. 1. 1.]
[1. 1. 1.]]
函数的入参是一个tuple,分别代表行和列,上例中创建了两个两行三列的数组。分别是全0和全1。我们也可以使用其他的矩阵来创造全0或者全1的矩阵:ones_like和zeros_like函数能帮助我们
>>> d = np.zeros_like(c)
>>> print(d)
[[0 0]
[0 0]]
>>> d = np.ones_like(c)
>>> print(d)
[[1 1]
[1 1]]
3. 创建被某个值填充的数组
>>> full_arr = np.full((2, 3), 8)
>>> print(full_arr)
[[8 8 8]
[8 8 8]]
函数中传入两个参数,一个是一个tuple,tuple的元素表示矩阵有几行几列。第二参数是一个值,表示用什么值填充整个矩阵。
4. 创建对角矩阵
>>> diag_mat = np.eye(3)
>>> print(diag_mat)
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
上例中穿件了一个3*3的对角矩阵。
5. 随机值矩阵
>>> rand_mat = np.random.randn(2,3)
>>> print(rand_mat)
[[-0.179857 0.05689865 -0.50993978]
[-0.41198704 -2.08951967 0.18763144]]
注意,在这里,入参不是tuple了,变成了两个表示行数和列数的数字。和之前的套路不一样,比较容易搞错。该函数生成的数据符合正太分布。
随机生成0到1之间的数字如下例所示。
>>> rand_mat = np.random.rand(2, 3)
>>> print(rand_mat)
[[0.62627156 0.23020075 0.34346337]
[0.49663935 0.13988671 0.56145168]]
生成指定范围的整数矩阵如下例,其中第一个参数和第二个参数是范围,为半闭半开区间
>>> rand_mat = np.random.randint(3, 7, (2, 3))
>>> print(rand_mat)
[[4 3 3]
[6 5 4]]
6. 创建一个没有被初始化的矩阵
>>> uninit_mat = np.empty((2, 3))
>>> print(uninit_mat)
[[0.179857 0.05689865 0.50993978]
[0.41198704 2.08951967 0.18763144]]
7. 创建一个指定范围的矩阵
>>> rang_mat = np.arange(15)
>>> print(rang_mat)
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
>>> rang_mat2 = np.arange(0, 15, 2)
>>> print(rang_mat2)
[ 0 2 4 6 8 10 12 14]
2. 矩阵元素的类型
矩阵元素的类型可以使用dtype来访问,参见1.1节。也可以使用函数astype将数组内的元素进行转换:
>>> a = np.arange(3)
>>> print(a, a.dtype)
[0 1 2] int32
>>> b = a.astype(np.float64)
>>> print(b, b.dtype)
[0. 1. 2.] float64
3. 矩阵元素的访问
>>> a = np.random.randint(0,10, (2, 3))
>>> print(a)
[[0 5 6]
[8 4 7]]
>>> a[0, 1]
5
>>> a[1][0]
>>> 8
4. 矩阵的size
可以使用shape来查询,也可以使用reshape来改变一个矩阵的size。
>>> print(a)
[[0 5 6]
[8 4 7]]
>>> print(a)
[[0 5 6]
[8 4 7]]
>>> a.shape
(2, 3)
>>> b = a.reshape(3,2)
>>> print(b)
[[0 5]
[6 8]
[4 7]]
5. 切片
行切片和列切片
>>> print(a)
[[0 1 2]
[3 4 5]
[6 7 8]]
>>> a[0:2]
array([[0, 1, 2],
[3, 4, 5]])
>>> a[:, 0:2]
array([[0, 1],
[3, 4],
[6, 7]])
同样的,我们也可以在行和列上同时做切片
>>> b = a[1:3, 1:3]
>>> print(b)
[[4 5]
[7 8]]
这里有一个非常需要注意的问题是,numpy为了加快处理的速度,所以是引用优先的;所有他的切片内的元素,其实是原来矩阵内元素的引用,所以,我改变切片内的值,原来矩阵中的值也会随之而改变。
>>> b[0,0] = 10
>>> print(b)
[[10 5]
[ 7 8]]
>>> print(a)
[[ 0 1 2]
[ 3 10 5]
[ 6 7 8]]
在切片和原来的矩阵不需要一起改变的场合,我们必须将切片中的值拷贝出来,形成一个单独的矩阵:
>>> c = a[1:, 1:].copy()
>>> print(a)
[[ 0 1 2]
[ 3 10 5]
[ 6 7 8]]
>>> print(c)
[[10 5]
[ 7 8]]
>>> c[0][0] = 4
>>> print(c)
[[4 5]
[7 8]]
>>> print(a)
[[ 0 1 2]
[ 3 10 5]
[ 6 7 8]]
6. 矩阵的逻辑判断和逻辑运算
使用逻辑判断可以得到一个bool值的矩阵,矩阵中的值为原矩阵中所有符合该判断条件的情况:
>>> a = np.random.randn(3, 4)
>>> print(a)
[[-0.20597177 -2.96639491 0.45304223 0.07387349]
[ 0.95893609 1.31844843 -0.20011805 -0.08828083]
[-0.53680503 -0.40183503 1.32248556 -0.92480772]]
>>> b = a > 0
>>> print(b)
[[False False True True]
[ True True False False]
[False False True False]]
>>> print(a[a>2])
[]
>>> print(a[a>0])
[0.45304223 0.07387349 0.95893609 1.31844843 1.32248556]
我们可以通过where函数来对矩阵进行逻辑判断,比如,下面的例子完成了矩阵中的阈值化,将所有小于0的值都复制为了0:
>>> zero_mat = np.zeros((3, 4))
>>> b = np.where(a > 0, a, zero_mat)
>>> print(b)
[[0. 0. 0.45304223 0.07387349]
[0.95893609 1.31844843 0. 0. ]
[0. 0. 1.32248556 0. ]]
第一个参数表示的是一个表示条件的矩阵,我们也可以通过直接输入矩阵去达到这么个效果:
>>> bool_mat = a < 0
>>> print(bool_mat)
[[ True True False False]
[False False True True]
[ True True False True]]
>>> b = np.where(bool_mat, a, zero_mat)
>>> print(b)
[[-0.20597177 -2.96639491 0. 0. ]
[ 0. 0. -0.20011805 -0.08828083]
[-0.53680503 -0.40183503 0. -0.92480772]]
7. 矩阵的运算
逐个元素的加/减/乘/除/平方根;直接看例子吧:
加法:
>>> print(b)
[[8 7 6]
[5 4 3]
[2 1 0]]
>>> print(a)
[[0 1 2]
[3 4 5]
[6 7 8]]
>>> print(a+b)
[[8 8 8]
[8 8 8]
[8 8 8]]
>>> print(np.add(a, b))
[[8 8 8]
[8 8 8]
[8 8 8]]
减法:
>>> print(a-b)
[[-8 -6 -4]
[-2 0 2]
[ 4 6 8]]
>>> print(np.subtract(a, b))
[[-8 -6 -4]
[-2 0 2]
[ 4 6 8]]
乘法:
>>> print(a*b)
[[ 0 7 12]
[15 16 15]
[12 7 0]]
>>> print(np.multiply(a,b))
[[ 0 7 12]
[15 16 15]
[12 7 0]]
除法:
>>> print(a)
[[1 2 3]
[4 5 6]
[7 8 9]]
>>> print(b)
[[9 8 7]
[6 5 4]
[3 2 1]]
>>> print(a/b)
[[0.11111111 0.25 0.42857143]
[0.66666667 1. 1.5 ]
[2.33333333 4. 9. ]]
>>> print(np.divide(a, b))
[[0.11111111 0.25 0.42857143]
[0.66666667 1. 1.5 ]
[2.33333333 4. 9. ]]
平方跟:
>>> np.sqrt(a)
array([[1. , 1.41421356, 1.73205081],
[2. , 2.23606798, 2.44948974],
[2.64575131, 2.82842712, 3. ]])
求和:
>>> np.sum(a)
45
>>> np.sum(a, axis=0)
array([12, 15, 18])
>>> np.sum(a, axis=1)
array([ 6, 15, 24])
>>> print(a)
[[1 2 3]
[4 5 6]
[7 8 9]]
求平均值:
>>> np.mean(a)
5.0
>>> np.mean(a, axis=0)
array([4., 5., 6.])
>>> np.mean(a, axis=1)
array([2., 5., 8.])
求累加值:
>>> print(a)
[[1 2 3]
[4 5 6]
[7 8 9]]
>>> print(np.cumsum(a))
[ 1 3 6 10 15 21 28 36 45]
>>> print(np.cumsum(a, axis =0))
[[ 1 2 3]
[ 5 7 9]
[12 15 18]]
>>> print(np.cumsum(a, axis=1))
[[ 1 3 6]
[ 4 9 15]
[ 7 15 24]]
求累乘值:
>>> print(a)
[[1 2 3]
[4 5 6]
[7 8 9]]
>>> print(np.cumprod(a))
[ 1 2 6 24 120 720 5040 40320 362880]
>>> print(np.cumprod(a, axis=0))
[[ 1 2 3]
[ 4 10 18]
[ 28 80 162]]
>>> print(np.cumprod(a, axis=1))
[[ 1 2 6]
[ 4 20 120]
[ 7 56 504]]
矩阵的乘法:
>>> print(a)
[[1 2 3]
[4 5 6]
[7 8 9]]
>>> print(b)
[[9 8 7]
[6 5 4]
[3 2 1]]
>>> print(a.dot(b))
[[ 30 24 18]
[ 84 69 54]
[138 114 90]]
>>> print(np.dot(a, b))
[[ 30 24 18]
[ 84 69 54]
[138 114 90]]
矩阵的转置,其中swapaxes其实是维度的相互转换,在多维的矩阵里面,也可以用来交换其中的某些维度上的数据:
>>> print(a)
[[1 2 3]
[4 5 6]
[7 8 9]]
>>> print(a.T)
[[1 4 7]
[2 5 8]
[3 6 9]]
>>> print(np.transpose(a))
[[1 4 7]
[2 5 8]
[3 6 9]]
>>> print(np.swapaxes(a, 0, 1))
[[1 4 7]
[2 5 8]
[3 6 9]]
矩阵的排序
>>> a = np.random.randn(3, 3)*10
>>> b = a
>>> print(b)
[[-21.13178925 5.86602791 -7.48252941]
[ 2.08921814 -14.81116508 11.49010435]
[-14.30293195 6.04423917 -8.70793998]]
>>> b.sort(1)
>>> print(b)
[[-21.13178925 -7.48252941 5.86602791]
[-14.81116508 2.08921814 11.49010435]
[-14.30293195 -8.70793998 6.04423917]]
>>> b.sort(0)
>>> print(b)
[[-21.13178925 -8.70793998 5.86602791]
[-14.81116508 -7.48252941 6.04423917]
[-14.30293195 2.08921814 11.49010435]]
8 broadcasting:
在介绍了矩阵的操作之后,来简单介绍一下numpy的broadcasting操作。在矩阵逐元素加的操作中,我们加上一个全部为某个值的矩阵和加上一个数字是一样的结果,如下:
>>> a = np.arange(9).reshape(3, 3)
>>> b = np.full((3, 3),2)
>>> print(a)
[[0 1 2]
[3 4 5]
[6 7 8]]
>>> print(b)
[[2 2 2]
[2 2 2]
[2 2 2]]
>>> print(a+b)
[[ 2 3 4]
[ 5 6 7]
[ 8 9 10]]
>>> print(a+2)
[[ 2 3 4]
[ 5 6 7]
[ 8 9 10]]
为什么加上一个常数会是这样的一个结果呢?这都是numpy中boradcasing机制的结果。我们在执行操作a+2的时候,可以认为2被拉伸到了和a一样的shape,再进行的逐个元素累加。当然,在拉伸的过程中,并不是真正的将每个元素都复制了一次,在内存中使用的是同一个值,因此,a+2的操作比a+b的操作更加高效。
当两个数组在做算术运算的时候(注:矩阵的乘法等操作不符合broadcasting的条件);numpy从后往前逐个比较两个矩阵的shape,当满足(1)相等;(2)其中一个是1;时,满足broadcasting的条件。
我们来看看上面的例子:
A: 3 * 3
B: 1
R: 3 * 3
再看一个其他的例子:
A (2d array): 5 x 4
B (1d array): 4
Result (2d array): 5 x 4
9 其他操作
降维:
>>> print(b)
[[0 1 2]
[3 4 5]
[6 7 8]]
>>> b.ravel()
array([0, 1, 2, 3, 4, 5, 6, 7, 8])
>>> b.ravel('F') # 按列降维
array([0, 3, 6, 1, 4, 7, 2, 5, 8])
拼接:
>>> a = np.ones((3,3))
>>> b = np.zeros((3,3))
>>> np.concatenate((a, b), axis=0)
array([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
>>> np.concatenate((a,b), axis=1)
array([[1., 1., 1., 0., 0., 0.],
[1., 1., 1., 0., 0., 0.],
[1., 1., 1., 0., 0., 0.]])
除此之外,我们还可以使用hstack和vstack函数,从下面的例子中,我们可以看到,vstack是在垂直方向上拼接,因此vstack的作用和np.concatenate((a,b), axis=0)是一样的。而同样的道理,hstack和np.concatenate((a,b), axis=1)是一样的。
>>> np.vstack((a,b))
array([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
>>> np.hstack((a,b))
array([[1., 1., 1., 0., 0., 0.],
[1., 1., 1., 0., 0., 0.],
[1., 1., 1., 0., 0., 0.]])
切分:
>>> a = np.arange(12).reshape(4,3)
>>> print(a)
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
>>> fst, snd, thd = np.split(a, [1, 3], axis=0)
>>> print(fst)
[[0 1 2]]
>>> print(snd)
[[3 4 5]
[6 7 8]]
>>> print(thd)
[[ 9 10 11]]
10 矩阵的存取
>>> a = np.loadtxt("d:\\np_test.txt", delimiter=',')
>>> print(a)
[[ 1. 2. 3. 4.]
[ 5. 6. 7. 8.]
[10. 12. 1. 2.]]
其中文件中的数据为:
>>> a = np.arange(12).reshape(4,3)
>>> print(a)
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
>>> np.save("d:\\save_tst", a)
>>> b = np.load("d://save_tst.npy")
>>> print(b)
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
并且,我们可以看到在D盘中多了要给文件save_tst.npy,注意,他会自己加上后缀npy。
11 获取最大值或者最小值的索引
我们通过argmin和argmax两个函数来获取最大值或者最小值的索引,如下例所示:
>>> t = [1, 10, 3, 1, 10, 2, 7, 10, 9]
>>> a = np.array(t).reshape(3, 3)
>>> print(a)
[[ 1 10 3]
[ 1 10 2]
[ 7 10 9]]
>>> b = np.argmin(a, axis =0)
>>> c = np.argmax(a, axis = 1)
>>> print(b)
[0 0 1]
>>> d = np.argmin(a, axis =1)
>>> print(d)
[0 0 0]