Numpy
一个用python实现的用于科学计算的扩展库
Numpy For Beginner
基本操作
first numpy program
将二维列表转为矩阵
import numpy as np
matrix = np.array([
[1,3,5],
[4,6,9],
[2,7,8]
])
print(matrix)
# 维度
print("dim of matrix: ", matrix.ndim)
# (行,列)
print('shape of matrix: ', matrix.shape)
# 元素个数
print('size of matrix: ', matrix.size)
2
3
4
5
6
7
8
9
10
11
12
13
14
这里的维度非常智能,可以自行判断其向量间是否线性无关
注意通常的python
环境并不包含这个库,要自己安装,Anaconda
的base
环境中自带,需要在VSCode
中手动选择默认python
环境:ctrl+shift+p
输入select Interpreter
切换环境
创建矩阵
创建一维矩阵
import numpy as np
a = np.array([1,2,3], dtype=np.int32)
print(a)
print(type(a))
print(a.dtype)
2
3
4
5
- 通过输出结果可知
a
实际上是一个类,叫作numpy.ndarray
dtype
是矩阵中元素类型,默认为int32
创建二维矩阵
b = np.array([[2,3,4],[3,4,5]])
print(b)
2
创建零阵
c = np.zeros((3,4))
print(c)
2
- 调用
zeros((row, colume))
函数,入参为一个长度为2的元组,表示零阵的行列大小
创建全1阵(不是单位阵捏),同时规定元素类型
d = np.ones((3,4), dtype=np.int32)
print(d)
2
创建空阵,打印结果每个元素都是0,但实际上其实是接近于零的浮点数
e = np.empty((3,4))
print(e)
2
在范围内按照步长创建值等距的一维数组
f = np.arange(10, 21, 2)
print(f)
2
- 参数分别为
(start, end, step)
,和range
函数一样含头不含尾
重塑矩阵,改变矩阵的行列数目
g = f.reshape((2,3))
print(g)
2
- 当然要总元素数相同才可以重塑,不同将报错
ValueError: cannot reshape array of size 6 into shape (2,4)
创建线段型数据,即将某一范围内数据分割称n
份,组成一维矩阵
这里的分割是均分的,含头也含尾,即start
将是向量第一个元素,end
将是向量最后一个元素,若想按1
的步长进行分割,则n
要等于end-start+1
(分得元素为间隔数+1)
h = np.linspace(0,11,12)
print(h)
2
同样通过linspace()
得到的向量也可以重塑
i = h.reshape((3,4))
基本运算
一维乘法
import numpy as np
a = np.array([5,6,7,8])
b = np.arange(4)
print(a,b)
print(a*b, a.dot(b))
2
3
4
5
6
a=[5,6,7,8], b=[0,1,2,3]
,a*b
是列向量乘行向量,结果仍为一个一维的含四个元素的向量,a.dot(b)
是维之和,即行向量乘以列向量,得到单个值
乘方,矩阵的幂运算
c = b**2
print(c)
2
三角函数,将作用于矩阵中每个元素
d = np.sin(a)
e = np.cos(b)
print(d, e)
2
3
数乘,加法运算
f = b*3
print(f)
g = b+3
print(g)
2
3
4
5
- 这里的乘3和加3都将作用于矩阵中每个元素
布尔矩阵
i = b>2
print(i)
j = a==b
print(j)
2
3
4
5
- 实际上就是将这个条件判断作用于每个元素上,若为真,该位置则为
True
,为假反之,这样构成的一个新的元素均为布尔值的矩阵
二维乘法,当然要保证二者能够相乘
k = np.array([1,1],[0,1])
l = np.arange(4).reshape((2,2))
print(k)
print(l)
print(k.dot(l))
print(l.dot(k))
print(np.dot(k,l))
print(np.dot(l,k))
2
3
4
5
6
7
8
9
- 由于这里是两个
2x2
的矩阵,左乘和右乘是有明显区别的,这里矩阵乘法的先后顺序也就表示了矩阵乘法的左右,如k.dot(l)/np.dot(k,l)
即为k
右乘l
,结果一样 - 多维矩阵乘法不能之久使用
*
号
矩阵元素求和
m = np.random.random((2,4))
print(m)
s = np.sum(m)
print("sum: ", s)
2
3
4
np.random.random((i, j))
将生成一个i
行j
列的矩阵,其元素为(0,1)
的随机浮点数- 使用
np.sum()
函数计算一个矩阵所有元素之和
矩阵最大/小元素
m2 = np.max(m)
m1 = np.min(m)
print("max: ", m2)
print("min: ", m1)
2
3
4
通过axis=1/0
参数可以控制求每行/列的和/最大值/最小值
axis=1
表示行axis=0
表示列
print("row sum: ", np.sum(m, axis=1))
print("colume min: ", np.min(m, axis=0))
print("row max: ", np.max(m, axis=1))
2
3
索引,aij
的索引按照从左到右,从上到下的顺序计数,从0
开始,如左上角元素索引为0
,右下角元素索引为元素总数-1
A = np.arange(2,14).reshape((3,4))
print(A)
# 最小元素索引
print(np.argmin(A))
# 最大元素索引
print(np.argmax(A))
2
3
4
5
6
7
矩阵均值
print(np.mean(A))
print(np.average(A))
print(A.mean())
2
3
矩阵中位数(按照索引来排)
print(np.median(A))
排序,对每个向量进行从小到大的排序,返回一个排序好的矩阵
print(np.sort(A))
转置
print(np.transpose(A))
print(A.T)
2
规范化矩阵元素大小
print(np.clip(A,5,9))
- 当元素小于
5
时,将变成5
,将元素大于9
,将变成9
索引和切片
对于一维矩阵(向量),直接通过索引取得的将是单个元素
B = np.array([1,2,3])
print(B[0]==1) # True
print(B[2]==3) # True
2
3
对于多维矩阵,其实就相当于多维数组取下标
B = np.arange(1,13).reshape((3,4))
print(B[0]) # [1,2,3,4]
print(B[0][0]) # 1
for row in B: # 一行一行打印
print(row)
for colume in B.T: # 一列一列打印
print(colume)
2
3
4
5
6
7
8
切片,有点像切片字符串
print(B[1,1:3]) # [6,7]
- 第
1
行的第1-2
元素组成的向量(这里的数字均为下标)
多维转一维,按照索引构成一个一维矩阵
C = B.flatten()
D = list(B.flat)
print(C)
print(D)
2
3
4
- 这里
B.flat
得到的是一个迭代器,为Object
,通过list
转为一维数组
矩阵合并
import numpy as np
A = np.array([4,5,6])
B = np.array([1,2,3])
print(A)
print(B)
2
3
4
5
6
- 这里的
A,B
都是向量,而不是矩阵 [[1,2,3]]
和[1,2,3]
有质的区别
向量上下合并,要求元素个数一样
C = np.vstack((A,B))
print(C)
2
向量左右合并
D = np.hstack((A,B))
print(D)
2
将向量转为矩阵
A1 = A[np.newaxis, :]
A2 = A[:, np.newaxis]
print(A1)
print(A2)
2
3
4
- 通过
A[np.newaxis, :]
将向量转为一维行矩阵 - 通过
A[:, np.newaxis]
将向量转为一维列矩阵
多个矩阵合并
A1 = A[np.newaxis, :] # [[4,5,6]]
A2 = A[:, np.newaxis] # [[4,5,6]]T
B1 = B[np.newaxis, :] # [[1,2,3]]
B2 = B[:, np.newaxis] # [[1,2,3]]T
E1 = np.hstack((A1,B1)) # 横向合并 [[4,5,6,1,2,3]]
E2 = np.vstack((A1,B1)) # 纵向合并 [[4,5,6],[1,2,3]]
E3 = np.vstack((A2,B2)) # 纵向合并 [[4,1],[5,2],[6,3]]
2
3
4
5
6
7
8
也可以通过np.concatenate((A,B), axis=1/0)
进行合并,当axis=1
横向合并,为0
纵向合并,合并顺序和入参顺序保持一致
矩阵分割
构造3行4列矩阵
import numpy as np
A = np.arange(12).reshape(3,4)
print(A)
2
3
4
等量分割,即均等分,分为纵向分割和横向分割
axis=1
纵向分割,第二个参数为分成的份数(axis=1
为横向合并)axis=0
横向分割,第二个参数为分成的份数(axis=0
为纵向合并)- 当无法等量分时将报错
- 分割的结果为一个矩阵迭代器,每个元素都是一个矩阵
A1 = np.split(A, 2, axis=1)
for item in A1:
print(item)
A2 = np.split(A, 3, axis=0)
for item in A2:
print(item)
2
3
4
5
6
7
不等量分割
A3= np.array_split(A,3,axis=1)
for item in A3:
print(item)
2
3
- 第一个元素为
3x2
矩阵,第二、三个元素为3x1
矩阵
Copy和=
使用等于号对矩阵进行赋值,如
import numpy as np
A = np.arange(4)
print(A)
B = A
C = A
D = A
A[0] = 11
print(A)
print(B)
print(C)
2
3
4
5
6
7
8
9
10
11
这里A[0]
改变后,矩阵B,C,D
的第一位元素均会改变,就像是A,B,C,D
是不同的指针,但指向同一块内存空间
同理改变B[1:3]=[22,33]
,所有的矩阵A,C,D
的第二、三个元素都会变成22,33
进行成员运算时,均会得到True
print(B is A) # True
print(C is A) # True
print(D is A) # True
2
3
通过copy
函数赋值将重新开辟空间
E = A.copy()
A[1] = 7
print(A)
print(E)
2
3
4
这时二者指向不同的内存空间,互不影响
广播机制
import numpy as np
A = np.array([[1,2,3],[4,5,6],[7,8,9]])
print(A)
print(A+3)
B = np.array([1,2,0])
print(B)
print(A+B)
print(A.dot(B))
print(B.dot(A))
2
3
4
5
6
7
8
9
10
上述代码都是能够正常运行的
怎么说,就是在做矩阵运算的时候,若两个矩阵不匹配,将对不匹配的部分自动进行广播,如
在做乘法的时候,不合规范的乘法numpy
会想办法让他符合规范
常用函数
np.bincount()
统计索引出现的次数,索引可以视作下标0,1,2...
如向量[0,0,1,1,2,2]
的bincount
为[2,2,2]
,因为0
出现两次,1
出现两次,2
出现两次,所以bincount[0]=2,bincount[1]=2,bincount[2]=2
对bincount()
进行加权,即bincount(arr, weights=weight)
,这里的arr
和weight
都是向量且必须长度相等,arr[i]
的权重即为weight[i]
,在没有权重的时候,每个arr[i]
的权重都为1
,在计算bincount[i]
的时候,i
每出现一次,bincount[i]
就+1
,当人为添加了权重,这时就不是加1
了,而是加上arr[i]
对应的权重weight[i]
如
import numpy as np
arr = np.array([0,0,1,1,2,2])
weight = np.array([0.1,0.3,0.3,0.5,0.6,0.2])
print(np.bincount(arr, weights=weight))
2
3
4
5
6
bincount[0] = weight[0]+weight[1] = 0.1+0.3 = 0.4
,为什么加这两个权重,因为arr[0] = arr[1] = 0
- 同理
bincount[1] = weight[2]+weight[3] = 0.3+0.5 = 0.8
bincount[2] = weight[4]+weight[5] = 0.6+0.2 = 0.8
np.argmax()
返回矩阵中最大元素的索引
x = [[1,3,3],
[7,5,2]]
print(np.argmax(x)) # 3,因为元素7的索引为3
2
3
可以规定按列或行进行操作
axis=0
按列操作axis=1
按行操作
x = [[1,3,3],
[7,5,2]]
print(np.argmax(x,axis=0)) # [1,1,0]
print(np.argmax(x,axis=1)) # [1,0]
2
3
4
结合上述两个函数
x = np.array([1, 2, 3, 3, 0, 1, 4])
print(np.argmax(np.bincount(x)))
2
结果为1
,首先bincount = [1,2,1,2,1]
,其最大值2
的索引为1
,故输出1
求取精度
np.around()
取精度函数,当精度为0
时即为取整,负数向下取整,正数向上取整
- 第一个参数为矩阵/向量
- 第二个参数为精度
np.around([-0.6,1.2798,2.357,9.67,13], decimals=0)
# [-1,2,3,10,13]
2
当精度为1
时,精确到小数点后一位,同样保持向下取整,正数向上取整
y = np.around([-1.2798,1.2798,2.357,9.67,13], decimals=1)
print(y) # [-1.3 1.3 2.4 9.7 13. ]
2
当精度为负数时,如-1
,表示精确到10
位,-2
表示精确到100
位,满足四舍五入的规则
- 注意是必须要超过
"5"
,如5
精确到10
位将变成0
,5.1
将变成10
,同理55
变成50
,而56
变成60
np.floor(arr)
表示取下限,-1.3 —> -2, 1.3 —> 1
np.ceil(arr)
表示取上限,-1.3 —> -1, 1.3 —> 2
np.where(x>0, x, 0)
,表示用0
填充负数,第一个入参是一个布尔值,若为真,则用第二个入参填充,若为假,则用第三个入参填充
x = np.array([[1, 0], [2, -2], [-2, 1]])
print(np.where(x>0, x, 0))
2
结果为