NumPy入门

NumPy入门

原文档是使用jupyter notebook编写,但是在CSDN无法正常显示,因此原文可以查看我的博客

import numpy as np

# jupyter输出显示设置
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

理解Python和NumPy的数据类型

从Python列表创建数组

# 创建整型数组
np.array([1, 2, 3, 4, 5])

array([1, 2, 3, 4, 5])
# 类型不匹配时自动转换
np.array([1.0, 2, 3, 4, 5])

array([1., 2., 3., 4., 5.])
# 指定数组的数据类型
np.array([1, 2, 3, 4, 5], dtype=np.float32)

array([1., 2., 3., 4., 5.], dtype=float32)
# 初始化多维数组
np.array([range(i, i+3) for i in [2, 4, 6]])

array([[2, 3, 4],
       [4, 5, 6],
       [6, 7, 8]])

从头创建数组

# 创建指定大小的全0数组
np.zeros((3, 4), dtype=np.int32)

array([[0, 0, 0, 0],
       [0, 0, 0, 0],
       [0, 0, 0, 0]])
# 创建指定大小的全1数组
np.ones((3, 5), dtype=np.float32)

array([[1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.]], dtype=float32)
# 创建指定大小、指定数值的数组
np.full((3, 5), 3.14)

array([[3.14, 3.14, 3.14, 3.14, 3.14],
       [3.14, 3.14, 3.14, 3.14, 3.14],
       [3.14, 3.14, 3.14, 3.14, 3.14]])
# 创建线性序列,参数为开始、结束、步长(类似于range)
np.arange(0, 20, 2)

array([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18])
# 创建均匀切割的数组,参数为开始、结束、数量
np.linspace(0, 1, 5)

array([0.  , 0.25, 0.5 , 0.75, 1.  ])
# 创建指定大小、0~1之间分布的随机数矩阵
np.random.random((3, 3))

array([[0.52300173, 0.6099551 , 0.90392997],
       [0.68513022, 0.40606534, 0.12176085],
       [0.50479174, 0.67819969, 0.60743873]])
# 创建指定大小、服从指定参数的正态分布的随机数矩阵
np.random.normal(0, 1, (3, 3))

array([[ 0.39088633,  0.01229742, -0.10358749],
       [ 0.17884759,  1.87676579,  0.48339031],
       [ 0.70697702,  0.75920357, -1.29395961]])
# 创建指定大小、指定区间内随机数的一维数组
np.random.randint(0, 10, (3, 3))

array([[5, 2, 9],
       [2, 7, 7],
       [9, 3, 3]])
# 创建指定大小的单位矩阵
np.eye(3)

array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]])
# 创建指定大小未初始化的矩阵
np.empty((3, 5))

array([[3.14, 3.14, 3.14, 3.14, 3.14],
       [3.14, 3.14, 3.14, 3.14, 3.14],
       [3.14, 3.14, 3.14, 3.14, 3.14]])

NumPy标准数据类型

数据类型说明
bool_布尔值,1字节存储
int_默认整型,int64或int32
intc同C语言int
intp用作索引的整型,同C语言ssize_t,通常为int64或int32
int8字节,-128~127
int16整型
int32整型
int64整型
uint8无符号整型
uint16无符号整型
uint32无符号整型
uint64无符号整型
float_float64简化形式
float16半精度浮点型,5比特指数、10比特尾数
float32单精度浮点型,8比特指数、23比特尾数
float64双精度浮点型,11比特指数、52比特尾数
complex_complex128简化形式
complex64复数,两个32位浮点数表示
complex128复数,两个64位浮点数表示
# 数据类型的指定有两种方式:字符串、NumPy对象
np.zeros(5, dtype='int32')
np.zeros(5, dtype=np.int32)

array([0, 0, 0, 0, 0])
array([0, 0, 0, 0, 0])

NumPy数组基础

数组属性

a = np.random.randint(0, 10, size=(10))
b = np.random.randint(0, 10, size=(3, 4))

# 数组的维度
b.ndim
# 数组每个维度的大小
b.shape
# 数组的总大小
b.size
# 数组的数据类型
b.dtype
# 数组元素的字节大小
b.itemsize

