【numpy】科学计算语法速查

生成

lst = [[1.0, -2], [-3, 4]]
x = np.array(lst, dtype=float)
# dtype=float, int, np.complex128

np.array(lst, ndmin=3)  # shape = (1, 2, 2)
y = array(lst, ndmin=4)  # shape = (1, 1, 2, 2)

np.zeros(shape=(5, 2), dtype=int)

# 含头不含尾:
np.arange(start=0, stop=11, step=1)
# 含头含尾:
np.linspace(start=0, stop=5, num=9)

np.eye # 对角矩阵

np.random.rand(2, 2, 2) # 2x2x2 的随机矩阵
# 占用 bytes
z.size * z.itemsize

取数

  • 切片取数:共享内存(对于多维数组,如果每一维都用切片,也共享内存)
    a[3:5]  # 含头不含尾
    a[:-1]  # -1表示最后,仍然不含尾
    a[2, 3] = 7, 8  # 切片用来改array
    b = a[2, 3]  # a和b共享内存空间
    a[1:-1:2]  # 最后一个数是步长
    a[::2]  # 省略表示头部
    
  • 用list取数:不共享内存(对于多维数组,可以用切片+list混用方式取数,只要有list就不共享内存)
    a=np.arange(1,10,1)
    b=a[[1,2,3]] # 修改b的元素值,不影响a
    
  • array取数:不共享内存
    a=np.arange(1,10,1)
    b=a[np.array([1,4,1])]
    
  • 布尔取数:不共享内存
    a=np.arange(0,5,1)
    b=a[np.array([True,False,True,False,True])]
    

一个实际案例:

a=numpy.random.rand(10)
a[a>0.5]

摊平操作

index 相关


# 6x7x8 矩阵的第 100 个元素,其 index 是什么
np.unravel_index(indices=100, shape=(6, 7, 8)) # 返回 (1, 5, 4)

# 6x7x8 矩阵,其坐标 (1, 5, 4) 的元素,是第几个元素
np.ravel_multi_index(multi_index=(1, 5, 4), dims=(6, 7, 8)) # 返回 100


# 以上方法也可以输入多组值,同时计算和返回
# 例如:
x_arr, y_arr = np.unravel_index(indices=[1, 2, 3], shape=(3, 3))
# 返回 (array([0, 0, 1]), array([1, 2, 0]))

# (0, 0) 和 (1, 2) 对应第几个?
np.ravel_multi_index(multi_index=[(0, 1), (0, 2)], dims=(3, 3))
# 返回 array([0, 5])

# 摊平
x.flatten()

# 取摊平后的第 6 个元素
x.item(6)

习题:有一个5x5的零矩阵,使随机n个元素变成1

x = np.zeros((5, 5))
n = 3
idx = np.random.choice(a=range(x.size), size=n, replace=False)
idx2 = np.unravel_index(indices=idx, shape=x.shape)
x[idx2] = 1

方法

a.shape

  • 返回a的维度
    • 如果a是一维数组,输出为(4,)
    • 二维数组,输出为(2, 1)
    • 如果某一维不规则,那么不显示这一维(2,) a.shape返回array的维度
      a.shape
      
  • 可以对a.shape赋值,效果是改变维度
    a=numpy.array([[1,2,3],[4,5,6]])
    a.shape=3,2
    
  • 在赋值时,用-1表示自动计算这一维的长度
    a=numpy.array([[1,2,3],[4,5,6]])
    a.shape=3,-1
    

reshape

  • reshape与shape的区别是,reshape保持原数组维度不变
  • 相同点是,内存是共享的
a=numpy.array([[1,2,3],[4,5,6]])
b=a.reshape((3,2))

这里生成的a和b维度不同,但是共享内存

比较而言,用shape,直接改了原array:

a=numpy.array([[1,2,3],[4,5,6]])
b=a
b.shape=3,-1
b.shape=6  # 变成一维的

这里a,b的维度都改了

dtype

a.dtype#返回元素类型
a=numpy.array([1,2,3,4],dtype=numpy.float)#指定元素类型
a=numpy.array([1,2,3,4],dtype=numpy.complex)#指定元素类型

