numpy
一、Numpy概述
NumPy 是 Numerical Python 的简称,是高性能计算和数据分析的基础包。包含了多维数组以及多维数组的操作。
Numeric,即 NumPy 的前身,是由 Jim Hugunin 开发的。Jim也开发了另一个包 Numarray,它拥有一些额外的功能。
2005 年,Travis Oliphant 通过将 Numarray 的功能集成到 Numeric 包中来创建 NumPy 包。
1.1 Numpy简介
Numpy相比于 Python 内建的库和数据类型有以下特性:
- 强大、灵活的多维数组对象及丰富的操作
- C 实现,执行效率高
- 线性代数、傅里叶变换、丰富的随机数功能
- 复杂的(广播)功能
NumPy 通常与 SciPy (Scientific Python) 和 Matplotlib(绘图库)一起使用。这种组合广泛用于替代 MatLab,是一个流行的技术计算平台。Python + Numpy 作为 MatLab 的替代方案,如今被视为一种更加现代和完整的编程语言。
1.2 Numpy的安装
方法一:
标准的 Python 发行版不会与 NumPy 模块捆绑在一起。一个轻量级的替代方法是使用流行的Python 包安装程序 pip 来安装 NumPy。
在 CMD 或命令行中执行: pip install numpy
方法二: (推荐)
但是实际在 Windows 系统中的安装,多数时候会出现各类需要编译或缺乏相关依赖的问题,由于在 Python 的编程基础部分已经提过,建议大家使用 Anaconda 的 Python 发行版,这个发行版已经提前为我们安装了各类的科学计算需要的第三方包。我们直接使用就可以了。
以下所有都是基于Anaconda
二、 Numpy-Ndarray对象
Numpy 的核心是 ndarray 对象,这个对象封装了同质数据类型的n维数组。(数组,即为有序的元素序列)
ndarray 是 n-dimension-array 的简写。
Numpy 约定俗成的导入方式如下:
import numpy as np
#全部行都能输出 from IPython.core.interactiveshell import InteractiveShell InteractiveShell.ast_node_interactivity = "all"
2.1 创建Ndarray
基本的 ndarray 是使用 NumPy 中的数组函数创建的,如下所示:
array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0)
2.1.1 np.array 可以把 list,tuple,array 或者其他的序列模式的数据转创建为新的 ndarray
#创建一维数组 arr = np.array([3, 5, 0.7, -4, 6.2, 0]) arr #array([ 3. , 5. , 0.7, -4. , 6.2, 0. ])
#创建二维数组 arr2 = np.array([[5,6,7,8,9],[4,3,2,1,0]]) arr2 #array([[5, 6, 7, 8, 9], # [4, 3, 2, 1, 0]])
arr3 = np.array([1,2,3,4,5], ndmin=2) #ndmin是指明数组维度 arr3 #array([[1, 2, 3, 4, 5]])
2.2 numpy的ndarray 与 python原生array有什么区别
NumPy 数组在创建时有固定的大小,不同于Python列表(可以动态增长)。更改ndarray的大小将创建一个新的数组并删除原始数据。
NumPy 数组中的元素都需要具有相同的数据类型,因此在存储器中将具有相同的大小。数组的元素如果也是数组(可以是 Python 的原生 array,也可以是 ndarray)的情况下,则构成了多维数组。
2.2.1 Numpy 的矢量化(向量化)功能
如果想要将一个2-D数组 a 的每个元素与长度相同的另外一个数组 b 中相应位置的元素相乘
使用 Python 原生的数组实现如下:
a = [[1, 2, 3], [5, 7, 8], [4, 5, 6]] b = [[6, 2, 1], [2, 3, 1], [4, 5, 6]] a b # [[1, 2, 3], [5, 7, 8], [4, 5, 6]] # [[6, 2, 1], [2, 3, 1], [4, 5, 6]] ## c=a*b #这样写可以么? 肯定不行,只能循环遍历 #写一个代码实现对应元素相乘 c = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] for i in range(3): for j in range(3): c[i][j] = a[i][j]*b[i][j] c #[[6, 4, 3], [10, 21, 8], [16, 25, 36]]
使用numpy实现a与b的对应元素相乘
a1 = np.array(a) b1 = np.array(b) a b # array([[1, 2, 3], # [5, 7, 8], # [4, 5, 6]]) # # array([[6, 2, 1], # [2, 3, 1], # [4, 5, 6]]) c1=a1*b1 c1 # array([[ 6, 4, 3], # [10, 21, 8], # [16, 25, 36]]) #其余初等运算均可,这里不再一一举例,下面这些运算都是可以的 # a1 # a1 + 5 # a1 * 3 # a1 ** 2
矢量化代码有很多优点,其中包括:
- 矢量化代码更简洁易读
- 更少的代码行通常意味着更少的错误
- 执行效率高,运行速度快
2.3 数据类型 (dtype)
Numpy 中的数组比 Python 原生中的数组(只支持整数类型与浮点类型)强大的一点就是它支持更多的数据类型。
但对于我们非开发者而言,只需要知道常用的几个类型就够用了。需要注意的是,在 Numpy 当中的数据都是有位数限制的,包括整数。当数据过长时就有可能出现数据截断或者数据溢出。
2.3.1 基本数据类型
Numpy 常见的基本数据类型如下:
数据类型 | 描述 |
---|---|
bool_ | 布尔(True或False),存储为一个字节 |
int_ | 默认整数类型(通常为int64或int32) |
intc | 与C int(通常为int32或int64)相同 |
intp | 用于索引的整数(与C ssize_t相同;通常为int32或int64) |
int8 | 字节(-128到127) |
int16 | 整数(-32768到32767) |
int32 | 整数(-2147483648至2147483647) |
int64 | 整数(-9223372036854775808至9223372036854775807) |
uint8 | 无符号整数(0到255) |
uint16 | 无符号整数(0到65535) |
uint32 | 无符号整数(0至4294967295) |
uint64 | 无符号整数(0至18446744073709551615) |
float_ | float64的简写。 |
float16 | 半精度浮点:符号位,5位指数,10位尾数 |
float32 | 单精度浮点:符号位,8位指数,23位尾数 |
float64 | 双精度浮点:符号位,11位指数,52位尾数 |
complex_ | complex128的简写。 |
complex64 | 复数,由两个32位浮点(实数和虚数分量) |
complex128 | 复数,由两个64位浮点(实数和虚数分量) |
不同于 Python 列表,NumPy 要求数组必须包含同一类型的数据
a = np.array([3.14, 4, 2, 3]) a #array([3.14, 4. , 2. , 3. ]) a.dtype #dtype('float64') b = np.array([3.14, 4, 2, 4], dtype='intc') b #array([3, 4, 2, 4], dtype=int32) b.dtype #dtype('int32')
关于数据溢出的问题,上面的数据类型如果不满足所需的内存要求,怎会返回一些无用数据,具体不做讨论
2.3.2 类型转换——.astype()方法(首选)
a= np.array([3.14, 4, 2, 3]) a #array([3.14, 4. , 2. , 3. ]) a.astype(np.bool) #array([ True, True, True, True]) a.astype(np.int32) #array([3, 4, 2, 3]) a.astype('str') #array(['3.14', '4.0', '2.0', '3.0'], dtype='<U32')
2.3.3 常用的数组
(1)全0数组——np.zeros()
np.zeros(5) #默认是float型 #array([0., 0., 0., 0., 0.]) np.zeros((3, 3), dtype="int") #array([[0, 0, 0], # [0, 0, 0], # [0, 0, 0]]) np.zeros((3,2,4), dtype=np.float) # array([[[0., 0., 0., 0.], # [0., 0., 0., 0.]], # # [[0., 0., 0., 0.], # [0., 0., 0., 0.]], # # [[0., 0., 0., 0.], # [0., 0., 0., 0.]]])
(2)全1数组——np.ones()
np.ones(3) #默认float型 #array([1., 1., 1.]) #与np.zeros雷同
(3)全为相同值的数组——np.full()
np.full((2,3),5) # array([[5, 5, 5], # [5, 5, 5]]) np.full((2,3),[[1,2,3],[2,3,4]])#前面的(2,3)是指生成两行三列 # array([[1, 2, 3], # [2, 3, 4]])
(4)单位矩阵——np.eye()
np.eye(5,dtype='int') #默认float型 # array([[1, 0, 0, 0, 0], # [0, 1, 0, 0, 0], # [0, 0, 1, 0, 0], # [0, 0, 0, 1, 0], # [0, 0, 0, 0, 1]]) np.eye(3,5) # array([[1., 0., 0., 0., 0.], # [0., 1., 0., 0., 0.], # [0., 0., 1., 0., 0.]])
(5)按照某一数组的形状生成ndarray——np.ones_like np.zeros_like np.full_like
a = [[2,1,3],[4,3,2]] np.ones_like(a) np.zeros_like(a) np.full_like(a,3) # array([[1, 1, 1], # [1, 1, 1]]) # # array([[0, 0, 0], # [0, 0, 0]]) # # array([[3, 3, 3], # [3, 3, 3]])
(6)创建一个初始化的数组——np.empty()
np.empty(6)#为什么这里会有数字显示呢? #array([ 3. , 5. , 0.7, -4. , 6.2, 0. ]) #初始化的数据无意义 np.empty([5]) #array([3. , 5. , 0.7, 4. , 6.2]) a = np.empty([2,3]) a # array([[ 3. , 5. , 0.7], # [-4. , 6.2, 0. ]])
(7)创建对角矩阵——np.diag()
np.diag([1,2,3,4,5]) #对角Diagonal # array([[1, 0, 0, 0, 0], # [0, 2, 0, 0, 0], # [0, 0, 3, 0, 0], # [0, 0, 0, 4, 0], # [0, 0, 0, 0, 5]]) np.diag([1,2,3,'a'],2) #最后一个参数表示偏移量,正数向右上角偏移,负数向最下角偏移 # array([['', '', '1', '', '', ''], # ['', '', '', '2', '', ''], # ['', '', '', '', '3', ''], # ['', '', '', '', '', 'a'], # ['', '', '', '', '', ''], # ['', '', '', '', '', '']], dtype='<U11') np.diag([1,2,3,'a'],-2) # array([['', '', '', '', '', ''], # ['', '', '', '', '', ''], # ['1', '', '', '', '', ''], # ['', '2', '', '', '', ''], # ['', '', '3', '', '', ''], # ['', '', '', 'a', '', '']], dtype='<U11') np.diag(np.array([1, 2, 3, 4])) # array([[1, 0, 0, 0], # [0, 2, 0, 0], # [0, 0, 3, 0], # [0, 0, 0, 4]]) #显然传入列表或者ndarray对象都可以
(8)设置空值——np.nan
np.nan #nan
(9)随机数组——np.random
np.random.randint(1, 10, (3, 6))#生成一个整数的3行6列的数组,范围[1,10) # array([[4, 5, 6, 4, 2, 6], # [6, 1, 2, 1, 1, 9], # [2, 5, 8, 4, 5, 8]]) np.random.randn(4, 2) #np.random.standard_normal的简写形式 # array([[-0.72149333, 0.16869444], # [ 0.18478612, -0.41606474], # [-0.25209803, -0.23236144], # [-0.04885846, -0.36685169]]) # 里面的数值满足标准正态分布,等价于 np.random.standard_normal((4,2)) np.random.normal(4, 2, (5, 3)) #均值, 标准差, 形状 # array([[ 5.05443727, 6.20571937, 4.34760661], # [-2.23781087, 3.82506235, 2.42951026], # [ 7.18431897, 8.53642108, 2.27927855], # [ 3.85618724, 5.23093731, 4.40823762], # [ 2.71784975, 8.04125715, 6.94961183]]) # 设置随机数种子, 拆开发现不好使, 必须放在一起才好使 np.random.seed(200) c = np.random.randn(2, 3) c # array([[-1.45094825, 1.91095313, 0.71187915], # [-0.24773829, 0.36146623, -0.03294967]]) #它的功能相当于只随机产生一次随机数,以后调用都是第一次执行的结果
(10)创建一个线性序列的数组——np.arange
np.arange(0, 16, 2) np.arange(16) np.arange(0, 16, 4) # array([ 0, 2, 4, 6, 8, 10, 12, 14]) # # array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]) # # array([ 0, 4, 8, 12]) #前两个是范围,后一个是步长 np.linspace(1, 101, 5, dtype=int) #起始值,结束值,样本数 #array([ 1, 26, 51, 76, 101]) np.linspace(1, 101, 5, endpoint=False) #array([ 1., 21., 41., 61., 81.]) a = np.arange(30).reshape(6,5) a # array([[ 0, 1, 2, 3, 4], # [ 5, 6, 7, 8, 9], # [10, 11, 12, 13, 14], # [15, 16, 17, 18, 19], # [20, 21, 22, 23, 24], # [25, 26, 27, 28, 29]])
2.3.4 数组属性
- ndarray.shape 返回一个包含数组维度的元祖
- ndarray.dtype 返回数组元素的类型
- ndarray.ndim 返回数组的维数
- ndarray.itemsize 返回数组中每个元素的字节单位长度
#为了确保大家都能生成一样的数组, 我们先设置随机数种子 np.random.seed(123) x1 = np.random.randint(10, size=6) # 一维数组 x2 = np.random.randint(10, size=(3, 4)) # 二维数组 x3 = np.random.randint(10, size=(3, 4, 5)) # 三维数组 x1 x2 x3 # array([2, 2, 6, 1, 3, 9]) # # array([[6, 1, 0, 1], # [9, 0, 0, 9], # [3, 4, 0, 0]]) # # array([[[4, 1, 7, 3, 2], # [4, 7, 2, 4, 8], # [0, 7, 9, 3, 4], # [6, 1, 5, 6, 2]], # # [[1, 8, 3, 5, 0], # [2, 6, 2, 4, 4], # [6, 3, 0, 6, 4], # [7, 6, 7, 1, 5]], # # [[7, 9, 2, 4, 8], # [1, 2, 1, 1, 3], # [5, 9, 0, 8, 1], # [6, 3, 3, 5, 9]]])
(1)查看数据的形状——np.shape
#查看数据的形状 x1.shape x2.shape x3.shape # (6,) # # (3, 4) # # (3, 4, 5) #形状以元祖形式返回
(2)查看维度——np.ndim
#查看维度 x1.ndim x2.ndim x3.ndim # 1 # # 2 # # 3
(3)统计数组中所有的元素个数——np.size
#查看元素个数 x1.size x2.size x3.size # 6 # # 12 # # 60
(4)查看数组中元素类型——np.dtype
#查看数组中元素类型 x1.dtype x2.dtype x3.dtype # dtype('int32') # # dtype('int32') # # dtype('int32')
(5)查看数组中每个元素的字节单位长度——np.itemsize
#查看数组中每个元素的字节单位长度 x1.itemsize x2.itemsize x3.itemsize # 4 # # 4 # # 4
# 数组的 dtype 为 int8(一个字节) x = np.array([1,2,3,4,5], dtype = np.int8) x.itemsize #1 x = np.array([1,2,3,4,5], dtype = np.float64) x.itemsize #8
2.3.5 数组的维度变换
- ndarray.reshape 返回调整shape后的数组(不改变原数组)
- ndarray.resize 返回调整shape后的数组(改变原数组)
- ndarray.swapaxes 返回调换两个维度后的数组
- ndarray.flatten 对数组进行降维,返回折叠后的一维数组
(1)改变数组形状,返回新的ndarray对象,即不改变原数组——ndarray.reshape
m = np.random.randint(1, 100,(2, 3, 4)) m # array([[[99, 4, 12, 4], # [95, 7, 10, 88], # [15, 84, 71, 13]], # # [[55, 28, 39, 18], # [62, 75, 66, 48], # [17, 6, 87, 47]]] m.reshape(6,4) #不改变原数组 # array([[99, 4, 12, 4], # [95, 7, 10, 88], # [15, 84, 71, 13], # [55, 28, 39, 18], # [62, 75, 66, 48], # [17, 6, 87, 47]]) #三维变成了两维,但原数组不发生改变,返回的是新的ndarray对象 m # array([[[99, 4, 12, 4], # [95, 7, 10, 88], # [15, 84, 71, 13]], # # [[55, 28, 39, 18], # [62, 75, 66, 48], # [17, 6, 87, 47]]]
(2)改变数组形状,但改变了原数组——ndarray.resize
m # array([[[99, 4, 12, 4], # [95, 7, 10, 88], # [15, 84, 71, 13]], # # [[55, 28, 39, 18], # [62, 75, 66, 48], # [17, 6, 87, 47]]] m.resize(6,4) #改变原数组 m # array([[99, 4, 12, 4], # [95, 7, 10, 88], # [15, 84, 71, 13], # [55, 28, 39, 18], # [62, 75, 66, 48], # [17, 6, 87, 47]])
(3)将二维数组的两个维度调换,但不改变了原数组——ndarray.swapaxes(1,0)
m # array([[99, 4, 12, 4], # [95, 7, 10, 88], # [15, 84, 71, 13], # [55, 28, 39, 18], # [62, 75, 66, 48], # [17, 6, 87, 47]]) n = m.swapaxes(1,0) #将两个维度调换,不改变原数组 n # array([[99, 95, 15, 55, 62, 17], # [ 4, 7, 84, 28, 75, 6], # [12, 10, 71, 39, 66, 87], # [ 4, 88, 13, 18, 48, 47]])
(4)全部转为一行m.reshape(1,-1)或者m.flatten(),或者一列m.reshape(-1,1)
m # array([[99, 4, 12, 4], # [95, 7, 10, 88], # [15, 84, 71, 13], # [55, 28, 39, 18], # [62, 75, 66, 48], # [17, 6, 87, 47]]) m.reshape(1,-1) # array([[99, 4, 12, 4, 95, 7, 10, 88, 15, 84, 71, 13, 55, 28, 39, 18, # 62, 75, 66, 48, 17, 6, 87, 47]]) m.reshape(-1,1) # array([[99], # [ 4], # [12], # [ 4], # [95], # [ 7], # [10], # [88], # [15], # [84], # [71], # [13], # [55], # [28], # [39], # [18], # [62], # [75], # [66], # [48], # [17], # [ 6], # [87], # [47]]) m.flatten() #与.reshape(1,-1)作用相同 # array([99, 4, 12, 4, 95, 7, 10, 88, 15, 84, 71, 13, 55, 28, 39, 18, 62, # 75, 66, 48, 17, 6, 87, 47])
2.3.6 数组的类型变换
ndarray.astype 更改数组的类型
ndarray..tolist 将数组变为列表
(1)更改数组中元素的类型——ndarray.astype
m # array([[99, 4, 12, 4], # [95, 7, 10, 88], # [15, 84, 71, 13], # [55, 28, 39, 18], # [62, 75, 66, 48], # [17, 6, 87, 47]]) p = m.astype(np.float32) #不改变原数组 p # array([[99., 4., 12., 4.], # [95., 7., 10., 88.], # [15., 84., 71., 13.], # [55., 28., 39., 18.], # [62., 75., 66., 48.], # [17., 6., 87., 47.]], dtype=float32) m.dtype p.dtype # dtype('int32') # # dtype('float32')
(2)将数组变为列表——ndarray.tolist
m # array([[99, 4, 12, 4], # [95, 7, 10, 88], # [15, 84, 71, 13], # [55, 28, 39, 18], # [62, 75, 66, 48], # [17, 6, 87, 47]]) q = m.tolist() #不改变原数组 q # [[99, 4, 12, 4], # [95, 7, 10, 88], # [15, 84, 71, 13], # [55, 28, 39, 18], # [62, 75, 66, 48], # [17, 6, 87, 47]] type(m) type(q) # numpy.ndarray # # list
三、 NumPy - 切片和索引
ndarray 对象的内容可以通过索引或切片来访问和修改,就像 Python 的内置容器对象一样。
ndarray 对象中的元素遵循基于零的索引。有三种可用的索引方法类型:字段访问,基本切片和高级索引。
基本切片是 Python 中基本切片概念到 n 维的扩展。通过将 start,stop 和 step 参数提供给内置的 slice 函数来构造一个 Python slice 对象。 此 slice 对象被传递给数组来提取数组的一部分。
3.1 基本索引与切片——规则 [start : stop : step]
arr = np.arange(10) arr #array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) arr[3] #找到索引为3的元素 #3 arr[:2] #截取前两个元素,返回的依然是ndarray结构 #array([0, 1]) arr[2:8:2]#从索引2开始,一直到索引8,但娶不到索引8,步长为2 #array([2, 4, 6]) #这里需要注意的是:ndarray 的索引方式和 Python 内置的 list 有所不同,核心在于 #ndarray 的索引获取的是一个视图而非复制 arr[4:7] = 888 arr #array([ 0, 1, 2, 3, 888, 888, 888, 7, 8, 9]) arr_ps = arr[4:8] arr_ps #array([888, 888, 888, 7]) arr_ps[1:3] = 555 print(arr_ps) print(arr) # [888 555 555 7] # [ 0 1 2 3 888 555 555 7 8 9] #如果需要得到一个复制,需要显式的制定获取一个副本: arr_cp = arr[4:8].copy() arr_cp[:] = 77 print(arr_cp) print(arr) # [77 77 77 77] 浅拷贝,没有改变原来的元素,说明是新开辟了内存空间来储存 # [ 0 1 2 3 888 555 555 7 8 9]
3.2 多维数组的基本索引切片
arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]]) arr2d # array([[1, 2, 3], # [4, 5, 6], # [7, 8, 9]]) arr2d[1] #array([4, 5, 6]) arr2d[1:] # array([[4, 5, 6], # [7, 8, 9]]) arr2d[0][2] #3 arr2d[0,2] #可以用列表的序列来索引多维数组中的元素 #3 #切片还可以包括省略号 ... ,来使选择元组的长度与数组的维度相同。如果在行位置使用##省略 号,它将返回包含行中元素的 ndarray:(一般不用的) arr2d[1:,...] # array([[4, 5, 6], # [7, 8, 9]]) arr2d[...,:1] # array([[1], # [4], # [7]]) #当然,也可以使用 : 来使用默认的从开始到包含结束的位置的索引: arr2d[:,:1] #这种方式用的更多 # array([[1], # [4], # [7]]) #对于更高维度的,也可以使用索引和切片,但是不易于理解和查看: arr3d = np.arange(1,13).reshape((2,2,3)) arr3d # array([[[ 1, 2, 3], # [ 4, 5, 6]], # # [[ 7, 8, 9], # [10, 11, 12]]]) arr3d[0] # array([[1, 2, 3], # [4, 5, 6]]) arr3d[1,0] #array([7, 8, 9]) arr3d[1,0,2] #9
3.3 整数索引
~如果一个 ndarray 是非元组序列,数据类型为整数或布尔值的 ndarray,或者至少一个元素为序列对象的元组,我们就能够用它来索引 ndarray。高级索引始终返回数据的副本。与此相反,切片只提供了一个视图。
~整数索引就是两种高级索引的类型之一,另一个高级索引方式为 布尔值索引。
~整数索引有助于基于 N 维索引来获取数组中任意元素。每个整数数组表示该维度的下标值。当索引的元素个数就是目标 ndarray 的维度时,会变得相当直接。以下示例获取了 ndarray 对象中每一行指定列的一个元素。因此,行索引包含所有行号,列索引指定要选择的元素。
x = np.array([[1, 2], [3, 4], [5, 6]]) x # array([[1, 2], # [3, 4], # [5, 6]]) #该结果包括数组中 (0,0) ,(1,1) 和 (2,0) 位置处的元素。 #但如果你需要的是按数字对行列同时进行索引的而不是索引单个值的话,应当使用下面的#方式: x[np.ix_([0,1,2],[0,1,0])] # array([[1, 2, 1], # [3, 4, 3], # [5, 6, 5]]) #解读,x[np.ix_([0,1,2],[0,1,0])]中的([0,1,2],[0,1,0])]中[0,1,2]时行,后面是列,#一一对应就会索引出一个3*3的数组 #也可以利用数字索引生成同样维度的数组: x = np.array([[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]]) x # array([[ 0, 1, 2], # [ 3, 4, 5], # [ 6, 7, 8], # [ 9, 10, 11]]) x[[[0,0],[3,3]], [[0,2],[0,2]]] # array([[ 0, 2], #好好想想为什么是这么个结果?? # [ 9, 11]])
3.4 布尔索引
当结果对象是布尔运算(例如比较运算符)的结果时,将使用此类型的高级索引。
x = np.arange(12).reshape(4,3) x # array([[ 0, 1, 2], # [ 3, 4, 5], # [ 6, 7, 8], # [ 9, 10, 11]]) x > 5 # array([[False, False, False], # [False, False, False], # [ True, True, True], # [ True, True, True]]) x[x > 5] #将之前的布尔数组进行索引,并将返回结果转化为一维数组 #array([ 6, 7, 8, 9, 10, 11]) a = np.array([np.nan,1,2,np.nan,3,4,5]) a #array([nan, 1., 2., nan, 3., 4., 5.]) b = np.isnan(a) #判断a中的元素是否是空值 b #array([ True, False, False, True, False, False, False]) a[np.isnan(a)] #去除a中的控制nan a #array([nan, nan]) a[~np.isnan(a)] #取出a中的所有非空元素,这是相当经典的方法 #array([1., 2., 3., 4., 5.]) a = np.array([1, 2+6j, 5, 3.5+5j]) print(a) print(a[np.iscomplex(a)]) #取出a中的复数 # [1. +0.j 2. +6.j 5. +0.j 3.5+5.j] # [2. +6.j 3.5+5.j]
四、Numpy-数组切分组合
几种方法可以沿不同轴将数组堆叠在一起:
- np.vstack 沿纵轴拼接
- np.hstack 沿横轴拼接
- np.row_stack 以行将数组拼接(等同于np.vstack)
- np.column_stack 以列将数组拼接(等同于np.hstack)
- np.concatenate 将数组以某一轴进行拼接(axis需人为设定)
4.1 np.vstack 沿纵轴拼接
a = np.array([[1,2],[3,4]]) b = np.array([[11,12],[13,14]]) print(a) print(b) # [[1 2] # [3 4]] # [[11 12] # [13 14]] np.vstack((a,b)) # array([[ 1, 2], # [ 3, 4], # [11, 12], # [13, 14]])
4.2 np.hstack 沿横轴拼接
a = np.array([[1,2],[3,4]]) b = np.array([[11,12],[13,14]]) print(a) print(b) # [[1 2] # [3 4]] # [[11 12] # [13 14]] np.hstack((a,b)) # array([[ 1, 2, 11, 12], # [ 3, 4, 13, 14]])
4.3 np.row_stack 以行将数组拼接(等同于np.vstack)
a = np.array([[1,2],[3,4]]) b = np.array([[11,12],[13,14]]) print(a) print(b) # [[1 2] # [3 4]] # [[11 12] # [13 14]] np.row_stack((a,b)) # array([[ 1, 2], # [ 3, 4], # [11, 12], # [13, 14]])
4.4 np.column_stack 以列将数组拼接(等同于np.hstack)
a = np.array([[1,2],[3,4]]) b = np.array([[11,12],[13,14]]) print(a) print(b) # [[1 2] # [3 4]] # [[11 12] # [13 14]] np.column_stack((a,b)) # array([[ 1, 2, 11, 12], # [ 3, 4, 13, 14]])
4.5 np.concatenate 将数组以某一轴进行拼接(axis需人为设定)
a = np.array([[1,2],[3,4]]) b = np.array([[11,12],[13,14]]) print(a) print(b) # [[1 2] # [3 4]] # [[11 12] # [13 14]] np.concatenate((a,b),axis=1) # array([[ 1, 2, 11, 12], # [ 3, 4, 13, 14]]) np.concatenate((a,b),axis=0) # array([[ 1, 2], # [ 3, 4], # [11, 12], # [13, 14]])
4.6 np.hsplit 纵向进行分割
a = np.arange(24).reshape(3,8) a # array([[ 0, 1, 2, 3, 4, 5, 6, 7], # [ 8, 9, 10, 11, 12, 13, 14, 15], # [16, 17, 18, 19, 20, 21, 22, 23]]) for i in np.hsplit(a,2): #保持行不变以列来分,如果只填一个数据,会平均分,如果不能 print(i) #平均分,就会报错 print('*'*20) # [[ 0 1 2 3] # [ 8 9 10 11] # [16 17 18 19]] # ******************** # [[ 4 5 6 7] # [12 13 14 15] # [20 21 22 23]] # ******************** for i in np.hsplit(a,(3,5)):#这种表示,先分出3列,再分出5列,但这5列里又包含之前 print(i) #的3列,于是第二部分只会有两列 print('*'*20) # [[ 0 1 2] # [ 8 9 10] # [16 17 18]] # ******************** # [[ 3 4] # [11 12] # [19 20]] # ******************** # [[ 5 6 7] # [13 14 15] # [21 22 23]] # ********************
4.7 np.vsplit 横向进行分割
a = np.arange(24).reshape(3,8) a # array([[ 0, 1, 2, 3, 4, 5, 6, 7], # [ 8, 9, 10, 11, 12, 13, 14, 15], # [16, 17, 18, 19, 20, 21, 22, 23]]) for i in np.vsplit(a,3): #平均分成3行 print(i) print('*'*20) # [[0 1 2 3 4 5 6 7]] # ******************** # [[ 8 9 10 11 12 13 14 15]] # ******************** # [[16 17 18 19 20 21 22 23]] # ******************** #和上面的np.hsplit相似,不多作讨论
4.8 np.array_split 按指定轴进行分割
a = np.arange(24).reshape(3,8) a # array([[ 0, 1, 2, 3, 4, 5, 6, 7], # [ 8, 9, 10, 11, 12, 13, 14, 15], # [16, 17, 18, 19, 20, 21, 22, 23]]) for i in np.array_split(a,3,axis=1): print(i) print('*'*20) # [[ 0 1 2] # [ 8 9 10] # [16 17 18]] # ******************** # [[ 3 4 5] # [11 12 13] # [19 20 21]] # ******************** # [[ 6 7] # [14 15] # [22 23]] # ******************** for i in np.array_split(a,3,axis=0): print(i) print('*'*20) # [[0 1 2 3 4 5 6 7]] # ******************** # [[ 8 9 10 11 12 13 14 15]] # ******************** # [[16 17 18 19 20 21 22 23]] # ********************
五、 NumPy-广播
术语广播是指 NumPy 在算术运算期间处理不同形状的数组的能力。对数组的算术运算通常在 相应的元素上进行。如果两个阵列具有完全相同的形状,则这些操作被无缝执行。
如果两个数组的维数不相同,则元素到元素的操作是不可能的。然而,在 NumPy 中仍然可以对形状不相似的数组进行操作,因为它拥有广播功能。较小的数组会广播到较大数组的大小,以便使它们的形状可兼容。
如果满足以下条件之一,那么数组被称为可广播的。
- 数组拥有相同形状。
- 数组拥有相同的维数,且某一个或多个维度长度为 1 。
- 数组拥有极少的维度,可以在其前面追加长度为 1 的维度,使上述条件成立
给出广播示意图:
#形状相同的广播: np.arange(3) #array([0, 1, 2]) a = np.ones((3,3)) print(a.ndim) print(a.shape) print(a) # 2 # (3, 3) # [[1. 1. 1.] # [1. 1. 1.] # [1. 1. 1.]] print(a+a) # [[2. 2. 2.] # [2. 2. 2.] # [2. 2. 2.]] #相同维度,但其中某一个或多个维度长度为 1 的广播: b = np.arange(3).reshape(1,3) print(b.ndim) print(b.shape) print(b) # 2 # (1, 3) # [[0 1 2]] print(a+b) # [[1. 2. 3.] # [1. 2. 3.] # [1. 2. 3.]] c = np.arange(3).reshape(3,1) print(c.ndim) print(c.shape) print(c) # 2 # (3, 1) # [[0] # [1] # [2]] print(a+c) # [[1. 1. 1.] # [2. 2. 2.] # [3. 3. 3.]] #较少的维度,默认在其前面追加长度为 1 的维度: d = np.arange(3) print(d.ndim) print(d.shape) print(d) # 1 # (3,) # [0 1 2] print(a + d) # [[1. 2. 3.] # [1. 2. 3.] # [1. 2. 3.]] #如果是标量的话,会广播整个数组上: print(a * 3) # [[3. 3. 3.] # [3. 3. 3.] # [3. 3. 3.]] print(c * 3) # [[0] # [3] # [6]] print(d * 3) #[0 3 6]
六、numpy运算
6.1 算数运算
用于执行算术运算(如 add() ,subtract() ,multiply() 和 divide() )的输入数组必须具 有相同的形状或符合数组广播规则。
常用数学运算函数:
a = np.arange(9, dtype = np.float_).reshape(3,3) b = np.array([10,11,12]) a b # array([[0., 1., 2.], # [3., 4., 5.], # [6., 7., 8.]]) # # array([10, 11, 12]) #执行数组的加法 print(np.add(a, b)) print(a+b) # [[10. 12. 14.] # [13. 15. 17.] # [16. 18. 20.]] # [[10. 12. 14.] # [13. 15. 17.] # [16. 18. 20.]] #其余运算类似
numpy.reciprocal() 此函数返回参数逐元素的倒数,由于 Python 处理整数除法的方式,对于绝对值大于 1 的整数 元素,结果始终为 0,对于整数 0,则发出溢出警告。
a = np.arange(0,5,0.3) a # array([0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8, 2.1, 2.4, 2.7, 3. , 3.3, 3.6, # 3.9, 4.2, 4.5, 4.8]) print(np.reciprocal(a)) # [ inf 3.33333333 1.66666667 1.11111111 0.83333333 0.66666667 # 0.55555556 0.47619048 0.41666667 0.37037037 0.33333333 0.3030303 # 0.27777778 0.25641026 0.23809524 0.22222222 0.20833333] # D:\anaconda\lib\site-packages\ipykernel_launcher.py:1: RuntimeWarning: #divide by zero encountered in reciprocal # """Entry point for launching an IPython kernel.
b = np.arange(1,5,1,dtype='int64') print(b) #[1 2 3 4] #执行指数函数 np.exp(b) np.exp2(b) np.expm1(b) #返回np.exp(b)-1 # array([ 2.71828183, 7.3890561 , 20.08553692, 54.59815003]) # Out[155]: # array([ 2., 4., 8., 16.]) # Out[155]: # array([ 1.71828183, 6.3890561 , 19.08553692, 53.59815003]) #执行幂函数 np.power(3,b) #3的b次方 np.power(b,3) #b的3次方 # array([ 3, 9, 27, 81], dtype=int64) # # array([ 1, 8, 27, 64], dtype=int64) #numpy.mod() 此函数返回输入数组中相应元素的除法余数。函数 numpy.remainder() #也产生相同的结果。 a = np.array([10,20,30]) b = np.array([3,5,7]) print(a) print(b) # [10 20 30] # [3 5 7] print(np.mod(a,b)) print(np.remainder(a,b)) # [1 0 2] # [1 0 2]
以下函数用于对含有复数的数组执行操作:
- numpy.real() 返回复数类型参数的实部。
- numpy.imag() 返回复数类型参数的虚部。
- numpy.conj() 返回通过改变虚部的符号而获得的共轭复数。
- numpy.angle() 返回复数参数的角度。函数的参数是 degree 。如果为 true,返回的角度以角度制来表示,否则为以弧度制来表示。
a = np.array([-5.6j, 0.2j, 11. , 1+1j]) print(a) #[-0.-5.6j 0.+0.2j 11.+0.j 1.+1.j ] print(np.real(a)) #实部 print(np.imag(a)) #虚部 # [-0. 0. 11. 1.] # [-5.6 0.2 0. 1. ] print(np.conj(a)) #求a的共轭复数 #[-0.+5.6j 0.-0.2j 11.-0.j 1.-1.j ] print(np.angle(a,deg=True)) #角度 print(np.angle(a,deg=False)) #弧度 # [-90. 90. 0. 45.] # [-1.57079633 1.57079633 0. 0.78539816] #执行三角函数 a = np.array([0,30,45,60,90]) print(np.sin(a * np.pi/180)) #[0. 0.5 0.70710678 0.8660254 1. ]
补充 numpy.around() numpy.floor() numpy.ceil()
#numpy.around() 这个函数返回四舍五入到所需精度的值。decimals 表示要舍入的小数位##数。默认值为 0。如果 为负,整数将四舍五入到小数点左侧的位置 a = np.array([1.0,5.55, 123, 0.567, 25.532]) print(a) print(np.around(a)) print(np.around(a, decimals = 1)) print(np.around(a, decimals = -1)) # [ 1. 5.55 123. 0.567 25.532] # [ 1. 6. 123. 1. 26.] # [ 1. 5.6 123. 0.6 25.5] # [ 0. 10. 120. 0. 30.] #同 Python 内置一样,在进行舍入操作时需要注意二进制小数的精度问题 np.around(2.5) #2.0 为什么????这个就有点意思了
#numpy.floor() 向下取整 #此函数返回不大于输入参数的最大整数。即标量 x 的下限是最大的整数 i ,使得 i <= x。注#意 在 Python 中,向下取整总是从 0 舍入。 a = np.array([-1.7, 1.5, -0.2, 0.6, 10]) print(np.floor(a)) #[-2. 1. -1. 0. 10.]
#numpy.ceil()向上取整 #本函数返回输入值的上限,即,标量 x 的上限是最小的整数 i ,使得 i> = x。 a = np.array([-1.7, 1.5, -0.2, 0.6, 10]) print(np.ceil(a)) #[-1. 2. -0. 1. 10.]
6.2 字符串函数
6.2.1 连接两个数组中对应位置上的字符串—numpy.char.add()
#函数执行按元素的字符串连接: a = np.array([["Hello"],["Hi"]]) print(a.dtype) print(a) # <U5 # [['Hello'] # ['Hi']] b = np.array([["abc"],["xyz"]]) print(b.dtype) print(b) # <U3 # [['abc'] # ['xyz']] print(np.char.add(a,b)) # [['Helloabc'] # ['Hixyz']] c = np.array(["abc", "def", "ghi"]) print(c.dtype) print(c) # <U3 # ['abc' 'def' 'ghi'] print(np.char.add(c, "嗯哼 ~?")) #['abc嗯哼 ~?' 'def嗯哼 ~?' 'ghi嗯哼 ~?']
6.2.2 返回按元素多重连接后的字符串—numpy.char.multiply()
print(np.char.multiply('Hello ',3)) #Hello Hello Hello print(np.char.multiply(a, 3)) # [['HelloHelloHello'] # ['HiHiHi']]
6.2.3 此函数返回所需宽度的数组,以便输入字符串位于中心,并使用 fillchar 在左侧和右侧进行填充—numpy.char.center()
np.char.center('hello', 20,fillchar = '*') #array('*******hello********', dtype='<U20')
6.2.4 函数返回字符串的副本,其中第一个字母大写—numpy.char.capitalize()
print(np.char.capitalize('hello world')) #Hello world e = np.array(['hello world', "how are you?"]) print(np.char.capitalize(e)) #['Hello world' 'How are you?']
6.2.5 将字符串的每个单词的第一个字母转换为大写—numpy.char.title()
print(np.char.title('hello how are you?')) #Hello How Are You? print(np.char.title(e)) #['Hello World' 'How Are You?']
6.2.6 数组元素转换为小写—numpy.char.lower()
#numpy.char.lower() #函数返回一个数组,其元素转换为小写。它对每个元素调用 str.lower: f = np.array(['HELLO','WORLD']) print(np.char.lower(f)) #['hello' 'world']
6.2.7 数组元素转换为大写—numpy.char.upper()
#numpy.char.upper() #函数返回一个数组,其元素转换为大写。它对每个元素调用 str.upper: print(np.char.upper('world')) #WORLD print(np.char.upper(e)) #['HELLO WORLD' 'HOW ARE YOU?']
6.2.8 指定分隔符对字符串进行分割,并返回数组列表—numpy.char.split()
# numpy.char.split()
#此函数返回输入字符串中的单词列表。默认情况下,空格用作分隔符。否则,指定的分隔符字符用于分割字符串: print(np.char.split(e)) #[list(['hello', 'world']) list(['how', 'are', 'you?'])] print(np.char.split ('TutorialsPoint,Hyderabad,Telangana', sep = ',')) #['TutorialsPoint', 'Hyderabad', 'Telangana']
6.2.9 返回元素中的行列表,以换行符分割—numpy.char.splitlines()
# numpy.char.splitlines() # 函数返回数组中元素的单词列表,以换行符分割: # '\n','\r','\r\n' 都被当做换行符处理。 print(np.char.splitlines('hello\nhow are you?')) #['hello', 'how are you?'] a = np.array(['123', '456', 'abc', 'zxc', '789', 'ooo']) b = a.reshape(3,2) print(b) # [['123' '456'] # ['abc' 'zxc'] # ['789' 'ooo']] print(np.char.splitlines(b)) # [[list(['123']) list(['456'])] # [list(['abc']) list(['zxc'])] # [list(['789']) list(['ooo'])]]
6.2.10 移除元素开头或者结尾处的特定字符—numpy.char.strip()
#numpy.char.strip() #函数返回数组的副本,其中元素移除了开头或结尾处的特定字符: print(np.char.strip('ashok arora','a')) #去除首位的a print(np.char.strip(['arora','admin','java'],'a')) #shok aror #['ror' 'dmin' 'jav']
6.2.11 通过指定分隔符来连接数组中的元素—numpy.char.join()
#numpy.char.join() #这个函数返回一个字符串,其中单个字符由特定的分隔符连接: print(np.char.join(':','dmy')) print(np.char.join([':','-'],['dmy','ymd'])) #d:m:y #['d:m:y' 'y-m-d']
6.2.12 使用新字符串替换字符串中选定子字符串—numpy.char.replace()
#numpy.char.replace() #这个函数返回字符串副本,其中所有字符序列的出现位置都被另一个给定的字符序列取代: print(np.char.replace('she is a bad girl', 'is', 'was')) #she was a bad girl
6.3 统计函数
NumPy有很多有用的统计函数,用于从数组中给定的元素中查找最小,最大,百分标准差和方差等。
NumPy有很多有用的统计函数,用于从数组中给定的元素中查找最小,最大,百分标准差和方差等。
常用统计函数 | |
---|---|
numpy.amin() | 从给定数组中的元素沿指定轴返回最小值 |
numpy.amax() | 从给定数组中的元素沿指定轴返回最大值 |
numpy.ptp() | 返回沿轴的值的极差(最大值 - 最小值) |
numpy.percentile() | 返回特定轴的百分位数 |
numpy.median() | 返回数组中值 |
numpy.mean() | 返回数组的算术平均值 |
numpy.average() | 返回数组的加权平均值 |
numpy.std() | 返回数组的标准差 |
numpy.var() | 返回数组的方差 |
6.3.1 从给定数组中的元素沿指定轴返回最小值—numpy.amin()
a = np.array([[3,7,5],[8,4,3],[2,4,9]]) print(a) # [[3 7 5] # [8 4 3] # [2 4 9]] print(np.amin(a)) #返回数组中的最小值 print(np.amin(a,axis=0)) #返回每一列中的最小值 print(np.amin(a,axis=1)) #返回没一行中的最小值 # 2 # [2 4 3] # [3 3 2]
6.3.2 从给定数组中的元素沿指定轴返回最大值—numpy.amax()
a = np.array([[3,7,5],[8,4,3],[2,4,9]]) print(a) # [[3 7 5] # [8 4 3] # [2 4 9]] print(np.amax(a)) #返回数组中的最大值 print(np.amax(a, 0)) #返回每一列当中的最大值 print(np.amax(a, 1)) #返回每一行当中的最大值 # 9 # [8 7 9] # [7 8 9]
6.3.3 返回沿轴的值的极差(最大值 - 最小值)—numpy.ptp()
a = np.array([[3,7,5],[8,4,3],[2,4,9]]) print(a) # [[3 7 5] # [8 4 3] # [2 4 9]] print(np.ptp(a)) #返回整个数组中的最大值-最小值 print(np.ptp(a, 0)) #返回每一列中的最大值-最小值 print(np.ptp(a, 1)) #返回每一行中的最大值-最小值 # 7 # [6 3 6] # [4 5 7]
6.3.4 百分位数—numpy.percentile()
百分位数是统计中使用的度量,表示小于这个值得观察值占某个百分比。函数numpy.percentile() 接受以下参数。
numpy.percentile(a, q, axis)
- a 输入数组
- q 要计算的百分位数,在 0 ~ 100 之间
- axis 沿着它计算百分位数的轴
a = np.array([[30,40,70],[80,20,10],[50,90,60]]) print(a) # [[30 40 70] # [80 20 10] # [50 90 60]] print(np.percentile(a,50)) print(np.percentile(a,50, axis = 0)) print(np.percentile(a,50, axis = 1)) # 50.0 # [50. 40. 60.] # [40. 20. 60.]
关于百分位数的原理:
然后查了下它的实现原理: 首先将你的输入数组进行从小到大排序,然后计算: (n−1)∗p=i+j (n-1)*p = i + j(n−1)∗p=i+j 其中n为数组元素的个数,将计算结果的整数部分用i表示,小数部分用j来表示。则最终的percentile值为: res=(1−j)∗array[i]+j∗array[i+1] res = (1-j) * array[i] + j * array[i+1]res=(1−j)∗array[i]+j∗array[i+1]
6.3.5 用于计算数组 a 中元素的中位数(中值)—numpy.median()
#numpy.median() #中值定义为将数据样本的上半部分与下半部分分开的值。 a = np.array([[30,65,70],[80,95,10],[50,90,60]]) print(a) # [[30 65 70] # [80 95 10] # [50 90 60]] print(np.median(a)) print(np.median(a, axis = 0)) #返回每一列的中值 print(np.median(a, axis = 1)) # 65.0 # [50. 90. 60.] # [65. 80. 60.]
6.3.6 返回数组中元素的算术平均值—numpy.mean()
#numpy.mean() #算术平均值是沿轴的元素的总和除以元素的数量。函数返回数组中元素的算术平均值。如果提#供了轴,则沿其计算。 a = np.array([[1,2,3],[3,4,5],[4,5,6]]) print(a) # [[1 2 3] # [3 4 5] # [4 5 6]] print(np.mean(a)) print(np.mean(a, axis = 0)) print(np.mean(a, axis = 1)) # 3.6666666666666665 # [2.66666667 3.66666667 4.66666667] # [2. 4. 5.]
6.3.7 返回数组中元素的加权平均值—numpy.average()
# numpy.average() # 加权平均值是由每个分量乘以反映其重要性的因子得到的平均值。函数根据在另一个数组中给出的各自的权重计算数组中元素的加权平均值。该函数可以接受一个轴参数。如果没有指定轴,则数组会被展开。 # 考虑数组 [1,2,3,4] 和相应的权重 [4,3,2,1] ,通过将相应元素的乘积相加,并将和除以权重的和,来计算加权平均值。 # 加权平均值 = (1*4+2*3+3*2+4*1)/(4+3+2+1) a = np.array([1,2,3,4]) print(a) # [1 2 3 4] #不指定权重时相当于 mean 函数 print(np.average(a)) #默认权重是[1, 1, 1, 1] #2.5 wts = np.array([4,3,2,1]) print(np.average(a,weights = wts)) #2.0 #如果 returned 参数设为 true,则会返回权重的和 print(np.average([1,2,3,4],weights=[4,3,2,1], returned=True)) 20/10 #(2.0, 10.0) #以元祖形式返回(加权平均, 权重之和)
6.3.8 返回数组的标准差—numpy.std()
#numpy.std() #标准差是与均值的偏差的平方的平均值的平方根。标准差公式如下: std = sqrt(mean((x - #x.mean())**2)) print(np.std([1,2,3,4])) #1.118033988749895
6.3.9 返回数组的方差—numpy.var()
print(np.var([1,2,3,4])) #1.25
6.4 排序、搜索和计数函数
6.4.1 返回输入数组的排序副本 默认对行进行升序—numpy.sort()
#numpy.sort()函数返回输入数组的排序副本。 默认对行进行升序 a = np.array([[3,7],[9,1]]) print(a) # [[3 7] # [9 1]] print(np.sort(a)) #默认对每行进行升序 # [[3 7] # [1 9]] print(np.sort(a, axis = 0)) #axis = 0表示对列进行排序 # [[3 1] # [9 7]]
6.4.2 返回的是数组值从小到大的索引值—numpy.argsort()
#numpy.argsort() #函数对输入数组沿给定轴执行间接排序,并使用指定排序类型返回数据的索引数组。这个索引 #数组用于构造排序后的数组。 返回数组升序后的原来数组的索引 x = np.array([3, 1, 2]) print(x) #[3 1 2] y = np.argsort(x) print(y) #[1 2 0] print(x[y]) #[1, 2, 3]
6.4.3 用于对多个序列进行排序—numpy.lexsort()
这个函数就有点意思了,刚看的时候完全不明白是怎么排序的
#numpy.lexsort() #函数使用键序列执行间接排序。键可以看作是电子表格中的一列。该函数返回一个索引数组,#使用它可以获得排序数据。注意,最后一个键恰好是 sort 的主键。 a = [1,5,1,4,3,4,4] # First column b = [9,4,0,4,0,2,1] # Second column ind = np.lexsort((b,a)) # Sort by a, then by b print(ind) #[2 0 4 6 5 3 1] #关于该函数的实现过程,第一步先对后面的a进行从小到大的排序[1 1 3 4 4 4 5],得到索引[0 2 4 3 5 6 1] #但是前面两个[1 1],是一样的,这这时按照对应的索引[0 2]取出中的[9 0],对此进行排序[0 9]意味着要把 #[0 2]变成[2 0],后面的[4 4 4]一样的 [(a[i],b[i]) for i in ind] #列表推导式 #[(1, 0), (1, 9), (3, 0), (4, 1), (4, 2), (4, 4), (5, 4)]
6.4.4 沿给定轴返回最大元素的索引—numpy.argmax() 最小—numpy.argmin()
a = np.array([[30,40,70],[80,20,10],[50,90,60]]) print(a) # [[30 40 70] # [80 20 10] # [50 90 60]] print(np.argmax(a)) #应该是返回在所有元素的第几个位置 #7 print(a.flatten()) #将数组转化为一行 a.flatten()[7] #90 np.argmax(a, axis = 0) #按列来求 np.argmax(a, axis = 1) #按行来求 # array([1, 2, 0], dtype=int64) # # array([2, 0, 1], dtype=int64)
6.4.5 返回输入数组中非零元素的索引—numpy.nonzero()
a = np.array([[30,40,0],[0,20,10],[50,0,60]]) print(a) # [[30 40 0] # [ 0 20 10] # [50 0 60] print(np.nonzero(a)) #两个是分别按照axis=0,axis=1返回的索引 第一个数组是行,第二 #个数组是列! #(array([0, 0, 1, 1, 2, 2], dtype=int64), array([0, 1, 1, 2, 0, 2], dtype=int64)) a[np.nonzero(a)] # 挑选出非零元素 相当经典 #array([30, 40, 20, 10, 50, 60])
6.4.6 返回输入数组中满足给定条件的元素的索引—numpy.where()
x = np.arange(9.).reshape(3, 3) print(x) # [[0. 1. 2.] # [3. 4. 5.] # [6. 7. 8.]]] print(np.where(x > 3)) #(array([1, 1, 2, 2, 2], dtype=int64), array([1, 2, 0, 1, 2], dtype=int64)) x[np.where(x>3)] #array([4., 5., 6., 7., 8.]) a = np.array([1,2,3,4,5]) b = np.array([5,4,3,2,1]) print(np.where(a > b, a, b)) #返回a, b中的较大值 #[5 4 3 4 5]
6.4.7 返回满足任何条件的元素—numpy.extract()
x = np.arange(9.).reshape(3, 3) print(x) # [[0. 1. 2.] # [3. 4. 5.] # [6. 7. 8.]] condition = np.mod(x,2) == 0 print(condition) # [[ True False True] # [False True False] # [ True False True]] np.extract(condition, x) #array([0., 2., 4., 6., 8.])
6.5 转置
Numpy 的转置可以按照你的需要对数组的轴进行转换
arr = np.arange(15).reshape((3, 5)) print(arr # [[ 0 1 2 3 4] # [ 5 6 7 8 9] # [10 11 12 13 14]] arr.T # array([[ 0, 5, 10], # [ 1, 6, 11], # [ 2, 7, 12], # [ 3, 8, 13], # [ 4, 9, 14]]) #需要注意的是,转置只能发生在二维及以上的维度的数组上生效,一维的数组只有一个维度是 #不可以转置的。 一维的怎么办?np.reshape(1,-1)变成二维,再转置 a = np.arange(7) print(a.shape) print(a.ndim) print(a) # (7,) # 1 # [0 1 2 3 4 5 6] a.T #array([0, 1, 2, 3, 4, 5, 6])
6.6 唯一化和集合逻辑
6.6.1 去掉数组中重复的元素—np.unique()
#字符串去重 names = np.array(['Atom', 'Lucy', 'Kid', 'Atom', 'Kid', 'Atom']) print(names) print(np.unique(names)) # ['Atom' 'Lucy' 'Kid' 'Atom' 'Kid' 'Atom'] # ['Atom' 'Kid' 'Lucy'] #整数去重 ints = np.array([1,2,3,4,2,4,3,5]) print(ints) print(np.unique(ints)) # [1 2 3 4 2 4 3 5] # [1 2 3 4 5] #布尔值去重 bools = np.array([False, True, True, False]) print(bools) print(np.unique(bools)) # [False True True False] # [False True]
6.6.2 验证元素是否在给定序列中—np.in1d()
#布尔值的any()和all()函数 bools = np.array([False, True, True, False]) bools.any() #有一个True就返回True bools.all() #所有都为True才返回True # True # # False val_1 = np.array([4,5,6,2,5,7,4,0]) val_2 = np.array([1,2,3,4,7,8,4,3]) # 验证 val_1 中的元素是否在给出的序列中 np.in1d(val_1, [0, 5, 7]) #array([False, True, False, False, True, True, False, True])
6.6.3 求交集—np.intersect1d()
val_1 = np.array([4,5,6,2,5,7,4,0]) val_2 = np.array([1,2,3,4,7,8,4,3]) #求交集 np.intersect1d(val_1, val_2) #array([2, 4, 7])
6.6.4 求并集—np.union1d()
val_1 = np.array([4,5,6,2,5,7,4,0]) val_2 = np.array([1,2,3,4,7,8,4,3]) #求并集 np.union1d(val_1,val_2) #array([0, 1, 2, 3, 4, 5, 6, 7, 8])
6.6.5 求差集—np.setdiff1d()
# 求差集 假设有集合A和B,所有属于A且不属于B的元素的集合被称为A与B的差集 =A - AB np.setdiff1d(val_1, val_2) np.setdiff1d(val_2, val_1) # array([0, 5, 6]) # array([1, 3, 8])
七、NumPy - 矩阵库
NumPy 包包含一个 Matrix 库 numpy.matlib 。此模块的函数返回矩阵而不是返回 ndarray对象。
7.1 导入矩阵库
import numpy.matlib
7.2 返回一个新的矩阵,且不初始化元素—matlib.empty()
# matlib.empty() # 函数返回一个新的矩阵,且不初始化元素。里面的初始化数据无意义 m = np.matlib.empty((2,2)) type(m) m # #numpy.matrixlib.defmatrix.matrix # Out[42]: # matrix([[4.24399158e-314, 8.48798317e-314], # [1.06099790e-313, 1.48539705e-313]])
7.3 返回以0填充的矩阵—numpy.matlib.zeros()
np.matlib.zeros((2,2)) # matrix([[0., 0.], # [0., 0.]]
7.4 返回以1填充的矩阵—numpy.matlib.ones()
np.matlib.ones((5,5)) # # #matrix([[1., 1., 1., 1., 1.], # [1., 1., 1., 1., 1.], # [1., 1., 1., 1., 1.], # [1., 1., 1., 1., 1.], # [1., 1., 1., 1., 1.]])
7.5 返回一个矩阵,对角线元素为 1,其他位置为零—numpy.matlib.eye()
np.matlib.eye(n = 3, M = 3, k = 0, dtype = float) #n: 返回矩阵的行数 # M: 返回矩阵的列数,默认为 n # k: 对角线的索引 # dtype: 数据类型 # matrix([[1., 0., 0.], # [0., 1., 0.], # [0., 0., 1.]]) np.matlib.eye(n = 3, M = 3, k = 1, dtype = float) # matrix([[0., 1., 0.], # [0., 0., 1.], # [0., 0., 0.]]) np.matlib.eye(n = 3, M = 4, k = 1, dtype = float) # matrix([[0., 1., 0., 0.], # [0., 0., 1., 0.], # [0., 0., 0., 1.]])
7.6 返回给定大小的单位矩阵。单位矩阵是主对角线元素都为 1 的方阵—numpy.matlib.identity()
np.matlib.identity(5, dtype = float) # matrix([[1., 0., 0., 0., 0.], # [0., 1., 0., 0., 0.], # [0., 0., 1., 0., 0.], # [0., 0., 0., 1., 0.], # [0., 0., 0., 0., 1.]])
7.7 返回给定大小的填充随机值的矩阵—numpy.matlib.rand()
np.matlib.rand(3,3) # matrix([[0.15307052, 0.69552953, 0.31876643], # [0.6919703 , 0.55438325, 0.38895057], # [0.92513249, 0.84167 , 0.35739757]])
注意,矩阵总是二维的,而 ndarray 是一个 n 维数组。两个对象都是可互换的,但是两个对象并不是相同的
八、 NumPy - 线性代数
NumPy 包包含 numpy.linalg 模块,提供线性代数所需的所有功能。
- numpy.dot() 返回两个数组的点积
- numpy.vdot() 返回两个向量的点积
- numpy.inner() 返回一维数组的向量内积
- numpy.matmul() 返回两个数组的矩阵乘积
- numpy.linalg.det() 计算输入矩阵的行列式
- numpy.linalg.solve() 求解矩阵形式的线性方程的解
- numpy.linalg.inv() 计算矩阵的逆
8.1 返回两个数组的点积—numpy.dot() (二维数组的点积就是矩阵的乘积)
#numpy.dot() #此函数返回两个数组的点积。对于二维向量,其等效于矩阵乘法。对于一维数组,它是向量的 #内积。对于 N 维数组,它是 a 的最后一个轴上的和与 b 的倒数第二个轴的乘积。 a = np.array([[1,2],[3,4]]) b = np.array([[11,12],[13,14]]) print(a) print(b) # [[1 2] # [3 4]] # [[11 12] # [13 14]] np.dot(a,b) # array([[37, 40], # [85, 92]]) #在较新版本中支持了以 @ 符号来表示矩阵的乘法 print(a @ b) # array([[37, 40], # [85, 92]])
8.2 返回两个向量的点积—numpy.vdot()
#numpy.vdot() #此函数返回两个向量的点积。如果第一个参数是复数,那么它的共轭复数会用于计算。如果参#数是多维数组,它会被展开。相同位置的元素相乘再求和 a = np.array([[1,2],[3,4]]) b = np.array([[11,12],[13,14]]) print(a) print(b) # [[1 2] # [3 4]] # [[11 12] # [13 14]] np.vdot(a,b) # 点积就是对应位置相乘再求和 #130 a = np.array([1,2,3,4]) b = np.array([11,12,13,14]).reshape(4,1) print(a) print(b) #[1 2 3 4] # [[11] # [12] # [13] # [14]] np.vdot(a,b) #130
8.3 返回一维数组的向量内积。对于更高的维度,它返回最后一个轴上的乘积的和—numpy.inner()
print(np.inner(np.array([1,2,3]), np.array([0,1,0])) ) #等价于1*0+2*1+3*0 #2 a = np.array([[1,2], [3,4]]) b = np.array([[11, 12], [13, 14]]) print(a) print(b) # [[1 2] # [3 4]] # [[11 12] # [13 14]] np.inner(a, b) # array([[35, 41], # [81, 95]]) #上面的例子中,内积计算如下: #1∗11+2∗121∗11+2∗12 , 1∗13+2∗141∗13+2∗14 #3∗11+4∗123∗11+4∗12 , 3∗13+4∗143∗13+4∗14
8.4 返回两个数组的矩阵乘积—numpy.matmul()
#numpy.matmul() #函数返回两个数组的矩阵乘积。虽然它返回二维数组的正常乘积,但如果任一参数的维数大于 #2,则将其视为存在于最后两个索引的矩阵的栈,并进行相应广播。另一方面,如果任一参数#是一 维数组,则通过在其维度上附加 1 来将其提升为矩阵,并在乘法之后被去除。 # 对于二维数组,它就是矩阵乘法 a = [[1,0],[0,1]] b = [[4,1],[2,2]] print(a) print(b) print(np.matmul(a,b)) # [[1, 0], [0, 1]] # [[4, 1], [2, 2]] # [[4 1] # [2 2]] # 二维和一维运算 a = [[1,0],[0,1]] b = [1,2] print(np.matmul(a,b)) print(np.matmul(b,a)) # [1 2] # [1 2] # 维度大于二的数组 a = np.arange(8).reshape(2,2,2) b = np.arange(4).reshape(2,2) print(np.matmul(a,b)) # [[[ 2 3] # [ 6 11]] # # [[10 19] # [14 27]]]
8.5 计算输入矩阵的行列式—numpy.linalg.det()
#numpy.linalg.det() #函数计算输入矩阵的行列式。行列式在线性代数中是非常有用的值。 a = np.array([[1,2], [3,4]]) print(a) np.linalg.det(a) # [[1 2] # [3 4]] # -2.0000000000000004 b = np.array([[6,1,1], [4, -2, 5], [2,8,7]]) print(b) np.linalg.det(b) # [[ 6 1 1] # [ 4 -2 5] # [ 2 8 7]] # # -306.0
8.6 求出矩阵形式的线性方程的解—numpy.linalg.solve()
如果矩阵成为 A 、X 和 B ,方程变为:AX = B
A = np.array([[1,1,1],[0,2,5],[2,5,-1]]) B = np.array([6,-4,27]) print(A) print(B) # [[ 1 1 1] # [ 0 2 5] # [ 2 5 -1]] # [ 6 -4 27] X = np.linalg.solve(A, B) print(X) #[ 5. 3. -2.] np.allclose(np.dot(A,X),B) #判断两者是否相等 #True
8.7 计算矩阵的逆—numpy.linalg.inv()
x = np.array([[1,2],[3,4]]) y = np.linalg.inv(x) print(x) print(y) # [[1 2] # [3 4]] # [[-2. 1. ] # [ 1.5 -0.5]] print(x.dot(y)) #A*A^{-1} 等于单位阵 # [[1.00000000e+00 1.11022302e-16] # [0.00000000e+00 1.00000000e+00]]
九、NumPy - IO
ndarray 对象可以保存到磁盘文件并从磁盘文件加载。可用的 IO 功能有:
- load() 和 save() 函数处理 NumPy 二进制文件(带 npy 扩展名)
- loadtxt() 和 savetxt() 函数处理正常的文本文件
NumPy 为 ndarray 对象引入了一个简单的文件格式。这个 npy 文件在磁盘文件中,存储重建ndarray 所需的数据、图形、dtype 和其他信息,以便正确获取数组,即使该文件在具有不同架构的另一台机器上。
9.1 将输入数组存储在具有 npy 扩展名的磁盘文件中—numpy.save()
a = np.array([1,2,3,4,5]) np.save('outfile222',a)
为了从 outfile.npy 重建数组,请使用 load() 函数
b = np.load('outfile222.npy') print(b) #[1 2 3 4 5]
9.2 以简单文本文件格式存储和获取数组数据—savetxt()和loadtx()
a = np.array([1,2,3,4,5]) np.savetxt('out.txt',a) b = np.loadtxt('out.txt') print(b) #[1. 2. 3. 4. 5.]
savetxt() 和 loadtxt() 函数接受附加的可选参数,例如页首,页尾和分隔符。