Python 之 Numpy 框架入门

NumPy

NumPy 是 Python 中用于科学计算的基本包。它是一个 Python 库,提供了一个多维数组对象、各种派生对象(比如屏蔽数组和矩阵) ,以及一系列用于数组快速操作的例程,包括数学、逻辑、形状操作、排序、选择、 i/o、离散傅里叶变换、基本线性代数、基本统计操作、随机模拟等等。

官网文档地址:https://numpy.org/

单纯学习 Numpy 会比较闷,因为 Numpy 是用于科学计算的。只是学习了各种 API 的使用,会很苦闷学来干啥,跟人工智能有什么关系?

Python 之 Numpy 框架入门

安装 numpy 比较简单,直接使用命令安装即可:

pip install numpy 

测试是否正常:

import numpy as np print(np.__version__) 

Python 之 Numpy 框架入门

基础使用

基本数据类型

下表列举了常用 NumPy 基本类型。

名称 描述
bool_ 布尔型数据类型(True 或者 False)
int_ 默认的整数类型(类似于 C 语言中的 long,int32 或 int64)
intc 与 C 的 int 类型一样,一般是 int32 或 int 64
intp 用于索引的整数类型(类似于 C 的 ssize_t,一般情况下仍然是 int32 或 int64)
int8 字节(-128 to 127)
int16 整数(-32768 to 32767)
int32 整数(-2147483648 to 2147483647)
int64 整数(-9223372036854775808 to 9223372036854775807)
uint8 无符号整数(0 to 255)
uint16 无符号整数(0 to 65535)
uint32 无符号整数(0 to 4294967295)
uint64 无符号整数(0 to 18446744073709551615)
float_ float64 类型的简写
float16 半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位
float32 单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位
float64 双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位
complex_ complex128 类型的简写,即 128 位复数
complex64 复数,表示双 32 位浮点数(实数部分和虚数部分)
complex128 复数,表示双 64 位浮点数(实数部分和虚数部分)

每个内建类型都有一个唯一定义它的字符代码,如下:

字符 对应类型
b 布尔型
i (有符号) 整型
u 无符号整型 integer
f 浮点型
c 复数浮点型
m timedelta(时间间隔)
M datetime(日期时间)
O (Python) 对象
S, a (byte-)字符串
U Unicode
V 原始数据 (void)

numpy 有个 dtype 函数,用于定义变量类型,其定义如下:

class numpy.dtype(dtype, align=False, copy=False[, metadata]) 

比如这段代码定义了一个numpy 中 int32 类型的变量:

import numpy as np a = np.dtype(dtype="int32") print(a) 

也可以使用短代码:

import numpy as np a = np.dtype("i") print(a) 

等效代码:

import numpy as np a = np.dtype(np.int32) print(a) 

运行代码后,都会打印:

int32 

这个类型是 numpy 中的类型,不是 Python 中的类型,要注意区分。numpy 的数值类型实际上是 dtype 对象的实例,并对应唯一的字符,包括 np.bool_,np.int32,np.float32,等等。

因为 Python 是弱类型,没有 int32 a = ... 这种语法,所以为了明确定义这个变量是何种类型,需要使用类型的字符串名称。

这句话现在可以先不管,后面会在很多地方使用 dtype,用熟了就知道了。

要注意的是 np.dtype 是创建一个类型标识,本身并没有存储变量值。

示例:

import numpy as np  def test(object, dtype):     if dtype == np.int32:         print(f"{object} int32")      elif dtype == np.int64:         print(f"{object} int64")      elif dtype == np.str_:         print(f"{object} str_")   a = 111 b = np.dtype(dtype="int32") test(a, b)  c = '111' d = np.dtype(dtype="str") test(c, d) 

创建基本数组

Numpy 提供了一个多维数组对象、各种派生对象(比如屏蔽数组和矩阵) ,numpy 中最重要的对象是数组和矩阵。所以要学会 numpy ,最基本的是学会 numpy 数组。

numpy 创建数组的定义:

numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0) 

参数说明:

名称 描述
object 数组或嵌套的数列
dtype 数组元素的数据类型,可选
copy 对象是否需要复制,可选
order 创建数组的样式,C为行方向,F为列方向,A为任意方向(默认)
subok 默认返回一个与基类类型一致的数组
ndmin 指定生成数组的最小维度

创建一个基本数组:

import numpy as np a = np.array([1, 2, 3]) 

创建多维数组

import numpy as np a = np.array([[1,  2],  [3,  4]]) print (a) 