2
(3, 4)
12
dtype('int32')
4

数组索引

# 中括号索引
a[0]
# 负值索引
a[-2]
# 逗号分隔维度
b[0, 1]

5
4
3

】 由于NumPy数组是固定类型的,因此如果修改的值与原类型不对应则会执行转换操作

数组切片

切片的语法大致为x[start:stop:step]

# 一维子数组
a
a[5:]
a[::2]
a[1::2]
a[::-1]  # 经典的逆排序操作

array([5, 5, 5, 3, 8, 9, 9, 7, 4, 3])
array([9, 9, 7, 4, 3])
array([5, 5, 8, 9, 4])
array([5, 3, 9, 7, 3])
array([3, 4, 7, 9, 9, 8, 3, 5, 5, 5])
# 多维子数组,逗号分隔不同维度
b
b[:2, :3]
b[:2, ::3]
b[::-1, ::-1]  # 经典的逆排序操作

array([[0, 3, 0, 4],
       [0, 9, 5, 6],
       [7, 0, 5, 9]])
array([[0, 3, 0],
       [0, 9, 5]])
array([[0, 4],
       [0, 6]])
array([[9, 5, 0, 7],
       [6, 5, 9, 0],
       [4, 0, 3, 0]])
# 获取数组的行和列
b[:, 0]
b[0, :]

array([0, 0, 7])
array([0, 3, 0, 4])

由于NumpPy数组切片返回的是数组数据的视图而非数值数据的副本(类似于引用关系),因此需要注意NumPy数组与Python数组的区别。

c = b[0, :]
c[0] = 100
b  # 可以看到改变c的值同时也改变了b的值

array([[100,   3,   0,   4],
       [  0,   9,   5,   6],
       [  7,   0,   5,   9]])
# 创建数组的副本
c = b[0, :].copy()
c[0] = 1000
b  # 改变c的值同时不改变b的值

array([[100,   3,   0,   4],
       [  0,   9,   5,   6],
       [  7,   0,   5,   9]])

数组变形

使用reshape函数进行数组变形时, 如果原始数组大小与变形后数组大小一致,则可以得到原始数组的非副本视图。然而在非连续数据缓存情况下,返回非副本试图往往不能实现。

# 使用reshape()函数
a = np.arange(1, 10)
b = a.reshape((3, 3))
b
b[1, 1] = 100
a # 改变b的值,则a的值也发生改变

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
array([  1,   2,   3,   4, 100,   6,   7,   8,   9])

将一维数组转换为二维矩阵时,可以在切片中使用newaxis关键字或reshape函数

# 使用newaxis关键字
a[np.newaxis, :]
# 使用reshape函数
a.reshape(1, 9)

array([[  1,   2,   3,   4, 100,   6,   7,   8,   9]])
array([[  1,   2,   3,   4, 100,   6,   7,   8,   9]])

数组拼接与分裂

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

数组的拼接或连接主要由np.concatenatenp.vstacknp.hstacknp.dstack实现

# np.concatenate将数组元组或数组列表作为第一参数
np.concatenate([a, b])

array([1, 2, 3, 4, 5, 6])
# np.concatenate也可以拼接多维数组,使用axis控制拼接维度
x = np.array([[1, 2, 3], [4, 5, 6]])
np.concatenate([x, x])
np.concatenate([x, x], axis=1)

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

沿着固定维度处理数据时,使用np.vstacknp.hstack(垂直栈和水平栈)会更加简洁

# 垂直栈
np.vstack([x, a])

# 水平栈
np.hstack([x, c])

array([[1, 2, 3],
       [4, 5, 6],
       [1, 2, 3]])
array([[1, 2, 3, 7],
       [4, 5, 6, 8]])

数组的分裂通过np.splitnp.hsplitnp.vsplitnp.dsplit实现

x = [1, 2, 3, 4, 5, 6, 7, 8]
x

# 使用np.split函数时,向函数传递一个记录分裂点位置的索引列表
x1, x2, x3 = np.split(x, [3, 5])

x1
x2
x3

