pythonPython

Numpy库

2020-04-09  本文已影响0人  小哲1998

0. NumPy的安装

访问 https://www.anaconda.com/distribution/ ,根据电脑的系统下载对应的软件,安装完成在软件中选择JupyterLab即可使用。

在CMD中输入python -m pip install --user numpy scipy matplotlib ipython jupyter pandas sympy nose等待安装完成即可。

附:安装验证

输入下列代码能得到结果即代表着安装成功:

from numpy import *
eye(4)

输出:

array([[1., 0., 0., 0.],
       [0., 1., 0., 0.],
       [0., 0., 1., 0.],
       [0., 0., 0., 1.]])

1. NumPy库简介

NumPy是一个科学计算基础库其中提供了许多向量和矩阵操作,能让用户轻松完成最优化、线性代数、积分、插值、特殊函数、傅里叶变换、信号处理和图像处理、常微分方程求解以及其他科学与工程中常用的计算,不仅方便易用而且效率更高。

2. NumPy

NumPy数组的维数称为秩(rank),秩就是轴的数量,一位数组的秩为1,二维数组的秩为2,依次类推。在 NumPy中,每一个线性的数组称为是一个轴(axis),也就是维度(dimensions)。比如说,二维数组相当于是两个一维数组,其中第一个一维数组中每个元素又是一个一维数组。所以一维数组就是 NumPy 中的轴(axis),第一个轴相当于是底层数组,第二个轴是底层数组里的数组。而轴的数量——秩,就是数组的维数。很多时候可以声明 axis。axis=0,表示沿着第 0 轴进行操作,即对每一列进行操作;axis=1,表示沿着第1轴进行操作,即对每一行进行操作。

2.1 Ndarray

Ndarray(N维数组)对象是NumPy最重要的一个特点,它是一系列同类型数据的集合,以0下标为开始进行集合中元素的索引。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 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。

示例:

import numpy as np
data = np.arange(12).reshape(3, 4)
print("data=", data)
print("type(data)=", type(data))
print("data.ndim=", data.ndim)
print("data.shape=", data.shape)
print("data.size=", data.size)
print("data.dtype=", data.dtype)

输出:

data= [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
type(data)= <class 'numpy.ndarray'>
data.ndim= 2
data.shape= (3, 4)
data.size= 12
data.dtype= int32

解析:

在代码示例中,第一行将numpy库导入并将其取名为np,第二行初始化一个三行四列的递增数组data,第三行输出data,第四行输出data的类型,第五行输出了数组的维度个数,第六行输出了数组的维度,第七行输出了数组中元素的总个数,第八行输出了元素的类型。

2.1.1 常用属性

ndarray.shape 表示数组的维度,返回一个元组,这个元组的长度就是维度的数目,即 ndim 属性(秩)。比如,一个二维数组,其维度表示"行数"和"列数"。ndarray.shape也可以用于调整数组大小。

代码:

import numpy as np
data = np.arange(12)
print("更改前的数组:", data)
data.shape = (3, 4)
print("更改后的数组:", data)

输出:

更改前的数组: [ 0  1  2  3  4  5  6  7  8 
 9 10 11]
更改后的数组: [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

reshape()函数可用来调整数组大小,例如:

import numpy as np
data = np.arange(12)
print("更改前的数组:", data)
data.shape = (3, 4)
print("更改后的数组:", data)
print("reshape后数值:", data.reshape(2,6))

输出:

更改前的数组: [ 0  1  2  3  4  5  6  7  8 
 9 10 11]
更改后的数组: [[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
reshape后数值: [[ 0  1  2  3  4  5]       
 [ 6  7  8  9 10 11]]

ndarray.flags返回 ndarray 对象的内存信息,包含以下属性:

属性 描述
C_CONTIGUOUS (C) 数据是在一个单一的C风格的连续段中
F_CONTIGUOUS (F) 数据是在一个单一的Fortran风格的连续段中
OWNDATA (O) 数组拥有它所使用的内存或从另一个对象中借用它
WRITEABLE (W) 数据区域可以被写入,将该值设置为 False,则数据为只读
ALIGNED (A) 数据和所有元素都适当地对齐到硬件上
UPDATEIFCOPY (U) 这个数组是其它数组的一个副本,当这个数组被释放时,原数组的内容将被更新

代码:

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

输出:

  C_CONTIGUOUS : True
  F_CONTIGUOUS : True
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  WRITEBACKIFCOPY : False
  UPDATEIFCOPY : False

2.2 创建NumPy数组

2.2.1 使用array()函数创建数组

语法:

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

示例:

import numpy as np
data = np.array([1, 2, 3])
data2 = np.array((1, 2, 3))
data3 = np.array(((1, 2, 3), (4, 5, 6)))
data4 = np.array([1, 2, 3, 4, 5], complex, ndmin=2)
print("data=", data)
print("data2=", data2)
print("data3=", data3)
print("data4=", data4)

输出:

data= [1 2 3]
data2= [1 2 3]
data3= [[1 2 3]
 [4 5 6]]
data4= [[1.+0.j 2.+0.j 3.+0.j 4.+0.j 5.+0.j]]

解析:

可以通过array()函数由列表元组转化,由列表/元组转化为多维数组需要子元素为列表/元组的列表/元组,即:

[[1,2,3],[4,5,6]]
[(1,2,3),(4,5,6)]
([1,2,3],[4,5,6])
((1,2,3),(4,5,6))

都是可以的。

2.2.2 numpy创建数组

创建一个只分配内存空间的数组,其中的元素将随机填充。

语法:

empty(shape, dtype=float, order='C', /)
名称 描述
shape 数组的维度,例如(2,3)代表两行三列
dtype 数组元素的类型,可选,默认为float64
order 创建数组的样式,C为行方向,F为列方向,A为任意方向(默认),可选

代码:

import numpy as np
data = np.empty((3, 5))
print(data)

输出:

[[6.23042070e-307 4.67296746e-307 1.69121096e-306 2.31424250e-306
  1.89146896e-307]
 [7.56571288e-307 3.11525958e-307 1.24610723e-306 1.37962320e-306       
  1.29060871e-306]
 [2.22518251e-306 1.33511969e-306 1.78022342e-306 1.05700345e-307       
  2.76676762e-322]]

zeros()将创建一个用指定形状用0填充的数组。默认的dtype是float64。

ones()将创建一个用指定形状用1填充的数组。默认的dtype是float64。

语法:

zeros(shape, dtype=float, order='C', /)
ones(shape, dtype=None, order='C')
名称 描述
shape 数组的维度,例如(2,3)代表两行三列
dtype 数组元素的类型,可选
order 创建数组的样式,C为行方向,F为列方向,A为任意方向(默认),可选

代码:

import numpy as np
data_0 = np.zeros((2, 3))
data_1 = np.ones((3, 2))
print("data_0=", data_0)
print("data_1=", data_1)

输出:

data_0= [[0. 0. 0.]
 [0. 0. 0.]]
data_1= [[1. 1.]
 [1. 1.]
 [1. 1.]]
2.2.3 从数值范围创建数组

arrange()函数将创建具有有规律递增值的数组。

语法:

arange(start=None, stop, step=None,dtype=None, /)
名称 描述
Start 开始数值,可选,所输出的数组中包括开始数值
stop 结束数值,若不定义则默认从0开始,单独使用时仅可使用正数,所输出的数组中不包括结束数值
step 步长,可正可负可为小数,可选
dtype 数组中的元素类型

代码:

import numpy as np
data = np.arange(10)
data1 = np.arange(1, 10)
data2 = np.arange(1, 10, 2)
data3 = np.arange(10, 1, -2)
dataf = np.arange(1, 10, 2, float)
print("data=", data)
print("data1=", data1)
print("data2=", data2)
print("data3=", data2)
print("dataf=", dataf)

输出:

data= [0 1 2 3 4 5 6 7 8 9]
data1= [1 2 3 4 5 6 7 8 9]
data2= [1 3 5 7 9]
data3= [1 3 5 7 9]
dataf= [1. 3. 5. 7. 9.]

linspace() 将创建具有指定数量元素的数组,并在指定的开始值和结束值之间平均间隔。该数组为指定起始值的等差数列。

语法:

linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)
名称 描述
start 序列的起始值
stop 序列的终止值
num 序列的项数,默认为50项
endpoint 是否包括stop默认包括
retstep 是否输出步长,默认不输出
dtype 元素属性,默认为float64
axis 操作维度,可选值0/-1,可选

代码:

import numpy as np
data = np.linspace(0,6,3,endpoint=False)
data_2 = np.linspace(0,6,3)
print(data)
print(data_2)

输出:

[0. 2. 4.]
[0. 3. 6.]

logspace()用于创建一个等比数列。

语法:

np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)
参数 描述
start 序列的起始值
stop 序列的终止值
num 要生成的等步长的样本数量,默认为50
endpoint 该值为 true 时,数列中中包含stop值,反之不包含,默认是True。
base 对数 log 的底数,默认底数为10。
dtype ndarray 的数据类型,默认为float64

数组为:[{base}^{start},……,{base}^{stop}],其中endpoint=True

代码:

import numpy as np
a = np.logspace(0, 9, 10, base=2)
print(a)

输出:

[  1.   2.   4.   8.  16.  32.  64. 128. 256. 512.]
2.2.4 从已有的数组创建数组

语法:

numpy.asarray(a, dtype = None, order = None)
参数 描述
a 任意形式的输入参数,可以是,列表, 列表的元组, 元组, 元组的元组, 元组的列表,多维数组
dtype 数据类型,可选
order 可选,有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序。

代码:

import numpy as np
x = [1, 2, 3]
y = (4, 5, 6)
z = [(7, 8), (9, 10, 11)]
# 从列表创建数组
a = np.asarray(x)
# 从元组创建数组
b = np.asarray(y)
# 从元组列表创建数组
c = np.asarray(z)
print(a, b, c)

输出:

[1 2 3] [4 5 6] [(7, 8) (9, 10, 11)]

当然,asarray也可以设置dtype属性,例如:

import numpy as np 
 
x =  [1,2,3] 
a = np.asarray(x, dtype =  float)  
print (a)

输出为:

[ 1.  2.  3.]

numpy.frombuffer用于实现动态数组。numpy.frombuffer接受 buffer 输入参数,以流的形式读入转化成 ndarray 对象。

语法:

numpy.frombuffer(buffer, dtype = float, count = -1, offset = 0)

注意:buffer 是字符串的时候,Python3 默认 str 是 Unicode 类型,所以要转成 bytestring 在原 str 前加上 b。

参数 描述
buffer 可以是任意对象,会以流的形式读入。
dtype 返回数组的数据类型,可选
count 读取的数据数量,默认为-1,读取所有数据。
offset 读取的起始位置,默认为0。

代码:

import numpy as np 
 
s =  b'Hello World' 
a = np.frombuffer(s, dtype =  'S1')  
print (a)

输出:

[b'H' b'e' b'l' b'l' b'o' b' ' b'W' b'o' b'r' b'l' b'd']

2.3 数据类型

numpy 支持的数据类型比 Python 内置的类型要多很多,基本上可以和 C 语言的数据类型对应上,其中部分类型对应为 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 位浮点数(实数部分和虚数部分)
2.3.1 查看数据类型

通过ndarray.dtype可以创建一个表示数据类型的对象,如果想要获取数据类型名称,需要访问name属性进行获取,例如:

import numpy as np
data = np.array([[1, 2, 3], [4, 5, 6]])
print(data.dtype.name)

本段代码在64位Windows系统将输出int32,在64位Linux或MacOS中将输出int64

2.3.2 创建数据类型

可以通过如下语法构造dtype对象

numpy.dtype(object, align, copy)

每一个NumPy内置的数据类型都有一个特征码,它能唯一标识一种数据类型,具体如表所示:

特征码 含义 特征码 含义
b 布尔型 i 有符号整型
u 无符号整型 f 浮点型
c 复数类型 O Python对象
S,a 字节字符串 U unicode字符串
V 原始数据

字节顺序是通过对数据类型预先设定"<"或">"来决定的。"<"意味着小端法(最小值存储在最小的地址,即低位组放在最前面)。">"意味着大端法(最重要的字节存储在最小的地址,即高位组放在最前面)。例如如下代码:

import numpy as np
# 创建car类型
car = np.dtype([('name', 'a3'), ('age', 'i1'), ('speed', 'f4')])
# 创建dtype为car类型的数组
a = np.array([('xz', 1, 20), ('ln', 2, 10)], dtype=car)
print(a)

输出为:

[(b'xz', 1, 20.) (b'ln', 2, 10.)]
2.3.3 转换数据类型

该函数可以对ndarray对象的数据类型进行转换。

代码:

import numpy as np
data = np.zeros((2, 3))
print("修改前的类型:", data.dtype)
int_data = data.astype(np.int64)
print("修改后的类型", int_data.dtype)

输出:

修改前的类型: float64
修改后的类型 int64

2.4 切片和索引

2.4.1 一维切片

在Python中接触过使用list函数的切片操作,ndarray对象内容可以同样通过索引或切片操作来访问和修改,基于0 - n的下标进行索引,使用内置的slice函数,设置startstopstep参数,从原数组中切割出一个新数组,其中slice语法为:

slice(start: Any, stop: Any, step: Any=...)
slice(stop)
slice(start, stop[, step])
参数 说明
start 索引开始
stop 索引结束
step 索引步长

代码:

import numpy as np
a = np.arange(10)
s = slice(2, 7, 2)   # 从索引 2 开始到索引 7 停止,间隔为 2
print(a[s])

输出:

[2 4 6]

当然也可以直接通过冒号分割切片参数start:stop:step来进行切片操作:

代码:

import numpy as np
a = np.arange(10)
b = a[2:7:2]    # 从索引 2 开始到索引 7 停止,间隔为 2
print(b)

输出:

[2 4 6]
有关:的解释
import numpy as np
a = np.arange(10)
print(a[2], " ", a[-2])

输出为:2 8

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

输出为:[2 3 4 5 6 7 8 9]

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

输出为:[0 1 2 3 4 5 6]

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

输出为:[2 3 4 5 6]

import numpy as np
a = np.arange(10)
print(a[::-1])

输出为:[9 8 7 6 5 4 3 2 1 0]

import numpy as np
a = np.array([[1, 2, 3], [3, 4, 5], [4, 5, 6]])
print(a)
# 从某个索引处开始切割
print('从数组索引 a[1:] 处开始切割')
print(a[1:])

输出为:

[[1 2 3]
 [3 4 5]
 [4 5 6]]
从数组索引 a[1:] 处开始切割
[[3 4 5]
 [4 5 6]]

更多例子:

import numpy as np
a = np.arange(10)
print(a[1:9:2])  # 输出在索引为1和9之间(不包括9)步长为2的元素
print(a[9:1:-2])  # 反向输出在索引为9和1之间(不包括1)步长为2的元素

输出为:

[1 3 5 7]
[9 7 5 3]
2.4.2 多维切片

冒号分割函数在多维数组的处理上也很方便,在多维数组切片[x,y],x代表行号,y代表列号,例如下图中为二维数组中对应的冒号索引。

多维访问

例如下列代码:

import numpy as np
a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
print(a[2,1])

输出为10,即为第2行第1列的元素。在多维数组的每一维同样可以使用:索引,在讲解多维数组下的:索引之前先引入一下省略号切片:

省略号切片

如图所示,如果需要输出第2行元素只需使用:

import numpy as np
a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
print(a[2, ...])
print(a[2]) # 当省略号代表列时可省略

而输出第2列元素可以使用:

import numpy as np
a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
print(a[..., 2])

多维数组下的:索引

创建一个4×4的二维数组,一些区域访问的例子如下图所示:

多维数组切片

代码:

import numpy as np
a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
print(a[1:3, 0])
print(a[2:, 1])
print(a[:3])
print(a[..., :3])
print(a[0::2, 2])
print(a[3:0:-2, 2])
print(a[0:2, 1:3])
print(a[::2, 0:])
print(a[::-2, 0:])

输出:

[5 9]
[10 14]
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
[[ 1  2  3]
 [ 5  6  7]
 [ 9 10 11]
 [13 14 15]]
[ 3 11]
[15  7]
[[2 3]
 [6 7]]
[[ 1  2  3  4]
 [ 9 10 11 12]]
[[13 14 15 16]
 [ 5  6  7  8]]

如果我们需要填充一个8×8的棋盘,黑的为0,白的为1,可以使用:索引迅速填充:

import numpy as np
chess = np.zeros((8, 8), int)
chess[::2, 1::2] = 1
chess[1::2, ::2] = 1
print(chess)
2.4.3 花式索引与布尔索引

花式索引的基本形式如下图所示:

花式索引
import numpy as np
a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]])
print(a[[0, 3]])
print(a[..., [0, 3]])
print(a[[0, 3], [1, 3]])
print(a[[0, 1, 2, 0, 3], [0, 2, 3, 1, 2]])

