花哨的索引探索花哨的索引组合索引Example:选择随机点利用花哨索引修改值数组排序Numpy中的快速排序:np.sort,np.argsort部分排序:分割
花哨的索引和前面那些简单的索引非常类似, 但是传递的是索引数组, 而不是单个标量。花哨的索引让我们能够快速获得并修改复杂的数组值的子数据集。
花哨的索引在概念上非常简单, 它意味着传递一个索引数组来一次性获得多个数组元素。例如以下数组:
import numpy as np
rand = np.random.RandomState()
x = rand.randint(, size=)
print(x)
[ ]
# 获得三个不同元素,可以用以下方式实现
[x[], x[], x[]]
[, , ]
# 另一种方法是传递索引的单个列表或数组来获得同样的结果
ind = [, , ]
x[ind]
array([, , ])
# 数组的形状与索引数组的形状一样,与被索引数组形状不需要一样
ind = np.array([[, ],
[, ]])
x[ind]
array([[71, 86],
[60, 20]])
# 花哨索引也适用于多维度数组
X = np.arange().reshape((, ))
X
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
row = np.array([, , ])
col = np.array([, , ])
X[row, col]
array([ , , ])
这里需要注意, 结果的第一个值是 X[0, 2], 第二个值是 X[1, 1], 第三个值是 X[2, 3]。在花哨的索引中, 索引值的配对遵循广播的规则。因此当我们将一个列向量和一个行向量组合在一个索引中时, 会得到一个二维的结果:
X[row[:, np.newaxis], col]
array([[ 2, 1, 3],
[ 6, 5, 7],
[10, 9, 11]])
row[:, np.newaxis] * col
array([[0, 0, 0],
[2, 1, 3],
[4, 2, 6]])
花哨的索引可以和其他索引方案结合起来形成更强大的索引操作:
print(X)
[[ ]
[ ]
[ ]]
# 花哨索引和普通索引组合使用
X[, [, , ]]
array([, , ])
# 花哨索引和切片组合使用
X[:, [, , ]]
array([[ 6, 4, 5],
[10, 8, 9]])
# 花哨索引和掩码组合使用
mask = np.array([, , , ], dtype=bool)
X[row[:, np.newaxis], mask]
array([[ 0, 2],
[ 4, 6],
[ 8, 10]])
# 以下是二维正态分布组成的数组
mean = [, ]
cov = [[, ],
[, ]]
X = rand.multivariate_normal(mean, cov, )
X.shape
(100, 2)
# 可视化
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn; seaborn.set() # for plot styling
plt.scatter(X[:, ], X[:, ]);
# 利用花哨索引随机选择20个不重复的索引值
indices = np.random.choice(X.shape[], , replace=False)
indices
array([, , , , , , , , , , , , , , , , ,
, , ])
selection = X[indices]
selection.shape
(20, 2)
plt.scatter(X[:, ], X[:, ], alpha=0.3)
plt.scatter(selection[:, ], selection[:, ],
facecolor='none', s=);
正如花哨的索引可以被用于获取部分数组, 它也可以被用于修改部分数组。例如, 假设我们有一个索引数组, 并且希望设置数组中对应的值:
x = np.arange()
i = np.array([, , , ])
x[i] =
print(x)
[ ]
# 可以使用任何赋值语句
x[i] -=
print(x)
[ ]
# 操作中重复出现的索引会导致出乎意料的结果产生
x = np.zeros()
x[[, ]] = [, ]
print(x)
[6. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
这个操作首先将x[0]=4,然后赋值x[0]=6
# 下面的结果和你想象的一样吗?思考下为什么
i = [, , , , , ]
x[i] +=
x
array([6., 0., 1., 1., 1., 0., 0., 0., 0., 0.])
你可能期望 x[3] 的值为 2, x[4] 的值为 3, 因为这是这些索引值重复的次数。但是为什么结果不同于我们的预想呢?从概念的角度理解, 这是因为 x[i] += 1 是 x[i] = x[i] + 1 的简写。x[i] + 1 计算后,这个结果被赋值给了 x 相应的索引值。记住这个原理后, 我们却发现数组并没有发生多次累加, 而是发生了赋值, 显然这不是我们希望的结果。
因此, 如果你希望累加, 该怎么做呢?你可以借助通用函数中的 at()方法来实现。进行如下操作:
x = np.zeros()
np.add.at(x, i, )
print(x)
[0. 1. 1. 0. 1. 0. 0. 0. 1. 0.]
at() 函数在这里对给定的操作、 给定的索引(这里是 i) 以及给定的值(这里是 1) 执行的是就地操作。另一个可以实现该功能的类似方法是通用函数中的 reduceat() 函数, 你可以在 NumPy 文档中找到关于该函数的更多信息。
例如, 一个简单的选择排序重复寻找列表中的最小值, 并且不断交换直到列表是有序的。可以在 Python 中仅用几行代码来实现:
# 用Python代码实现选择排序
import numpy as np
def selection_sort(x):
for i in range(len(x)):
swap = i + np.argmin(x[i:])
(x[i], x[swap]) = (x[swap], x[i])
return x
x = np.array([, , , , ])
selection_sort(x)
array([, , , , ])
默认情况下, np.sort 的排序算法是 快速排序, 其算法复杂度为[N log N], 另外也可以选择归并排序和堆排序。对于大多数应用场景, 默认的快速排序已经足够高效了。
x = np.array([, , , , ])
np.sort(x)
array([, , , , ])
# 可以使用排好序的数组代替原数组
x.sort()
print(x)
[ ]
# np.argsort返回的是原来数组排好序的索引值
x = np.array([, , , , ])
i = np.argsort(x)
print(i)
[ ]
# 通过花哨索引创建有序数组
x[i]
array([, , , , ])
沿着行或列排序
通过axis参数,沿着多维数组的行或列进行排序,这种操作将会丢失行或列值之间的关系
rand = np.random.RandomState()
X = rand.randint(, , (, ))
print(X)
[[ ]
[ ]
[ ]
[ ]]
# 对每一列进行排序
np.sort(X, axis=)
array([[2, 1, 4, 0, 1, 5],
[5, 2, 5, 4, 3, 7],
[6, 3, 7, 4, 6, 7],
[7, 6, 7, 4, 9, 9]])
# 对每一行进行排序
np.sort(X, axis=)
array([[3, 4, 6, 6, 7, 9],
[2, 3, 4, 6, 7, 7],
[1, 2, 4, 5, 7, 7],
[0, 1, 4, 5, 5, 9]])
np.partition输入的是数组和数字K,输出结果是一个新数组,新数组最左边排列的是K个最小的值,往右是任意顺序的其他值
x = np.array([, , , , , , ])
np.partition(x, )
array([, , , , , , ])
请注意, 结果数组中前三个值是数组中最小的三个值, 剩下的位置是原始数组剩下的值。在这两个分隔区间中, 元素都是任意排列的。 与排序类似, 也可以沿着多维数组任意的轴进行分隔:
# 与排序类似也可以沿着多维数组的任意轴进行分割
np.partition(X, , axis=)
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有