Python 之 Numpy 框架入门

定义一个数组,然后生成多维数组:

import numpy as np a = np.array([1, 2, 3, 4, 5], ndmin =  2) # 相当于 np.array([[1, 2, 3, 4, 5]]) print (a)  b = np.array([1, 2, 3, 4, 5], ndmin =  3) # 相当于 np.array([[[1, 2, 3, 4, 5]]]) print (b)  c = np.array([[1, 2, 3, 4, 5],[1, 2, 3, 4, 5]], ndmin =  3) # 相当于 np.array([[[1, 2, 3, 4, 5],[1, 2, 3, 4, 5]]]) print (c) 

Python 之 Numpy 框架入门

数组属性

由于 Python 是弱类型,所以想学习和了解细节的时候,会比较懵逼。因此,我们尽量在编写 Python 代码时,获取代码的一些文档注释。

如下面代码中,定义了一个数组:

import numpy as np a = np.array([[1,  2],  [3,  4]]) print (a) 

numpy 的数组,其类型为 ndarray[Any, dtype],完整文档如下:

a: ndarray[Any, dtype] = np.array([[1,  2],  [3,  4]]) 

所以,要掌握 numpy 数组,实际上就是在了解 ndarray

ndarray 中比较重要的属性如下:

属性 说明
ndarray.ndim 秩,即轴的数量或维度的数量
ndarray.shape 数组的维度,对于矩阵,n 行 m 列
ndarray.size 数组元素的总个数,相当于 .shape 中 n*m 的值
ndarray.dtype ndarray 对象的元素类型
ndarray.itemsize ndarray 对象中每个元素的大小,以字节为单位
ndarray.flags ndarray 对象的内存信息
ndarray.real ndarray元素的实部
ndarray.imag ndarray 元素的虚部
ndarray.data 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。

回到之前提到过的 numpy.dtype,结合 numpy.array,其示例代码如下:

import numpy import numpy as np  a = np.array([1, 2]) print(a.dtype) print(a)  t = np.dtype(numpy.float64) b = np.array(object=[1, 2], dtype=t) print(b.dtype) print(b) 

Python 之 Numpy 框架入门

如果我们不配置 dtype 参数,那么数组的 dtype 会以数组元素类型为依据。如果配置了 dtype,那么数组元素都会被转换为对应的类型,如 np.array(object=[1, 2], dtype='float64')

数组生成

zeros、ones、empty 数组生成

numpy.zeros

numpy.zeros 的作用是创建一个元素全部为 0 的数组。

其定义如下:

def zeros(shape, dtype=float, order='C', *, like=None, /) 
参数 描述
shape 数组形状
dtype 数据类型,可选
order 有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序。

创建一个全部由 0 填充的数组:

import numpy as np  # 长度为 2 a = np.zeros(2) print(a) 

Python 之 Numpy 框架入门

np.zeros() 默认创建的数组是 float64 类型,如果需要自定义类型,可以使用 dtype:

import numpy as np  # 长度为 2 a = np.zeros(2,dtype=int) print(a) 

Python 之 Numpy 框架入门

numpy.ones

ones 创建一个元素值均为 1 的数组。

其定义如下:

def ones(shape, dtype=None, order='C', *, like=None) 

示例如下:

import numpy as np  # 长度为 2 a = np.ones(2,dtype=int) print(a) 

由于其 API 与 numpy.zeros 一致,因此不再赘述。

numpy.empty

创建一个指定长度的空数组,但是不会对内存区域进行初始化,所以其被分配的内存区域可能已经有值

其定义如下:

def empty(shape, dtype=None, order='C', *args, **kwargs) 

示例:

import numpy as np  # 长度为 2 a = np.empty(2)  print(a) 

Python 之 Numpy 框架入门

由于其没有初始化内存,因此内存区域会残留数据。

其它说明

此外,还有三个对应的原型复制函数:

def empty_like(prototype, dtype=None, order=None, subok=None, shape=None 
def zeros_like(prototype, dtype=None, order='K', subok=True, shape=None) 
def ones_like(prototype, dtype=None, order='K', subok=True, shape=None) 

它们的作用是根据数组类型,拷贝一个相同的结构,然后填充对应值。

如下示例,复制数组相同的结构,但是填充的值为 0。

import numpy as np  a = np.array([[1],[1]]) b = np.zeros_like(a) print(b) 

Python 之 Numpy 框架入门

此外,这三个函数,可以传递元组,生成多维的数组(矩阵)。

import numpy import numpy as np  a = np.zeros(shape=(2, 3, 4), dtype=numpy.double) print(a) 

Python 之 Numpy 框架入门

numpy.random

numpy.random 是一个类,不是一个函数,numpy.random 中有一些随机生成数组的函数。

以下是一些常用的 API:

#生成具有给定形状的均匀分布的随机样本,范围在[0, 1)之间。 numpy.random.rand(size)  # 生成具有给定形状的标准正态分布(平均值为0,方差为1)的随机样本。随机样本取值范围是[0,1)。 numpy.random.randn(size)  # 正态分布,指定均值和方差 numpy.random.normal(loc=0.0, scale=1.0, size=None)  # 随机生成 numpy.random.random(size=None)  # 从给定的上下限范围内生成随机整数。 numpy.random.randint(low, high=None, size=None, dtype=int)  # 从给定的一维数组中生成随机样本。 numpy.random.choice(a, size=None, replace=True, p=None)  # 随机打乱给定数组的顺序。 numpy.random.shuffle(x) 

随机数值生成和正态分布生成示例如下:

import numpy as np  a = np.random.rand(10) b = np.random.rand(10) print(a) print(b) 
[0.39809428 0.83922059 0.10808865 0.00332159 0.75922001 0.26850704  0.04497839 0.59012908 0.0438718  0.59988563] [0.78161896 0.91401858 0.10980276 0.89723959 0.06802148 0.18993732  0.10664519 0.14121531 0.27353601 0.56878734] 

Python 之 Numpy 框架入门

x1 = np.random.randint(10, size=6) # 一维数组 x2 = np.random.randint(10, size=(3, 4)) # 二维数组 x3 = np.random.randint(10, size=(3, 4, 5)) # 三维数组 

对于其它 API,由于篇幅有限,不再赘述。

numpy.arange

numpy.arange 用于有规律地生成数组。

其定义如下:

numpy.arange([start, ]stop, [step, ]dtype=None, *, like=None) 
参数 描述
start 起始值,默认为0
stop 终止值(不包含)
step 步长,默认为1
dtype 返回ndarray的数据类型,如果没有提供,则会使用输入数据的类型。

numpy.arange 默认从 0 开始生成数组,间隔为 1。

比如,下面代码会生成一个元素值不超过 4 的数组,即范围是 [0,4)

import numpy as np  # 长度为 4 a = np.arange(4) print(a) 

Python 之 Numpy 框架入门

arange(start, stop) 指定开始结束范围,但是依然步长为 1。

import numpy as np  # 长度为 4 a = np.arange(1,4) print(a) 

Python 之 Numpy 框架入门

arange(start, stop, step) 自定义设置范围和步长。

import numpy as np   # 长度为 4 a = np.arange(1,10,3) print(a) 

numpy.linspace

numpy.linspace 可以使用线性间隔的方式生成数组:

np.linspace(0, 10, num=5) 

Python 之 Numpy 框架入门

num=5 的含义是从来的之间平均取得 5 个数值。

[ 0.   2.5  5.   7.5  10. ] 

Python 之 Numpy 框架入门

但是跟我们预料的结果可能不太一样,因为 linspace() 是包括起始点的,所以 0-10 其实个数是 11 个。

import numpy as np  # 长度为 4 a = np.linspace(0, 10, num=10) print(a) 

Python 之 Numpy 框架入门

import numpy as np  # 长度为 4 a = np.linspace(0, 10, num=11) print(a) 

Python 之 Numpy 框架入门

数组操作

数组排序

排序会返回数组的副本。

主要排序函数如下:

sort :按照大小排序

argsort:它是沿指定轴的间接排序,

lexsort:它是对多个键的间接稳定排序,

searchsorted, 它将查找排序数组中的元素。

partition, 分区,这是一个部分排序。

对于 numpy 的数组,请使用 numpy 的函数排序,不要使用 Python 自带的函数排序。

import numpy as np  # 长度为 4 a = np.random.rand(10)  print(a)  # 使用 Python 内置函数 print(sorted(a))  # 使用 numpy.sort print(np.sort(a)) 

Python 之 Numpy 框架入门

如上图所示,使用 Python 自带的函数,会导致精确度出现问题。

切片索引

可以使用 slice(start,stop,step) 函数或 [start:stop:step] 进行切片。

import numpy as np  a = np.arange(10) print(a)  #  索引范围是 2-7 ,间隔为2 # [0 1 2 3 4 5 6 7 8 9] s1 = slice(2, 7, 2)  #  索引范围是 2-8 ,间隔为2 # [0 1 2 3 4 5 6 7 8 9] s2 = slice(2, 8, 2)  print(a[s1]) print(a[s2]) 

Python 之 Numpy 框架入门

等同于:

import numpy as np  a = np.arange(10) print(a)  print(a[2:7:2]) print(a[2:8:2])  

对于二维数组,可以通过坐标点取值。

import numpy as np  x = np.array([[0, 1, 2],               [3, 4, 5],               [6, 7, 8],               [9, 10, 11]])   # 左上角、右上角、左下角、右下角 四个点 a1 = np.array([[0, 0], [3, 3]]) a2 = np.array([[0, 2], [0, 2]])  y = x[a1, a2] print(y)  
[[ 0  2]  [ 9 11]] 

取值时,跟一维数组一致,可以通过索引取值。

import numpy as np  x = np.array([[0, 1, 2],               [3, 4, 5],               [6, 7, 8],               [9, 10, 11]])  y = x[1:2] print(y) 

Python 之 Numpy 框架入门

数组还可以通过表达式取值,如 x>5x<5 等。

import numpy as np  x = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]) print(x)  print(x[x > 5]) 