输出为:

[[ 1  2  3  4]
 [13 14 15 16]]
[[ 1  4]
 [ 5  8]
 [ 9 12]
 [13 16]]
[ 2 16]
[ 1  7 12  2 15]

当花式索引使用一个数组做索引,即a[[x,y]]a[..., [x,y]]形式时,输出第x,y行/列的元素,而当使用两个数组做索引,即a[[x,y],[m,n]]形式时,输出第xm列和第y行第n列的元素。

np.ix_
np.ix_

代码:

import numpy as np

x = np.arange(32).reshape((8, 4))
print(x[np.ix_([1, 5, 7, 2], [0, 3, 1, 2])])
print(x[[1, 5, 7, 2], [0, 3, 1, 2]])

输出:

[[ 4  7  5  6]
 [20 23 21 22]
 [28 31 29 30]
 [ 8 11  9 10]]
[ 4 23 29 10]

布尔索引指的是将一个布尔数组作为数组索引,返回的数据是布尔数组中True对应位置的值,比如一个简单的例子:

考试结束五个同学的成绩如下表:

zz 98 64 87
yxy 100 92 76
wyf 67 99 90
wcc 80 100 99
zyh 79 95 66

使用student存储姓名,使用student_score存储学生成绩,使用布尔索引输出姓名为zyh的成绩