[1, 2, 3, 4, 5, 6, 7, 8]
array([1, 2, 3])
array([4, 5])
array([6, 7, 8])
x = np.arange(16).reshape((4, 4))
x

# np.vsplit函数
x1, x2 = np.vsplit(x, [2])

x1
x2

# np.hsplit函数
x1, x2 = np.hsplit(x, [2])

x1
x2

array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15]])
array([[0, 1, 2, 3],
       [4, 5, 6, 7]])
array([[ 8,  9, 10, 11],
       [12, 13, 14, 15]])
array([[ 0,  1],
       [ 4,  5],
       [ 8,  9],
       [12, 13]])
array([[ 2,  3],
       [ 6,  7],
       [10, 11],
       [14, 15]])

NumPy数组计算:通用函数

使NumPy计算变快的关键是利用向量化操作,通常在NumPy通用函数实现。

通用函数介绍

NumPy为很多类型的操作提供了方便的、静态类型的、可编译程序的接口,也称为向量操作。向量操作被用于将循环推送至NumPy之下的编译层,以达到更高的执行效率。

x = np.arange(9).reshape((3, 3))
2**x

array([[  1,   2,   4],
       [  8,  16,  32],
       [ 64, 128, 256]], dtype=int32)

探索NumPy的通用函数

通用函数有两种存在形式:一元通用函数(对单个输入操作)、二元通用函数(对两个输入操作)

x = np.arange(4)
# 数组的四则运算
x
x + 5  # np.add
x - 5  # np.subtract
x * 2  # np.multiply
x / 2  # np.divide
x // 2 # np.floor_divide

array([0, 1, 2, 3])
array([5, 6, 7, 8])
array([-5, -4, -3, -2])
array([0, 2, 4, 6])
array([0. , 0.5, 1. , 1.5])
array([0, 0, 1, 1], dtype=int32)
# 数组的其他运算
-x     # np.negative
x ** 2 # np.power
x % 2  # np.mod

array([ 0, -1, -2, -3])
array([0, 1, 4, 9], dtype=int32)
array([0, 1, 0, 1], dtype=int32)
# 绝对值
x = np.array([1, 2, -1, -3, 2, 2])
y = np.array([3-4j, 3+4j, 2, -1])


# 实数数组求绝对值
np.abs(x)

# 复数数组求模长
np.abs(y)

array([1, 2, 1, 3, 2, 2])
array([5., 5., 2., 1.])
# 三角函数
a = np.linspace(0, np.pi, 3)
b = np.linspace(-1, 1, 3)

np.sin(a)
np.cos(a)
np.tan(a)
np.arcsin(b)
np.arccos(b)
np.arctan(b)

array([0.0000000e+00, 1.0000000e+00, 1.2246468e-16])
array([ 1.000000e+00,  6.123234e-17, -1.000000e+00])
array([ 0.00000000e+00,  1.63312394e+16, -1.22464680e-16])
array([-1.57079633,  0.        ,  1.57079633])
array([3.14159265, 1.57079633, 0.        ])
array([-0.78539816,  0.        ,  0.78539816])
# 指数与对数
x = np.array([1, 2, 3])

np.exp(x)
np.exp2(x)
np.power(3, x)
np.log(x)
np.log2(x)
np.log10(x)

array([ 2.71828183,  7.3890561 , 20.08553692])
array([2., 4., 8.])
array([ 3,  9, 27], dtype=int32)
array([0.        , 0.69314718, 1.09861229])
array([0.       , 1.       , 1.5849625])
array([0.        , 0.30103   , 0.47712125])
# 专用的通用函数,由子模块scipy.special提供
from scipy import special

x = [1, 5, 10]
special.gamma(x)
special.beta(x, 2)

x = np.array([0, 0.3, 0.6, 0.9])
special.erf(x)
special.erfc(x)
special.erfinv(x)

array([1.0000e+00, 2.4000e+01, 3.6288e+05])
array([0.5       , 0.03333333, 0.00909091])
array([0.        , 0.32862676, 0.60385609, 0.79690821])
array([1.        , 0.67137324, 0.39614391, 0.20309179])
array([0.        , 0.27246271, 0.59511608, 1.16308715])

