前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Numpy中的索引与排序

Numpy中的索引与排序

作者头像
用户3577892
发布2020-06-12 16:34:27
发布2020-06-12 16:34:27
2.6K00
代码可运行
举报
文章被收录于专栏:数据科学CLUB数据科学CLUB
运行总次数:0
代码可运行

花哨的索引探索花哨的索引组合索引Example:选择随机点利用花哨索引修改值数组排序Numpy中的快速排序:np.sort,np.argsort部分排序:分割

花哨的索引

花哨的索引和前面那些简单的索引非常类似, 但是传递的是索引数组, 而不是单个标量。花哨的索引让我们能够快速获得并修改复杂的数组值的子数据集。

探索花哨的索引

花哨的索引在概念上非常简单, 它意味着传递一个索引数组来一次性获得多个数组元素。例如以下数组:

代码语言:javascript
代码运行次数:0
运行
复制
import numpy as np
rand = np.random.RandomState()

x = rand.randint(, size=)
print(x)
代码语言:javascript
代码运行次数:0
运行
复制
[         ]
代码语言:javascript
代码运行次数:0
运行
复制
# 获得三个不同元素,可以用以下方式实现
[x[], x[], x[]]
代码语言:javascript
代码运行次数:0
运行
复制
[, , ]
代码语言:javascript
代码运行次数:0
运行
复制
# 另一种方法是传递索引的单个列表或数组来获得同样的结果
ind = [, , ]
x[ind]
代码语言:javascript
代码运行次数:0
运行
复制
array([, , ])
代码语言:javascript
代码运行次数:0
运行
复制
# 数组的形状与索引数组的形状一样,与被索引数组形状不需要一样
ind = np.array([[, ],
                [, ]])
x[ind]
代码语言:javascript
代码运行次数:0
运行
复制
array([[71, 86],
       [60, 20]])
代码语言:javascript
代码运行次数:0
运行
复制
# 花哨索引也适用于多维度数组
X = np.arange().reshape((, ))
X
代码语言:javascript
代码运行次数:0
运行
复制
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
代码语言:javascript
代码运行次数:0
运行
复制
row = np.array([, , ])
col = np.array([, , ])
X[row, col]
代码语言:javascript
代码运行次数:0
运行
复制
array([ ,  , ])

这里需要注意, 结果的第一个值是 X[0, 2], 第二个值是 X[1, 1], 第三个值是 X[2, 3]。在花哨的索引中, 索引值的配对遵循广播的规则。因此当我们将一个列向量和一个行向量组合在一个索引中时, 会得到一个二维的结果:

代码语言:javascript
代码运行次数:0
运行
复制
X[row[:, np.newaxis], col]
代码语言:javascript
代码运行次数:0
运行
复制
array([[ 2,  1,  3],
       [ 6,  5,  7],
       [10,  9, 11]])
代码语言:javascript
代码运行次数:0
运行
复制
row[:, np.newaxis] * col
代码语言:javascript
代码运行次数:0
运行
复制
array([[0, 0, 0],
       [2, 1, 3],
       [4, 2, 6]])

组合索引

花哨的索引可以和其他索引方案结合起来形成更强大的索引操作:

代码语言:javascript
代码运行次数:0
运行
复制
print(X)
代码语言:javascript
代码运行次数:0
运行
复制
[[       ]
 [       ]
 [     ]]
代码语言:javascript
代码运行次数:0
运行
复制
# 花哨索引和普通索引组合使用
X[, [, , ]]
代码语言:javascript
代码运行次数:0
运行
复制
array([,  ,  ])
代码语言:javascript
代码运行次数:0
运行
复制
# 花哨索引和切片组合使用
X[:, [, , ]]
代码语言:javascript
代码运行次数:0
运行
复制
array([[ 6,  4,  5],
       [10,  8,  9]])
代码语言:javascript
代码运行次数:0
运行
复制
# 花哨索引和掩码组合使用
mask = np.array([, , , ], dtype=bool)
X[row[:, np.newaxis], mask]
代码语言:javascript
代码运行次数:0
运行
复制
array([[ 0,  2],
       [ 4,  6],
       [ 8, 10]])

Example:选择随机点

  • 这种方法常用于分割数据集
代码语言:javascript
代码运行次数:0
运行
复制
# 以下是二维正态分布组成的数组
mean = [, ]
cov = [[, ],
       [, ]]
X = rand.multivariate_normal(mean, cov, )
X.shape
代码语言:javascript
代码运行次数:0
运行
复制
(100, 2)
代码语言:javascript
代码运行次数:0
运行
复制
# 可视化
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn; seaborn.set()  # for plot styling

plt.scatter(X[:, ], X[:, ]);
代码语言:javascript
代码运行次数:0
运行
复制
# 利用花哨索引随机选择20个不重复的索引值
indices = np.random.choice(X.shape[], , replace=False)
indices
代码语言:javascript
代码运行次数:0
运行
复制
array([, , , , , , , , , , , , , , , ,  ,
       , ,  ])
代码语言:javascript
代码运行次数:0
运行
复制
selection = X[indices]  
selection.shape
代码语言:javascript
代码运行次数:0
运行
复制
(20, 2)
代码语言:javascript
代码运行次数:0
运行
复制
plt.scatter(X[:, ], X[:, ], alpha=0.3)
plt.scatter(selection[:, ], selection[:, ],
            facecolor='none', s=);