代码:

import numpy as np
student = np.array(['zz', 'yxy', 'wyf', 'wcc', 'zyh'])
student_score = np.array([[98, 64, 87], [100, 92, 76], [67, 99, 90],
                          [80, 100, 99], [79, 95, 66]])

print(student == 'zyh')
# 将布尔数组作为索引应用于存储成绩的数组,返回的数据是True值对应的行
print(student_score[student == 'zyh'])
# 布尔型数组与切片混合使用
print(student_score[student == 'zyh', 1:])

输出:

[False False False False  True]
[[79 95 66]]
[[95 66]]

在使用布尔型索引获取值得时候,除了可以使用"=="运算符还可以使用"!="、"-"来进行否定、">"和"<"来判断数值大小以及"&"和"|"等符号来组合多个布尔条件。

2.5 数组运算

NumPy数组不需要循环遍历即可对每个元素执行批量的算术运算操作,这个过程叫矢量化运算。如果两个数组大小ndarray.shape不同,则进行算术运算时会出现广播机制。同时,数组还支持算术运算符和标量进行运算。

2.5.1 矢量化运算

在NumPy中任何大小相等的数组之间的算术运算都会应用到元素级,即只用于位置相同的元素之间,所得的运算结果组成一个新的数组。

矢量化运算

如图所示,两数组对齐以后会让相同位置的元素操作得到结果,并且结果的位置和操作数的位置相同,例如:

import numpy as np
a = np.array([4, 5, 3, 1])
b = np.array([1, 3, 2, 8])
print("a+b=", a + b)
print("a-b=", a - b)
print("a*b=", a * b)
print("a%b=", a % b)

输出为:

a+b= [5 8 5 9]
a-b= [ 3  2  1 -7]
a*b= [ 4 15  6  8]
a%b= [0 2 1 1]
2.5.2 数组广播

数组进行矢量化运算时,要求数组的形状是相等的。当形状不相等的数组执行算术运算时会出现广播机制,该机制会对数组进行扩展,使数组的shape属性值一样,然后就可以进行矢量化运算。

广播机制