高级的通用函数特性

所有的通用函数都可以通过out参数指定计算结果的存放位置,而不同于创建临时数组

# 指定输出,通过out字段指定存储位置
x = np.arange(6)
y = np.arange(6)

np.multiply(x, 10, out=y)
y

# 该特性也可以用在数组视图
y = np.zeros(12)

np.power(2, x, out=y[::2])
y

array([ 0, 10, 20, 30, 40, 50])
array([ 0, 10, 20, 30, 40, 50])
array([ 1.,  2.,  4.,  8., 16., 32.])
array([ 1.,  0.,  2.,  0.,  4.,  0.,  8.,  0., 16.,  0., 32.,  0.])

二元通用函数有些非常有趣的聚合功能,这些聚合可以直接在对象上计算

# 聚合
x = np.arange(1, 6)

np.add.reduce(x)
np.multiply.reduce(x)

# 如果需要存储每次计算的中间结果,则可使用accumulate
np.add.accumulate(x)

15
120
array([ 1,  3,  6, 10, 15], dtype=int32)

任何通用函数都可以用outer函数获取两个不同输入数组所有元素对的函数运算结果

# multiply与outer函数实现外积的计算
x = np.arange(1, 6)
np.multiply.outer(x, x)

array([[ 1,  2,  3,  4,  5],
       [ 2,  4,  6,  8, 10],
       [ 3,  6,  9, 12, 15],
       [ 4,  8, 12, 16, 20],
       [ 5, 10, 15, 20, 25]])

聚合:最小值、最大值和其他值

# 数组值求和
x = np.arange(10)

np.sum(x)

45
# 最大值与最小值
x = np.arange(10)

np.min(x)
np.max(x)

0
9

NumPy的聚合默认操作范围为整个数组,因此如需指定维度则用axis字段进行约束

# 多维度聚合
x = np.random.randint(0, 10, size=(4, 4))

x
x.sum()
x.sum(axis=0)
x.sum(axis=1)

array([[2, 0, 8, 9],
       [4, 8, 6, 1],
       [3, 1, 8, 5],
       [7, 9, 3, 5]])
79
array([16, 18, 25, 20])
array([19, 19, 17, 24])

NumPy的其他聚合函数以及NaN安全版本如下表所示(NaN版本在计算时会忽略所有缺失值NaN)

函数名称NaN安全版本描述
np.sumnp.nansum计算元素之和
np.prodnp.nanprod计算元素之积
np.meannp.nanmean计算元素平均值
np.stdnp.nanstd计算元素标准差
np.varnp.nanvar计算元素方差
np.minnp.nanmin计算最小值
np.maxnp.nanmax计算最大值
np.argminnp.nanargmin找出最小值索引
np.argmaxnp.nanargmax找出最大值索引
np.mediannp.nanmedian计算中位数
np.percentilenp.nanpercentile计算基于元素排序的统计值
np.anyN/A验证任何一个元素是否为真
np.allN/A验证所有元素是否为真

数组的计算:广播

NumPy通过通用函数的向量化操作减少缓慢的Python循环。NumPy还提供了另一种向量化操作:利用NumPy的广播功能。广播功能可以理解为用于不同大小数组的二进制通用函数(加减乘等)的一组规则

广播简介

# 加减乘
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

a + b

# 数组与标量相加
a + 5

array([5, 7, 9])
array([6, 7, 8])

广播操作可以理解为将标量或数组进行扩展,然后执行相应的操作

# 多维数组的广播机制
a = np.ones((2, 3))
b = np.arange(3)

a
b
a + b
a * b

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

有时可能发生两个数组同时广播,此时情况更加复杂

# 两个数组同时发生广播
a = np.arange(3)
b = np.arange(3)[:, np.newaxis]

a
b
a + b

array([0, 1, 2])
array([[0],
       [1],
       [2]])
array([[0, 1, 2],
       [1, 2, 3],
       [2, 3, 4]])

广播的规则

