Numpy

7/6/2022 PythonDataScience

一个用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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

这里的维度非常智能,可以自行判断其向量间是否线性无关

注意通常的python环境并不包含这个库,要自己安装,Anacondabase环境中自带,需要在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)
1
2
3
4
5
  • 通过输出结果可知a实际上是一个类,叫作numpy.ndarray
  • dtype是矩阵中元素类型,默认为int32

创建二维矩阵

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

创建零阵

c = np.zeros((3,4))
print(c)
1
2
  • 调用zeros((row, colume))函数,入参为一个长度为2的元组,表示零阵的行列大小

创建全1阵(不是单位阵捏),同时规定元素类型

d = np.ones((3,4), dtype=np.int32)
print(d)
1
2

创建空阵,打印结果每个元素都是0,但实际上其实是接近于零的浮点数

e = np.empty((3,4))
print(e)
1
2

在范围内按照步长创建值等距的一维数组

f = np.arange(10, 21, 2)
print(f)
1
2
  • 参数分别为(start, end, step),和range函数一样含头不含尾

重塑矩阵,改变矩阵的行列数目

g = f.reshape((2,3))
print(g)
1
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)
1
2

同样通过linspace()得到的向量也可以重塑

i = h.reshape((3,4))
1

基本运算

一维乘法

import numpy as np
a = np.array([5,6,7,8])
b = np.arange(4)
print(a,b)

print(a*b, a.dot(b))
1
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)
1
2

三角函数,将作用于矩阵中每个元素

d = np.sin(a)
e = np.cos(b)
print(d, e)
1
2
3

数乘,加法运算

f = b*3
print(f)

g = b+3
print(g)
1
2
3
4
5
  • 这里的乘3和加3都将作用于矩阵中每个元素

布尔矩阵

i = b>2
print(i)

j = a==b
print(j)
1
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))
1
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)
1
2
3
4
  • np.random.random((i, j))将生成一个ij列的矩阵,其元素为(0,1)的随机浮点数
  • 使用np.sum()函数计算一个矩阵所有元素之和

矩阵最大/小元素

m2 = np.max(m)
m1 = np.min(m)
print("max: ", m2)
print("min: ", m1)
1
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))
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))
1
2
3
4
5
6
7

矩阵均值

print(np.mean(A))
print(np.average(A))
print(A.mean())
1
2
3

矩阵中位数(按照索引来排)

print(np.median(A))
1

排序,对每个向量进行从小到大的排序,返回一个排序好的矩阵

print(np.sort(A))
1

转置

print(np.transpose(A))
print(A.T)
1
2

规范化矩阵元素大小

print(np.clip(A,5,9))
1
  • 当元素小于5时,将变成5,将元素大于9,将变成9

索引和切片

对于一维矩阵(向量),直接通过索引取得的将是单个元素

B = np.array([1,2,3])
print(B[0]==1) # True
print(B[2]==3) # True
1
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)
1
2
3
4
5
6
7
8

切片,有点像切片字符串

print(B[1,1:3]) # [6,7]
1
  • 1行的第1-2元素组成的向量(这里的数字均为下标)

多维转一维,按照索引构成一个一维矩阵

C = B.flatten()
D = list(B.flat)
print(C)
print(D)
1
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)
1
2
3
4
5
6
  • 这里的A,B都是向量,而不是矩阵
  • [[1,2,3]][1,2,3]有质的区别

向量上下合并,要求元素个数一样

C = np.vstack((A,B))
print(C)
1
2

向量左右合并

D = np.hstack((A,B))
print(D)
1
2

将向量转为矩阵

A1 = A[np.newaxis, :]
A2 = A[:, np.newaxis]
print(A1)
print(A2)
1
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]]
1
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)
1
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)
1
2
3
4
5
6
7

不等量分割

A3= np.array_split(A,3,axis=1)
for item in A3:
    print(item)
1
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)
1
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
1
2
3

通过copy函数赋值将重新开辟空间

E = A.copy()
A[1] = 7
print(A)
print(E)
1
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))
1
2
3
4
5
6
7
8
9
10

上述代码都是能够正常运行的

怎么说,就是在做矩阵运算的时候,若两个矩阵不匹配,将对不匹配的部分自动进行广播,如

[1,2,3]+3=[1,2,3]+[3,3,3]=[4,5,6] [1,2,3]+3=[1,2,3]+[3,3,3]=[4,5,6]
又如

[1,2,34,5,67,8,9]+[0,1,2]=[1,2,34,5,67,8,9]+[0,1,20,1,20,1,2]=[1,3,54,6,87,9,11] \begin{bmatrix} 1,2,3\\ 4,5,6\\ 7,8,9 \end{bmatrix} + \begin{bmatrix} 0,1,2 \end{bmatrix} = \begin{bmatrix} 1,2,3\\ 4,5,6\\ 7,8,9 \end{bmatrix} + \begin{bmatrix} 0,1,2\\ 0,1,2\\ 0,1,2 \end{bmatrix} = \begin{bmatrix} 1,3,5\\ 4,6,8\\ 7,9,11 \end{bmatrix}

在做乘法的时候,不合规范的乘法numpy会想办法让他符合规范

[1,2,34,5,67,8,9][0,1,2][1,2,34,5,67,8,9][012] \begin{bmatrix} 1,2,3\\ 4,5,6\\ 7,8,9 \end{bmatrix} * \begin{bmatrix} 0,1,2 \end{bmatrix} \rightarrow \begin{bmatrix} 1,2,3\\ 4,5,6\\ 7,8,9 \end{bmatrix} * \begin{bmatrix} 0\\1\\2 \end{bmatrix}

常用函数

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),这里的arrweight都是向量且必须长度相等,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))
1
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
1
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]
1
2
3
4

结合上述两个函数

x = np.array([1, 2, 3, 3, 0, 1, 4])
print(np.argmax(np.bincount(x)))
1
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]
1
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. ]
1
2

当精度为负数时,如-1,表示精确到10位,-2表示精确到100位,满足四舍五入的规则

  • 注意是必须要超过"5",如5精确到10位将变成05.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))
1
2

结果为

[1,02,00,1] \begin{bmatrix} 1,0\\ 2,0\\ 0,1 \end{bmatrix}

Numpy 100

Last Updated: 7/16/2024, 4:06:40 AM
妖风过海
刘森