如图所示,输入一个4行1列和一个1行3列的数组,在二者进行计算的时候会按照广播机制进行扩展使两者都成为4行3列的数组再进行矢量运算,代码为:

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

输出为:

a+b=
[[ 4  3  8]
 [ 7  6 11]
 [ 9  8 13]
 [11 10 15]]

广播的规则:

2.5.3 数组与标量间的运算

数组与标量之间的运算类似于广播机制,标量会扩展为与输入相同大小的数组,所产生的数组中的所有元素均为该标量,例如:

import numpy as np
a = np.arange(10)
a.shape = (2, 5)
b = 1
print("a=", a)
print("a+b=", a + b)

输出为:

a= [[0 1 2 3 4]
 [5 6 7 8 9]]
a+b= [[ 1  2  3  4  5]
 [ 6  7  8  9 10]]
2.5.4 数组的操作

NumPy中包含了一些函数用于处理数组,如图所示:

NumPy数组操作

修改数组形状

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

numpy.reshape

格式:

numpy.reshape(arr, newshape, order='C')

代码:

import numpy as np
a = np.arange(6)
print("原始数组为:")
print(a, '\n')

b = a.reshape(2, 3)
print("修改后的数组为:")
print(b)

输出:

原始数组为:
[0 1 2 3 4 5] 

修改后的数组为:
[[0 1 2]
 [3 4 5]]

numpy.ndarray.flat

数组元素迭代器,对数组中每个元素都进行处理,可以使用flat属性。

代码:

import numpy as np
a = np.arange(6).reshape(2,3)
print("原始数组:")
for r in a:
    print(r)

print("迭代后的数组:")
for e in a.flat:
    print(e)

输出:

原始数组:
[0 1 2]
[3 4 5]
迭代后的数组:
0
1
2
3
4
5

numpy.ndarray.flatten

返回一份数组拷贝,对拷贝数组所做的修改不会影响原始数组。

格式:

ndarray.flatten(order='C')

参数说明:

代码:

import numpy as np
a = np.arange(8).reshape(2, 4)
print("原数组:")
print(a, '\n')

print("展开的数组:")
print(a.flatten(), '\n')

print("以F风格顺序展开的数组:")
print(a.flatten(order='F'), '\n')

输出:

原数组:
[[0 1 2 3]
 [4 5 6 7]]

展开的数组:
[0 1 2 3 4 5 6 7]

以F风格顺序展开的数组:
[0 4 1 5 2 6 3 7]

numpy.ravel

numpy.ravel() 展平的数组元素,顺序通常是"C风格",返回的是数组视图,修改会影响原始数组。

语法:

numpy.ravel(a, order='C')

参数说明:

代码:

import numpy as np
a = np.arange(8).reshape(2, 4)
print("原数组:")
print(a, '\n')

print("使用ravel后:")
print(a.ravel(), '\n')

print("以F风格调用ravel后:")
print(a.ravel(order='F'), '\n')

输出:

原数组:
[[0 1 2 3]
 [4 5 6 7]]

使用ravel后:
[0 1 2 3 4 5 6 7]

以F风格调用ravel后:
[0 4 1 5 2 6 3 7]

flattenravel

import numpy as np
a = np.arange(8).reshape(2, 4)
a_2 = a
b = a.flatten()
c = a_2.ravel()
b[1] = 10
c[1] = 10
print("b=", b)
print("a=", a)
print("c=", c)
print("a_2=", a_2)

输出:

b= [ 0 10  2  3  4  5  6  7]
a= [[ 0 10  2  3]
 [ 4  5  6  7]]
c= [ 0 10  2  3  4  5  6  7]
a_2= [[ 0 10  2  3]
 [ 4  5  6  7]]

容易看出修改ravel中的值对原数组元素是有影响的,而修改flatten中的值对原数组无影响。


翻转数组

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

numpy.transpose

numpy.transpose() 函数用于对换数组的维度

语法:

numpy.transpose(arr, axes)

参数说明:

代码:

import numpy as np
a = np.arange(12).reshape(3, 2, 2)
print('原数组:')
print(a, '\n')

print('置换数组:')
print(np.transpose(a))
print(np.transpose(a, (2, 1, 0)))

输出:

原数组:
[[[ 0  1]
  [ 2  3]]

 [[ 4  5]
  [ 6  7]]

 [[ 8  9]
  [10 11]]]

置换数组:
[[[ 0  4  8]
  [ 2  6 10]]

 [[ 1  5  9]
  [ 3  7 11]]]
[[[ 0  4  8]
  [ 2  6 10]]

 [[ 1  5  9]
  [ 3  7 11]]]
有关参数axes的解释

以上例为例,a = np.arange(12).reshape(3, 2, 2)产生一个如图所示的数组:

axes

对于transpose函数中的axes如果不定义则默认全部转置,例如在三维数组中使用transpose会将坐标轴由(x,y,z)转置为(z,y,x),通常的表达式为:np.transpose(a,(0,1,2))其中0代表x轴,1代表y轴,2代表z轴,如果希望在新生成的数组中交换y轴和z轴,则只需输入np.transpose(a,(0,2,1)),如果是四维数组则第四个坐标对应的数字为3,即默认定义的四维数组的axes=(0,1,2,3)