广播的规则如下:

  • 如果两个数组的维度数量不同,则小维度数组的形状将会在最左边补1
  • 如果两个数组的形状在任何一个维度上都不匹配,则数组的形状会沿着维度为1的维度扩展以匹配另外一个数组的形状
  • 如果两个数组的形状在任何一个维度上都不匹配且没有任何一个维度等于1,则引发异常

广播规则对于任任意二进制通用函数都是适用的,例如logaddexp等。

广播的实际应用

# 数组的归一化
x = np.random.random((10, 3))
xmean = x.mean(0)  # 沿着第一个维度聚合

x - xmean

array([[-0.25235933, -0.40876055, -0.29193434],
       [ 0.20706869, -0.40842629,  0.04335263],
       [ 0.32411636,  0.07717028,  0.08544746],
       [ 0.07033109,  0.46299066, -0.14045554],
       [-0.15462263, -0.05521411, -0.35915212],
       [-0.12088064, -0.18449039,  0.03603256],
       [ 0.20239461, -0.19075211, -0.19478297],
       [ 0.50400593, -0.09198252, -0.17657219],
       [-0.41733717,  0.45233086,  0.5438025 ],
       [-0.3627169 ,  0.34713416,  0.45426202]])
# 绘制二维函数

import matplotlib.pyplot as plt
x = np.linspace(0, 5, 50)
y = np.linspace(0, 5, 50)[:, np.newaxis]
z = np.sin(x)**10+np.cos(10+y*x)*np.cos(x)

x.shape, y.shape, z.shape

%matplotlib inline

plt.imshow(z, origin='lower', extent=[0, 5, 0, 5], cmap='viridis')
plt.colorbar()

((50,), (50, 1), (50, 50))
<matplotlib.image.AxesImage at 0x144eaa640d0>
<matplotlib.colorbar.Colorbar at 0x144eb12b310>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nD2cTt4k-1640344147213)(1NumPy%E5%85%A5%E9%97%A8_files/1NumPy%E5%85%A5%E9%97%A8_84_3.png)]

比较、掩码和布尔逻辑

当想基于某些准则抽取、修改、计数或对一个数组中的值进行其他操作时,掩码可以派上用场。

传统的统计方式是对所有数据循环,当碰到数据落在区间时计数器加1,但这是一种非常低效的方法。NumPy的通用函数能够替代循环,快速实现数组的逐元素运算。同样,我们也可以用其他通用函数实现数组的逐元素比较。

与通用函数类似的比较操作

x = np.array([0, 1, 2, 3, 4, 5])

# 比较操作
x < 3  # np.less
x > 3  # np.greater
x <= 3 # np.less_equal
x >= 3 # np.greater_equal
x != 3 # np.not_equal
x == 3 # np.equal

array([ True,  True,  True, False, False, False])
array([False, False, False, False,  True,  True])
array([ True,  True,  True,  True, False, False])
array([False, False, False,  True,  True,  True])
array([ True,  True,  True, False,  True,  True])
array([False, False, False,  True, False, False])

操作布尔数组

x = np.random.randint(0, 10, size=(3, 4))
x

# 统计True的个数
np.count_nonzero(x < 6)  # 统计布尔数组True的个数
np.sum(x < 6)
np.sum(x < 6, axis=1)  # sum函数能够指定维度进行统计

# 统计是否全为True
np.all(x < 6)
np.any(x < 6)
np.all(x < 6, axis=1)
np.any(x < 6, axis=1)

array([[2, 2, 4, 1],
       [5, 1, 2, 6],
       [2, 5, 4, 9]])
10
10
array([4, 3, 3])
False
True
array([ True, False, False])
array([ True,  True,  True])
# NumPy使用通用函数重载逻辑运算符
np.sum((x > 3) & (x < 8))
np.sum(~((x <= 3) | (x >= 8)))  # 与上式等价

5
5

逐位的布尔运算符与对应的通用函数对应关系如下表:

运算符对应通用函数
&np.bitwise_and
|np.bitwise_or
^np.bitwise_xor
~np.bitwise_not

将布尔数组作为掩码

x = np.random.randint(0, 10, size=(3, 4))

# 布尔数组作为掩码,选出对应元素
x
x < 5
x[x < 5]

