【numpy】科学计算语法速查
🗓 2017年07月05日 📁 文章归类: 0x12_特征工程
版权声明:本文作者是郭飞。转载随意,标明原文链接即可。
原文链接:https://www.guofei.site/2017/07/05/numpy.html
生成
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’ 用边缘填充
- 还有很多填充模式,用的时候查
- ‘constant’ (default) 常量填充。默认填0,配合
where
x = np.array([1, 2, 0, 0, 3, 2, 0])
np.where(x != 0) # 返回符合条件的 index
np.where(x != 0, 9, 99) # 符合条件则填充为 9,否则填充为 99
统计方法
以下方法都可以
- 对数组操作。
- 加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
- dtype=np.int32
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 (爱因斯坦求和约定)
您的支持将鼓励我继续创作!