numpy.rollaxis

numpy.rollaxis 函数向后滚动特定的轴到一个特定位置。

语法:

numpy.rollaxis(arr, axis, start)

参数说明:

代码:

import numpy as np
a = np.arange(24).reshape(4, 3, 2)

print("滚动坐标轴:")
print(np.rollaxis(a, 2).shape)

输出:

滚动坐标轴:
(2, 4, 3)
(4, 3, 2)

通过一幅图来了解一下这个函数的机制:

rollaxis

假设创建的一个数组arr为5维数组,即arr.ndim=5,则axis的取值为[-5,4],start取值[-5,5],如果在函数中不定义start值默认取0,而axis为要移动的轴,轴从0开始编号,当然反向同样成立,对于一个n维数组,轴0也是轴-n,而轴a为轴-n+a,官方文档对start的定义为The axis is rolled until it lies before this position. The default, 0, results in a “complete” roll.翻译过来就是轴滚动,直到它位于此位置之前。默认值 0 会导致"完整"滚动。通过对五维数组的尝试,可以发现,以axis-arr.ndim+axis为分隔,当start值小于等于axis-arr.ndim+axis时,原来位于轴axis或轴-arr.ndim+axis的元素滚动至轴start处,其余轴的相对位置保持不变,当start值大于axis-arr.ndim+axis时,原来位于轴axis或轴-arr.ndim+axis的元素滚动至轴start-1处,其余轴的相对位置保持不变。


numpy.moveaxis

(版本 1.11.0 中的新增功能) 将数组的轴移动到新位置,其他轴保持原始顺序类似于numpy.rollaxis,但是这个函数只需指定始位置与终位置即可,且可通过序列定义。

语法:

numpy.moveaxis(arr, source, destination)

参数说明:

代码:

import numpy as np
a = np.zeros((1, 2, 3, 4, 5))
print(np.moveaxis(a, [1, 2], [-1, -5]).shape)

输出:

(3, 1, 4, 5, 2)

如果输入print(np.moveaxis(a, [1, 1], [-1, -5]).shape)会报错,原因是moveaxis第二个参数[1,1]冲突。


numpy.swapaxes

numpy.swapaxes 函数用于交换数组的两个轴。

语法:

numpy.swapaxes(arr, axis1, axis2)

参数说明:

代码:

import numpy as np
a = np.ones((1, 2, 3, 4, 5))
print(np.swapaxes(a,0,-3).shape)

输出:

(3, 2, 1, 4, 5)

更改维度数

方法 描述
atleast_1d(*arys) 将输入转换为至少一维的数组。
atleast_2d(*arys) 将输入视为至少具有二维的数组。
atleast_3d(*arys) 以至少三个维度的数组形式查看输入。
broadcast 产生模仿广播的对象。
broadcast_to(array, shape[, subok]) 将数组广播为新形状。
broadcast_arrays(*args, **kwargs) 互相广播任意数量的阵列。
expand_dims(a, axis) 扩展数组的形状。
squeeze(a[, axis]) 从数组形状中删除一维条目。

改变数组的种类

方法 描述
asarray(a[, dtype, order]) 将输入转换为数组。
asanyarray(a[, dtype, order]) 将输入转换为ndarray,但通过ndarray子类。
asmatrix(data[, dtype]) 将输入解释为矩阵。
asfarray(a[, dtype]) 返回转换为浮点类型的数组。
asfortranarray(a[, dtype]) 返回以Fortran顺序排列在内存中的数组(ndim> = 1)。
ascontiguousarray(a[, dtype]) 返回内存中的连续数组(ndim> = 1)(C顺序)。
asarray_chkfinite(a[, dtype, order]) 将输入转换为数组,检查NaN或Infs。
asscalar(a) 将大小为1的数组转换为其等效的标量。
require(a[, dtype, requirements]) 返回提供的类型满足要求的ndarray。

组合数组