array([[9, 2, 5, 9],
       [0, 7, 3, 6],
       [6, 2, 4, 5]])
array([[False,  True, False, False],
       [ True, False,  True, False],
       [False,  True,  True, False]])
array([2, 0, 3, 2, 4])

花哨的索引

在之前的小节中索引使用的都是简单的索引值、切片和布尔掩码,本节将使用索引数组快速获得并修复复杂的数组值的子数据集。

探索花哨的索引

需要注意的是,花哨的索引的结果与索引数组的形状一致,而不是被索引数组的形状。

x = np.random.randint(0, 10, size=(12))
y = x.reshape(-1, 4)
x
y

# 通过传递索引的单个列表或数组获取元素
index = [0, 2]
x[index]
y[index]

# 花哨的索引的结果与索引数组的形状一致(而不是被索引数组的形状)
index = np.array([[1, 1], [2, 2]])  # 注:这里用的是ndarray类型而不是list
x[index]

array([5, 4, 3, 4, 8, 1, 3, 3, 1, 9, 4, 1])
array([[5, 4, 3, 4],
       [8, 1, 3, 3],
       [1, 9, 4, 1]])
array([5, 3])
array([[5, 4, 3, 4],
       [1, 9, 4, 1]])
array([[4, 4],
       [3, 3]])
# 数组索引对多维数组同样适用,注意每个维度构建一个列表
row, col = [1, 2], [2, 3]
y[row, col]

array([3, 1])
# 数组索引时同样可以适用广播机制
row, col = np.array([1, 2]), np.array([2, 3])
y[row[:, np.newaxis], col]

array([[3, 3],
       [4, 1]])

组合索引

组合索引,即将多种索引方式组合适用

x = np.arange(12).reshape(-1, 4)
x

# 数组索引与简单索引组合
x[2, [1, 2]]
x[1:, [0, 3]]

array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
array([ 9, 10])
array([[ 4,  7],
       [ 8, 11]])
# 数组索引与掩码索引组合
mask = np.array([1, 0, 1, 0], dtype=np.bool8)
x[np.array([0, 2])[:, np.newaxis], mask]

array([[ 0,  2],
       [ 8, 10]])

用花哨的索引修改值

x = np.arange(10)
x

# 用花哨的索引修改值
index = np.array([1, 2, 3])
x[index] -= 9
x
x[index] = 11
x

array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
array([ 0, -8, -7, -6,  4,  5,  6,  7,  8,  9])
array([ 0, 11, 11, 11,  4,  5,  6,  7,  8,  9])

需要注意的是,操作中出现重复的索引可能导致意外:

x = np.zeros(10)
i = [1, 1, 2, 2, 2, 3, 3, 3, 3]

# 重复的索引导致意外的结果
x[i] += 1
x
array([0., 1., 1., 1., 0., 0., 0., 0., 0., 0.])

为了避免这种情况,可以使用at函数或reduceat函数

x = np.zeros(10)
i = [1, 1, 2, 2, 2, 3, 3, 3, 3]

# at函数:为给定位置、给定数值进行给定操作
np.add.at(x, i, 1)
x

array([0., 2., 3., 4., 0., 0., 0., 0., 0., 0.])

数组的排序

快速排序:np.sort和np.argsort

x = np.random.randint(0, 100, size=(12))
x

# np.sort排序元素值
np.sort(x)

# np.argsort排序索引值
np.argsort(x)

array([11,  0, 23, 92, 58, 57, 79, 28, 78,  5, 41, 92])
array([ 0,  5, 11, 23, 28, 41, 57, 58, 78, 79, 92, 92])
array([ 1,  9,  0,  2,  7, 10,  5,  4,  8,  6,  3, 11], dtype=int64)
x = x.reshape(3, 4)
x

# 多维数组的排序
np.sort(x, axis=1)

array([[11,  0, 23, 92],
       [58, 57, 79, 28],
       [78,  5, 41, 92]])
array([[ 0, 11, 23, 92],
       [28, 57, 58, 79],
       [ 5, 41, 78, 92]])

部分排序:分隔