详细的表达式操作方法,可以查阅官网文档,这里不再赘述。

数组运算符

numpy 数组,可以通过操作符直接操作。

如两个数组的值相加:

import numpy as np  a1 = np.array([1, 2, 3]) a2 = np.array([4, 5, 6])  a3 = a1 + a2 a4 = a1 * a2 print(a3) print(a4)  

得到:

[5 7 9] [ 4 10 18] 

广播规则

对于不同形状的数组(即维数不同),numpy 可以自动补全维数。

其规则约束如下:

  • 两个数组的形状相同

  • 维数比较少的数组,需要是一维数组。

import numpy as np  a = np.array([[1, 2, 3],               [4, 5, 6],               [7, 8, 9]])  b = np.array([100, 100, 100]) print(a + b)  

Python 之 Numpy 框架入门

[						[ [1, 2, 3]		+		[100, 100, 100] [4, 5, 6]		+		[100, 100, 100] [7, 8, 9]		+		[100, 100, 100] ]						] 

相加后:

[ [101 102 103] [104 105 106] [107 108 109] ] 

但是要注意,如果两个数组的一个维中,元素个数不一致,则运算会报错。

import numpy as np  a1 = np.array([1, 2, 3]) a2 = np.array([4, 5, 6, 7])  a3 = a1 + a2 print(a3) 

Python 之 Numpy 框架入门

如果两个数组维度一致,但是形状不一样,维数少的数组必须是一维数组。

如下面代码会报错:

import numpy as np  a = np.array([[1, 2, 3],               [1, 1, 1],               [1, 1, 1]])  b = np.array([[1, 1, 1],               [2, 2, 2]]) print(a + b)  

Python 之 Numpy 框架入门

修改数组

Numpy 中包含了一些函数用于处理数组,大概可分为以下几类:

  • 修改数组形状
  • 翻转数组
  • 修改数组维度
  • 连接数组
  • 分割数组
  • 数组元素的添加与删除

修改数组的形状

主要有以下函数:

函数 描述
reshape 不改变数据的条件下修改形状
flat 数组元素迭代器
flatten 返回一份数组拷贝,对拷贝所做的修改不会影响原始数组
ravel 返回展开数组

将一维数组,转换为二维数组,每个数组元素有 3 个,其示例如下:

import numpy as np  a = np.arange(6).reshape(2, 3) b = np.array([0,1,2,3,4,5]).reshape(2, 3) print(a) print(b) 
[[0 1 2]  [3 4 5]] [[0 1 2] 

其它几个函数可以使用以下示例表达:

import numpy as np  a = np.arange(10) print(a)  # 数组迭代器 .flat for element in a.flat:     print(element)  # 将数组转换为二维数组 b = a.reshape(2,5) print("将数组转换为二维:") print(b)  print("将多维数组合并为一维:") c = b.ravel() print(c) 
[0 1 2 3 4 5 6 7 8 9] 0 1 2 3 4 5 6 7 8 9 将数组转换为二维: [[0 1 2 3 4]  [5 6 7 8 9]] 将多维数组合并为一维: [0 1 2 3 4 5 6 7 8 9] 

翻转数组

其常用函数定义如下:

函数 描述
transpose 对换数组的维度
ndarray.T self.transpose() 相同
rollaxis 向后滚动指定的轴
swapaxes 对换数组的两个轴

transposendarray.T 都可以将数组翻转,例如将 2x5 的数组翻转为 5x2

import numpy import numpy as np  a = np.arange(10).reshape(2,5) print(a) b = numpy.transpose(a) c = a.T print(b) print(c) 
[[0 1 2 3 4]  [5 6 7 8 9]] [[0 5]  [1 6]  [2 7]  [3 8]  [4 9]] [[0 5]  [1 6]  [2 7]  [3 8]  [4 9]] 

rollaxisswapaxes 都有三个参数:

arr:数组 axis:要向后滚动的轴,其它轴的相对位置不会改变。取值范围为 [0, a.ndim] start:默认为零,表示完整的滚动。会滚动到特定位置。取值范围为 [-a.ndim, a.ndim] 

注意:二维只有 01 两个轴,三维有 012 三个轴。axis、start 都是填写轴的序号。

Python 之 Numpy 框架入门

使用 print(a1.ndim) 可以打印数组的维数,即轴数。

swapaxes 用于指定交互两个轴的位置。

如:

import numpy import numpy as np  a1 = np.array([     [0, 0, 0, 0],     [1, 1, 1, 1],     [2, 2, 2, 2],     [3, 3, 3, 3] ])  b = np.swapaxes(a1, 0, 1)  print(b)  

原数组:

[[0, 0, 0, 0] [1, 1, 1, 1] [2, 2, 2, 2] [3, 3, 3, 3]] 

变换后的数组:

[[0 1 2 3]  [0 1 2 3]  [0 1 2 3]  [0 1 2 3]] 

也可以理解成坐标系的 x 轴 和 y 轴,x 轴变成了 y 轴。

swapaxes 在更多维数组的情况下,有更多的轴,例如三维的 x、y、z 三个轴。这里不再赘述。

至于 numpy.rollaxis ,我也不会。

修改数组维度

其主要函数如下:

维度 描述
broadcast 产生模仿广播的对象
broadcast_to 将数组广播到新形状
expand_dims 扩展数组的形状
squeeze 从数组的形状中删除一维条目

连接数组

其主要函数如下:

函数 描述
concatenate 连接沿现有轴的数组序列
stack 沿着新的轴加入一系列数组。
hstack 水平堆叠序列中的数组(列方向)
vstack 竖直堆叠序列中的数组(行方向)

numpy.concatenate 将两个数组拼接成一个新的数组:

import numpy as np  a = np.array([1, 2, 3, 4]) b = np.array([5, 6, 7, 8])  c = np.concatenate((a, b)) print(c) 

Python 之 Numpy 框架入门

分割数组

其主要函数如下:

函数 数组及操作
split 将一个数组分割为多个子数组
hsplit 将一个数组水平分割为多个子数组(按列)
vsplit 将一个数组垂直分割为多个子数组(按行)

其使用方法比较简单,这里不再赘述。

增删数组元素

其主要函数如下:

函数 元素及描述
resize 返回指定形状的新数组
append 将值添加到数组末尾
insert 沿指定轴将值插入到指定下标之前
delete 删掉某个轴的子数组,并返回删除后的新数组
unique 查找数组内的唯一元素

其使用方法比较简单,这里不再赘述。

数组迭代

前面提到过 .flat

import numpy as np  # 这里是二维 a = np.arange(10).reshape(2,5)  # 数组迭代器 .flat for element in a.flat:     print(element) 

.flat 会按照顺序打印每一个元素。

0 1 2 3 4 5 6 7 8 9 

.nditer 也是如此。

import numpy as np  a = np.arange(10).reshape(2,5)  # 数组迭代器 .flat for element in np.nditer(a):     print(element)  

.nditer 可以控制遍历规则。

for x in np.nditer(a.T, order='C'),默认,行遍历。

for x in np.nditer(a, order='F'),列遍历。

import numpy as np  a = np.arange(10).reshape(2, 5)  # 数组迭代器 .flat for element in np.nditer(a, order='F'):     print(element) 
0 5 1 6 2 7 3 8 4 9 

.nditer 可以控制迭代多维数组的维还是元素。

前面提到的代码,均是迭代逐个元素。

如果设置了 flags 参数,则可以迭代维。

import numpy as np  a = np.arange(10).reshape(2, 5)  # 数组迭代器 .flat for element in np.nditer(a, order='F', flags=['external_loop']):     print(element) 
原数组: [[0 1 2 3 4]  [5 6 7 8 9]]  按照迭代方向 F: [0 5] [1 6] [2 7] [3 8] [4 9] 

发表评论

评论已关闭。

相关文章