显示可用的dtype列表

set(numpy.typeDict.values())

np.pad:四周添加数字

np.pad(array, pad_width, mode='constant')

  • pad_width: ((before_1, after_1), ... (before_N, after_N)),例如 ((2, 3), (4, 5)) 表示第1纬度前填充2后填充3,第2纬度前填充4后填充5
  • mode
    • ‘constant’ (default) 常量填充。默认填0,配合 constant_values=((-10, 10), (-20, 20)) 指定填充什么数字。上面是第1个纬度前后填充-10和10,第二个纬度前后填充-20,20
    • ‘edge’ 用边缘填充
    • 还有很多填充模式,用的时候查

where

x = np.array([1, 2, 0, 0, 3, 2, 0])
np.where(x != 0) # 返回符合条件的 index
np.where(x != 0, 9, 99) # 符合条件则填充为 9,否则填充为 99

统计方法

以下方法都可以

  1. 对数组操作。
  2. 加nan表示跳过nan,例如 nanmean
方法 说明
sum  
mean  
std,var  
min,max  
argmin,argmax 最小值和最大值的索引
cumsum  
cumprod  
diff  
sort 排序

使用详解

# 对 ndarray 的操作
arr1 = np.random.rand(5, 3)
np.mean(arr1)
np.mean(arr1, axis=1, keepdims=True)  
# 1. 对第axis维度求平均
# 2. keepdims 默认为 False,表示把结果变成一维的

# 加nan表示跳过nan
np.nanmean(arr1)

其它统计学方法

# 协方差矩阵
np.corrcoef(arr1)

常用方法

np.ceil
np.floor
np.rint
np.isnan



np.unique # 去重并排序


np.unique(
    arr
    , return_index=True  # 额外返回一个array,记录去重后的元素来自 arr 的哪个位置
    , return_inverse=True  # 额外返回一个array,用它+返回值可以重新构建 arr
    , return_counts=True  # 额外返回一个array,记录元素个数
    , axis=0  # 按照axis去重;如果没有,去重粒度是元素,
)

集合

np.intersect1d([1, 2, 3], [4, 3, 5])  # 交集
np.union1d([1, 5, 4], [5, 3, 1])  # 并集

np.in1d(ar1=[1, 4, 4, 1, 2], ar2=[1, 2])  # ar1 中每个元素,是否是 ar2 中的元素。返回一个 np.array<bool> ,大小与 ar1 一致

逻辑运算

np.logical_not([True, True, False])  # 求否
np.logical_or(arr1, arr2)
np.logical_and(arr1, arr2)

# 更好记:
arr1 & arr2
arr1 | arr2
~arr1

np.all
np.any


np.isnan(np.array([1, np.nan]))

sort

import numpy as np
a=np.random.randn(10,3)
a.sort(axis=1) # 直接改变a
np.sort(a) # 不改变a,而是返回一个排序完毕的ndarray
  • axis=1,axis=1是对行降序,axis=0是对列降序
  • 只能降序排列,向生序 a[:,::-1]
  • kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}

np.argsort

np.meshgrid

X, Y = np.meshgrid(np.arange(3), np.arange(4))

矩阵操作

常用方法

a=np.random.rand(3,4)
np.fliplr(a) # 左右翻转
np.flipud(a) # 上下翻转
np.rot90(a,k=3) # 逆时针转动k次

np.eye(N=4,M=3,k=2) # 生成一个对角阵,N*M大小,k是向右上角偏置量
np.diag(a,k=1) # 取出对角元素,放到一维数组中,返回一个 1darray
np.diag([1,2,3],k=2) # 生成对角矩阵(一维数组转二维数组)
# np.diag 没有 keepdim 这类入参,可以用 np.diag(np.diag(a)) 来提取对角矩阵

np.triu(m=a,1) # 矩阵的上三角部分
np.tril(m=a,1) # 矩阵的下三角部分
np.tri(N=3,M=4,k=1) # 生成一个下三角矩阵,元素是0和1

np.vander(x=[1,2,3],N=5) # 生成一个 Vandermonde matrix,每一行是x中的元素,N列