有时我们不希望对整个数组进行排序,仅仅希望找到数组中第K小的值。np.partition函数提供了这一功能,其输入是数组和数字K,输出结果是一个新数组,最小的K个元素排列于数组前端,其余元素排列于数组后端,分隔开的两个数组内部无排序。

x = np.random.randint(0, 100, size=(20))
x

# np.partition
np.partition(x, 10)

# np.partition可沿着特定维度操作
x = x.reshape(4, -1)
np.partition(x, 2, axis=1)

array([92, 19, 75, 56, 98, 24,  9, 68, 99, 67, 41, 13, 52, 79, 81, 97, 56,
       94, 92, 63])
array([19, 63, 56, 56, 52, 24,  9, 13, 41, 67, 68, 75, 81, 79, 92, 92, 97,
       94, 98, 99])
array([[19, 56, 75, 92, 98],
       [ 9, 24, 67, 99, 68],
       [13, 41, 52, 79, 81],
       [56, 63, 92, 94, 97]])

正如np.sort对应有np.partitionnp.argsort也对应有np.argpartition

结构化数据:NumPy的结构化数组

NumPy的结构化数组和记录数组为复合的、异构的数据提供了有效的存储。

# 示例
name = ['A', 'B', 'C', 'D']
age = [11, 12, 13, 14]
weight = [55, 56, 57, 58]

data = np.zeros(4, dtype={
    'names': ('name', 'age', 'weight'),
    'formats': ('U10', 'i4', 'f8')
})
data['name'], data['age'], data['weight'] = name, age, weight

data
data['name']
data[0]
data[0]['name']
data[data['age'] < 13]['name']

array([('A', 11, 55.), ('B', 12, 56.), ('C', 13, 57.), ('D', 14, 58.)],
      dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f8')])
array(['A', 'B', 'C', 'D'], dtype='<U10')
('A', 11, 55.)
'A'
array(['A', 'B'], dtype='<U10')

生成结构化数组

# 采用字典
np.dtype({
    'names': ('name', 'age', 'weight'),
    'formats': ('U10', 'i4', 'f8')
})
dtype([('name', '<U10'), ('age', '<i4'), ('weight', '<f8')])
# 数值的类型可使用Python或NumpPy的类型指定
np.dtype({
    'names': ('name', 'age', 'weight'),
    'formats': ((np.str_, 10), int, np.float32)
})

dtype([('name', '<U10'), ('age', '<i4'), ('weight', '<f4')])
# 也可以采用元组列表
np.dtype([('name', 'U10'), ('age', 'i4'), ('weight', 'f8')])

dtype([('name', '<U10'), ('age', '<i4'), ('weight', '<f8')])
# 可省略类型名称
np.dtype('U10,i4,f8')

dtype([('f0', '<U10'), ('f1', '<i4'), ('f2', '<f8')])

NumPy数据类型简写规则:

  • 字符<和>分别表示小端和大端
  • 字符u、i、f等表示数据类型
  • 数字4、8等表示类型字节大小
NumPy数据类型符号描述
b字节型
i有符号整型
u无符号整型
f浮点型
c复数浮点型
S、a字符串
UUnicode编码字符串
V原生数据raw

更高级的复合类型

有时使用更高级的矩阵代替多维数组或Python字典,因为NumPy的dtype直接映射到C结构的定义,因此数组内容能够直接在C程序中使用。

# 更高级的复合类型
t = np.dtype([('id', 'i8'), ('mat', 'f8', (3, 3))])
x = np.zeros(4, dtype=t)

x[0]
x['mat']
x['mat'][0]

(0, [[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]])
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.],
        [0., 0., 0.]],

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

记录数组:结构化数组的扭转

NumPy提供了np.recarray类,其具有独特的性质为:域可以像属性一样获取,而不是像字典的键那样获取。记录数组的缺点在于会造成额外的开销。

data = np.zeros(4, dtype={
    'names': ('name', 'age', 'weight'),
    'formats': ('U10', 'i4', 'f8')
})
data['age']

# 记录数组
data_rec=data.view(np.recarray)
data_rec.age
array([0, 0, 0, 0])
array([0, 0, 0, 0])
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值