方法 描述
concatenate((a1, a2, …) 沿现有轴连接一系列数组。
stack(arrays[, axis, out]) 沿新轴连接一系列数组。
column_stack(tup) 将一维数组作为列堆叠到二维数组中。
dstack(tup) 沿深度方向(沿第三轴)按顺序堆叠数组。
hstack(tup) 水平(按列)顺序堆叠数组。
vstack(tup) 垂直(行)按顺序堆叠数组。
block(arrays) 从块的嵌套列表中组装一个nd数组。

拆分数组

方法 描述
split(ary, indices_or_sections[, axis]) 将数组拆分为多个子数组,作为ary的视图。
array_split(ary, indices_or_sections[, axis]) 将一个数组拆分为多个子数组。
dsplit(ary, indices_or_sections) 沿第3轴(深度)将数组拆分为多个子数组。
hsplit(ary, indices_or_sections) 水平(按列)将一个数组拆分为多个子数组。
vsplit(ary, indices_or_sections) 垂直(行)将数组拆分为多个子数组。

平铺数组

方法 描述
tile(A, reps) 通过重复A代表次数来构造一个数组。
repeat(a, repeats[, axis]) 重复数组的元素。

添加和删除元素

方法 描述
delete(arr, obj[, axis]) 返回一个新的数组,该数组具有沿删除的轴的子数组。
insert(arr, obj, values[, axis]) 沿给定轴在给定索引之前插入值。
append(arr, values[, axis]) 将值附加到数组的末尾。
resize(a, new_shape) 返回具有指定形状的新数组。
trim_zeros(filt[, trim]) 修剪一维数组或序列中的前导和/或尾随零。
unique(ar[, return_index, return_inverse, …]) 查找数组的唯一元素。

重新排列元素

方法 描述
flip(m[, axis]) 沿给定轴颠倒数组中元素的顺序。
fliplr(m) 左右翻转数组。
flipud(m) 上下翻转阵列。
reshape(a, newshape[, order]) 在不更改数据的情况下为数组赋予新的形状。
roll(a, shift[, axis]) 沿给定轴滚动数组元素。
rot90(m[, k, axes]) 在轴指定的平面中将阵列旋转90度。

2.6 函数

2.6.1 通用函数

在Numpy中提供了诸如sincosexp等常见的数学函数,这些函数称为通用函数(ufunc),通用函数是针对ndarray数据执行元素级运算的函数,函数返回是一个新的数组,通常,将通用函数中接受一个数组参数的函数称为一元通用函数,接受两个数组参数的称为二元通用函数。

常用的一元通用函数

函数 描述
abs、fabs 计算整数、浮点数或辅助的绝对值
sqrt 计算各元素的算术平方根
square 计算各元素的平方
exp 计算各元素的指数ex
log、log10、log2、log1p 分别为自然对数(底数为e),底数为10的对数,底数为2的对数,log(1+x)
sign 计算各元素的正负号:1(正数)、0(零)、-1(负数)
ceil 计算各元素的ceilling值,即大于或者等于该值的最小整数
floor 计算个元素的floor值,即小于或者等于该值的最大整数
rint 将各元素四舍五入到最接近的整数
modf 将数组的小数和整数部分以两个独立数组的形式返回
isnan 返回一个表示“哪些值是NaN”的布尔型数组
isfinite、isinf 分别返回表示“哪些元素是有穷的”或“哪些元素是无穷的”的布尔型数组
sin、sinh、cos、cosh、tan、tanh 普通型和双曲型三角函数
arcos、arccosh、arcsin 反三角函数

常见的二元通用函数

函数 描述
add 将数组中对应的元素相加
subtract 从第一个数组减去第二个数组中的元素
multiply 两个数组元素相乘
divide、floor_divide 除法或向下整除法(舍去余数)
maximum、fmax 元素级的最大值计算
minimum、fmin 元素级的最小值计算
mod 元素级的求模运算
copysign 将第二个数组中的值得符号赋值给第一个数组中的值
greater、greater_equal、less、less_equal、equal、not_equal、logical_and、logical_or、logical_xor 执行元素级的比较运算,最终产生布尔型数组,相当于运算符>、≥、<、≤、==、!=、逻辑和、逻辑或、逻辑异或

代码:

# 通用函数
import numpy as np
# 计算各元素的平方根
a = np.array([1, 4, 9])
print("数组平方根为:", np.sqrt(a))
# 返回数组的整数与小数
b = np.array([1.2, 2.5, 3])
c = np.modf(b)[0]
d = np.modf(b)[1]
print("b数组的小数部分为:", c, "\nb数组的整数部分为:", d)
# 符号赋予
e = np.ones(5)
e[::2] = -1
f = np.arange(5)
g = np.copysign(f, e)
print("符号赋予后的数组:", g)
# 元素级比较
print("e和g数组比较:", np.greater(e, g))

输出:

数组平方根为: [1. 2. 3.]
b数组的小数部分为: [0.2 0.5 0. ] 
b数组的整数部分为: [1. 2. 3.]
符号赋予后的数组: [-0.  1. -2.  3. -4.]   
e和g数组比较: [False False  True False  True]
2.6.2 统计函数
1. 将条件逻辑转换为数组运算

numpy的where()函数是三元表达式x if condition else y的矢量化版本,可以通过逻辑转化为数组运算,例如:

import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
con = np.array([True, False, True])
print(np.where(con, a, b))

输出为[1 5 3],可以看出,where函数的第一个参数作为判定条件,如果元素为True则选取第二个数组中对应位置的元素,如果为False则选取第三个数组中对应位置的元素。当然判定数组也可以使用1代表True0代表False,即con = np.array([1, 0, 1])也能得到同样的结果。

2. 数组的统计运算

NumPy数组中与统计运算相关的方法

方法 描述
sum 对数组中全部或某个轴向的元素求和
mean 算术平均值
min 计算数组中的最小值
max 计算数组中的最大值
argmin 输出最小值索引
argmax 输出最大值索引
cumsum 所有元素的累计和
cumprod 所有元素的累计积

代码:

import numpy as np
a = np.arange(10)
print("累计和为:", np.cumsum(a))
print("累计积为:", np.cumprod(a))

对于累计和如下图所示,累计积同理:

cumsum

输出:

累计和为: [ 0  1  3  6 10 15 21 28 36 45]
累计积为: [0 0 0 0 0 0 0 0 0 0]
3. 数组排序

对数组中的元素进行排序,只需使用sort()函数,例如:

import numpy as np
arr = np.array([[1, 5, 2, 3], [5, 8, 3, 1]])
arr.sort()
print(arr)

输出:

[[1 2 3 5]
 [1 3 5 8]]

排序方法会修改原来的数组,函数中的参数代表着轴,例如:

import numpy as np
arr = np.array([[1, 5, 2, 3], [5, 8, 3, 1]])
arr.sort(0)
print(arr)

则得到的结果为:

[[1 5 2 1]
 [5 8 3 3]]
排序
4. 检索数组元素

在NumPy中,all()函数用于判断整个数组中的元素的值是否全部满足条件,如果全部满足条件则返回True,否则返回Falseany()函数用于判断整个数组中的元素至少有一个满足条件则返回True,否则返回False

代码:

import numpy as np
arr = np.arange(12).reshape(3, 4)
print(np.any(arr > 10))
print(np.all(arr > 10))

输出:

True
False
5. 唯一化及其他集合逻辑

unique()

去除数组中的重复元素,保留唯一元素,即如果数组为[1,1,2,2]则输出为[1,2],且排序输出数组

语法:

unique(ar, return_index=False, return_inverse=False, return_counts=False, axis=None)

参数说明:

图解参数:

unique

对于操作维度,如果不定义默认将数组降为一维,对一维数组进行unique操作。

代码:

import numpy as np
arr = np.array([7, 2, 1, 1, 8, 2])
print(np.unique(arr, return_index=True))
print(np.unique(arr, return_inverse=True))
print(np.unique(arr, return_counts=True))
arr_2 = np.array([[0, 1, 0], [0, 1, 0], [2, 3, 4]])
print(np.unique(arr_2))
print(np.unique(arr_2, axis=0))
print(np.unique(arr_2, axis=1))

输出:

(array([1, 2, 7, 8]), array([2, 1, 0, 4], 
dtype=int64))
(array([1, 2, 7, 8]), array([2, 1, 0, 0, 3, 1], dtype=int64))
(array([1, 2, 7, 8]), array([2, 2, 1, 1], 
dtype=int64))
[0 1 2 3 4]
[[0 1 0]
 [2 3 4]]
[[0 0 1]
 [0 0 1]
 [2 4 3]]

在二维数组中对1轴使用unique函数时,排序以输出的第一行为准,例如:

[[4 3 2 1]
 [5 6 7 8]]

输出将为:

[[1 2 3 4]
 [8 7 6 5]]

数组集合运算的常见函数

函数 描述
unique(x) 计算x中的唯一元素,并返回有序结果
intersect1d(x,y) 计算x和y中的公共元素,并返回有序结果
union1d(x,y) 计算x和y的并集,并返回有序结果
in1d(x,y) 得到一个表示"x的元素是否包含y"的布尔型数组
setdiff1d(x,y) 集合的差,即元素在x中且不再y中
setxor1d(x,y) 集合的对称差,即存在于一个数组中但不同时存在于两个元素中的元素
2.6.3 线性代数相关函数

线性代数是数学运算中的一个重要工具,在numpy.linalg模块中有一组标准的矩阵分解运算以及诸如逆和行列式之类的东西,下面的例子代表矩阵的乘法:

import numpy as np
a = np.array([[1, 2, 3], [4, 5, 6]])
b = np.array([[1, 2], [3, 4], [5, 6]])
print(a.dot(b))  # 等价于np.dot(a,b)

输出为:

[[22 28]
 [49 64]]
矩阵乘法

linalg模块常用函数

函数 描述
dot 矩阵乘法
diag 以一维数组的形式返回方阵的对角线或将一维数组转为方阵
trace 计算对角线元素和
det 计算矩阵的行列式
eig 计算方阵的特征值和特征向量
inv 计算方阵的逆
qr 计算qr分解
svd 计算奇异值
solve 解线性方程组Ax=b,其中A是一个方阵
lstsq 计算Ax=b的最小二乘解
2.6.4 随机数相关函数

与Python的random模块相比,NumPy的random模块功能更多,它增加了一些可以高效生成多种概率分布的样本值函数。

import numpy as np
# 随机生成一个3行3列的二维数组
print(np.random.rand(3, 3))
# 随机生成一个的三维数组
print(np.random.rand(2, 3, 3))

输出:

[[0.51977788 0.78215477 0.03626778]
 [0.53886531 0.84636492 0.20763375]       
 [0.62779302 0.01742627 0.21344803]]      
[[[0.21952024 0.79324513 0.99029048]      
  [0.25493268 0.64863243 0.61611571]      
  [0.85816947 0.52925024 0.16129451]]     

 [[0.02905666 0.85701923 0.81112184]      
  [0.93242048 0.2237645  0.35160048]      
  [0.8884219  0.59137365 0.81497935]]]  

random模块常见函数

函数 描述
seed 生成随机数种子
rand 生成均匀分布的样本值
randint 从给定的上下限范围内随机选取整数
normal 产生正态分布的样本值
beta 产生Beta分布的样本值
uniform 产生在[0,1]中均匀分布的样本值
上一篇下一篇

猜你喜欢

热点阅读