(a>0.5).any(axis=0) # 每列是否有True
(a>0.5).any(axis=1) # 每行是否有True


np.tile(np.array([[1, 2], [3, 4]]), (3, 2))
# 把一个矩阵复制 3*2 次,也就是行变成 3 倍,列变成 2 倍

矩阵拆拼

拼装

import numpy as np
a=np.random.rand(3,3)
b=np.random.rand(3,3)
np.concatenate([a,b],axis=0) # axis=0是竖着拼起来,axis=1是横着拼起来

scipy距离矩阵

https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.cdist.html#scipy.spatial.distance.cdist

import numpy as np
from scipy import spatial

num_points = 8
points = range(num_points) # generate index of points
points_coordinate = np.random.rand(num_points, 2) # generate coordinate of points
distance_matrix = spatial.distance.cdist(points_coordinate, points_coordinate, metric='euclidean')

存文件和读文件

文本类型的存和读

# 以下两个方法可以读 csv/txt 等格式
arr1 = np.genfromtxt('file1.csv', delimiter=',')
# 如果某个数据是字符串,相应位置会读取为nan
arr2 = np.loadtxt('file1.csv', delimiter=',', skiprows=1)
# 多了一个 skiprows 方法,一般用来跳过第一行(字段名)
# 如果某个数据是字符串,会报错

二进制形式存和读(*.npy 格式)

# 存
np.save('file4.npy', arr1)

# 读
np.load('file4.npy')

多个变量批量存/读(*.npz 格式)

# 存
# 区别是:是否压缩
np.savez('file2.npz', arr1=arr1, arr2=arr2)
np.savez_compressed('file2_compressed', arr1=arr1, arr2=arr2)
# 如果不指定变量名,变量值默认为 arr_1, arr_2 等




# 读
npzfile = np.load('file2.npz')

npzfile.files  # 一个列表,都有哪些变量名
npzfile['arr2']  # arr2 这个变量的值
npzfile.get(key='arr3', default=1)  # 同上,但是对于不存在的变量,返回一个默认值

npzfile.items()  # 一个 iterator,key-value 结构
npzfile.values()  # 一个 iterator,存放value

scipy 也可以读写文件(据说与Matlab通用)

scipy.io.savemat('file2_scipy', {'arr1': arr1, 'arr2': arr2})

data_scipy = scipy.io.loadmat('file2_scipy')

矩阵运算

函数 说明
diag (输入是2维时)对角线(第k个)转1维阵
diag (输入是1维时)一维阵转对角阵
dot 矩阵乘法
matrix_power(arr1, n) n次方,n是正/负/零整数
trace 对角线元素和
det 对应行列式值
eig 特征值和特征向量
inv 矩阵的逆
pinv 矩阵的Moore-Pwnrose伪逆
qr QR分解
svd SVD分解

import numpy as np

arr1 = np.random.uniform(0, 1, size=(3, 3))
arr2 = np.random.uniform(0, 1, size=(10, 1))

# 矩阵对应的行列式的值
A = np.linalg.det(arr1)

# 矩阵的转置
arr1.T

# 矩阵的逆
np.linalg.inv(arr1)

# 矩阵乘法
np.dot(arr1, arr2)
# 注意,这里的a,b必须是多维的,否则返回的是內积(对应项相乘)  
# python 3.5 以上也可以这样写:
arr1 @ arr2


# 矩阵的点积
a * b

# 矩阵的次方
np.linalg.matrix_power(arr1, n=3)
# n是正/负/零整数

# 矩阵的特征值特征向量
eigenvalues, eigenvectors = np.linalg.eig(arr1)
np.linalg.eig(A)  # 输入任意方阵,返回特征值+特征向量
np.linalg.eigvals(A)  # 输入任意矩阵,返回特征值
np.linalg.eigh(A)  # 输入:实对称或 Hermitian 方阵。返回特征值+特征向量,速度快,精度高
np.linalg.eigvalsh(A)  # 输入:实对称或 Hermitian 方阵。返回特征值,不计算特征向量,速度更快。不能用于非对称矩阵
scipy.linalg.eigh
scipy.linalg.eigvals
scipy.linalg.eigvalsh
scipy.linalg.eig_banded
scipy.linalg.eigh_tridiagonal
scipy.linalg.eigvals_banded
scipy.linalg.eigvalsh_tridiagonal