利用花哨索引修改值

正如花哨的索引可以被用于获取部分数组, 它也可以被用于修改部分数组。例如, 假设我们有一个索引数组, 并且希望设置数组中对应的值:

代码语言:javascript
代码运行次数:0
运行
复制
x = np.arange()
i = np.array([, , , ])
x[i] = 
print(x)
代码语言:javascript
代码运行次数:0
运行
复制
[               ]
代码语言:javascript
代码运行次数:0
运行
复制
# 可以使用任何赋值语句
x[i] -= 
print(x)
代码语言:javascript
代码运行次数:0
运行
复制
[               ]
代码语言:javascript
代码运行次数:0
运行
复制
# 操作中重复出现的索引会导致出乎意料的结果产生
x = np.zeros()
x[[, ]] = [, ]
print(x)
代码语言:javascript
代码运行次数:0
运行
复制
[6. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

这个操作首先将x[0]=4,然后赋值x[0]=6

代码语言:javascript
代码运行次数:0
运行
复制
# 下面的结果和你想象的一样吗?思考下为什么
i = [, , , , , ]
x[i] += 
x
代码语言:javascript
代码运行次数:0
运行
复制
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()方法来实现。进行如下操作:

代码语言:javascript
代码运行次数:0
运行
复制
x = np.zeros()
np.add.at(x, i, )
print(x)
代码语言:javascript
代码运行次数:0
运行
复制
[0. 1. 1. 0. 1. 0. 0. 0. 1. 0.]

at() 函数在这里对给定的操作、 给定的索引(这里是 i) 以及给定的值(这里是 1) 执行的是就地操作。另一个可以实现该功能的类似方法是通用函数中的 reduceat() 函数, 你可以在 NumPy 文档中找到关于该函数的更多信息。

数组排序

例如, 一个简单的选择排序重复寻找列表中的最小值, 并且不断交换直到列表是有序的。可以在 Python 中仅用几行代码来实现:

代码语言:javascript
代码运行次数:0
运行
复制
# 用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
代码语言:javascript
代码运行次数:0
运行
复制
x = np.array([, , , , ])
selection_sort(x)
代码语言:javascript
代码运行次数:0
运行
复制
array([, , , , ])

Numpy中的快速排序:np.sort,np.argsort

默认情况下, np.sort 的排序算法是 快速排序, 其算法复杂度为[N log N], 另外也可以选择归并排序和堆排序。对于大多数应用场景, 默认的快速排序已经足够高效了。

代码语言:javascript
代码运行次数:0
运行
复制
x = np.array([, , , , ])
np.sort(x)
代码语言:javascript
代码运行次数:0
运行
复制
array([, , , , ])
代码语言:javascript
代码运行次数:0
运行
复制
# 可以使用排好序的数组代替原数组
x.sort()
print(x)
代码语言:javascript
代码运行次数:0
运行
复制
[    ]
代码语言:javascript
代码运行次数:0
运行
复制
# np.argsort返回的是原来数组排好序的索引值
x = np.array([, , , , ])
i = np.argsort(x)
print(i)
代码语言:javascript
代码运行次数:0
运行
复制
[    ]
代码语言:javascript
代码运行次数:0
运行
复制
# 通过花哨索引创建有序数组
x[i]
代码语言:javascript
代码运行次数:0
运行
复制
array([, , , , ])

沿着行或列排序

通过axis参数,沿着多维数组的行或列进行排序,这种操作将会丢失行或列值之间的关系

代码语言:javascript
代码运行次数:0
运行
复制
rand = np.random.RandomState()
X = rand.randint(, , (, ))
print(X)
代码语言:javascript
代码运行次数:0
运行
复制
[[     ]
 [     ]
 [     ]
 [     ]]
代码语言:javascript
代码运行次数:0
运行
复制
# 对每一列进行排序
np.sort(X, axis=)
代码语言:javascript
代码运行次数:0
运行
复制
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]])
代码语言:javascript
代码运行次数:0
运行
复制
# 对每一行进行排序
np.sort(X, axis=)
代码语言:javascript
代码运行次数:0
运行
复制
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个最小的值,往右是任意顺序的其他值

代码语言:javascript
代码运行次数:0
运行
复制
x = np.array([, , , , , , ])
np.partition(x, )
代码语言:javascript
代码运行次数:0
运行
复制
array([, , , , , , ])

请注意, 结果数组中前三个值是数组中最小的三个值, 剩下的位置是原始数组剩下的值。在这两个分隔区间中, 元素都是任意排列的。 与排序类似, 也可以沿着多维数组任意的轴进行分隔:

代码语言:javascript
代码运行次数:0
运行
复制
# 与排序类似也可以沿着多维数组的任意轴进行分割
np.partition(X, , axis=)
代码语言:javascript
代码运行次数:0
运行
复制
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据科学CLUB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 花哨的索引
    • 探索花哨的索引
    • 组合索引
    • Example:选择随机点
    • 利用花哨索引修改值
  • 数组排序
    • Numpy中的快速排序:np.sort,np.argsort
    • 部分排序:分割
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档