# 矩阵的秩
np.linalg.matrix_rank(a)

ufunc

ufunc是对ndarray执行运算的函数,用矢量化运算的方法极大的提高运算效率。

内置ufunc-1个输入值

函数 说明
abs 绝对值
sqrt 比a**0.5快
exp  
log,log10,log2  
sign  
ceil 向上取整
floor 向下取整
rint 四舍五入
isnan  
isfinite  
isinf  
sin,sinh,cos,cosh,tan,tanh  
arcsin,arccos,arctan,arcsinh,arccosh,arctanh  

内置ufunc-2个输入值

符号运算

a+b
a-b
a*b
a/b
a//b #商
a%b  #余数
#1. a,b是同样shape的ndarray
#2. b可以是数字
#3. b可以是1个元素的ndarray,如np.array([2])

b=a.T#转置
np.linalg.inv(a)#取逆

布尔运算

  • 生成bool
    x==y
    x!=y
    x<y
    x<=y
    x>y
    x>=y
    
  • bool运算:
    & #与
    ~ #非
    | #或
    ^ #异或
    

注意:

  • 实际上&~|^是按位运算符,因为与array.dtype=bool的情况下,与逻辑运算效果完全相同,所以可以这么用
  • and 和 or 等逻辑运算符不能直接对array使用,因为他们只能用于True/False
  • 非bool方式是取反,运算规则与C语言完全相同(有些编程技巧)
    • dtype=np.int32 ~0=-1
    • dtype=np.int8 ~0=255

np.any和np.all

  • np.any(a==b) and np.all(a>b)

其它运算符

函数 说明
maximum a,b对应每项的最大值
minimum a,b对应每项最小值

自己定义 ufunc

ufunc函数可以矢量化运算,提高运算效率,增加代码可读性

准备函数和数据:

import numpy as np


def func(x, a=1, b=0):
    return int(x) + int(a) - int(b)


ufunc = np.frompyfunc(func, nin=3, nout=1)
# nin 和 nout 是 ufunc 输入值的数量 和 输出值的数量 
# 如果 nin 设定为2,那么x和a是矢量,b就用默认值
ufunc(np.linspace(1, 5, 10), np.array([[3], [2]]), 2)

输出有多个,一样的

import numpy as np
# 构建函数
def oct_fun(x, a=1, b=0):
    return int(x) + int(a) - int(b), x + a + b


oct_ufun = np.frompyfunc(oct_fun, 3, 2)
oct_ufun(np.linspace(1, 5, 10), np.array([[3], [2]]), 2)

(测试发现,并不是并行运行的)

广播计算

def func1(x,y,c=0):
    return (x-1)**2+(y-1)**2+c
import numpy as np
func2=np.frompyfunc(func1,2,1)
x=np.linspace(0,2,5)
y=np.linspace(0,2,10).reshape(10,-1)
func1(x,y)

意思是,当shape不一致的array进行ufunc运算时,自动用repeat补齐

reduce()

只对两个输入、一个输出的ufunc对象有效

np.vectorize

前面的frompyfunc构建的函数,特点是广播计算,每次输入的是 array 中的一个元素。

import numpy as np
def myfunc(a, b):
    "Return a-b if a>b, otherwise return a+b"

    if a > b:
        return a - b
    else:
        return a + b


vfunc = np.vectorize(myfunc)

# 入参可以是list,数字,不同shape的array,规则与广播计算完全一样
vfunc([1, 2, 3, 4], 2)
vfunc([1, 2, 3, 4], [1, 2, 3, 4])

参数

excluded 可以让参数不矢量化,而是直接进入函数

def mypolyval(p, x):
    return sum(p) + x


vpolyval = np.vectorize(mypolyval, excluded=['p'])
vpolyval(p=[1, 2, 3], x=[0, 1])


# 也可以用这个命令,达成同样的效果
vpolyval.excluded.add(0)

其它

np.einsum (爱因斯坦求和约定)



您的支持将鼓励我继续创作!