第89天:NumPy 排序和筛选函数

简介: 第89天:NumPy 排序和筛选函数

对于数据分析来说,排序和筛选数据是不可或缺的一部分内容。NumPy 也提供了多种排序和筛选函数,本文就来介绍一下 NumPy 常见的排序和筛选函数。


排序函数


NumPy 中提供了排序相关的函数。排序函数已经帮助我们实现了不同的排序算法,我们只需要拿来直接使用就行。每个排序算法的执行速度,时间复杂度,空间复杂度和算法的稳定性都不相同,我们来看看常见的几种排序算法的比较。


排序算法 速度 时间复杂度 空间复杂度 稳定性
quicksort(快速排序) 1 o(n^2) 0
mergesort(归并排序) 2 O(n*log(n)) ~n/2
heapsort(堆排序) 3 O(n*log(n)) 0


numpy.sort(a, axis, kind, order)


这个排序函数有4个参数,我们来看看参数的说明:


参数 说明
a 要排序的数组
axis 排序数组的轴,如果没有数组会被展开,沿着最后的轴排序。axis=0 按列排序,axis=1 按行排序
kind 排序类型,有 quicksortmergesortheapsortstable 几种,默认为quicksort(快速排序)
order 排序的字段,针对包含字段的数组

我们来看看实例:



import numpy as npimport time
a = np.array([[3, 7, 12, 45], [9, 1, 0, 34]])print("初始数组:")print(a)print('\n')
print(np.char.center('调用 sort() 函数,默认快速排序', 15, '*'))print(np.sort(a))print('\n')
print(np.char.center('按列排序', 15, '*'))print(np.sort(a, axis=0))print('\n')
b = np.random.randint(1, 1000, size=[10000, 10000])
print(np.char.center('快速排序时间', 15, '*'))t1 = time.time()np.sort(b)t2 = time.time()print(t2 - t1)print('\n')
print(np.char.center('堆排序时间', 15, '*'))t3 = time.time()np.sort(b, -1, 'heapsort')t4 = time.time()print(t4 - t3)print('\n')
print(np.char.center('归并排序时间', 15, '*'))t5 = time.time()np.sort(b, -1, 'mergesort')t6 = time.time()print(t6 - t5)print('\n')
# 根据字段排序dt = np.dtype([('name', 'S10'), ('age', int)])c = np.array([("raju", 21), ("anil", 25), ("ravi", 17), ("amar", 27)], dtype=dt)print(np.char.center('根据字段排序的数组', 15, '*'))print(c)print('\n')
print(np.char.center('按 name 排序', 15, '*'))print(np.sort(c, order='name'))
# 返回初始数组:[[ 3  7 12 45] [ 9  1  0 34]] 调用 sort() 函数,默认[[ 3  7 12 45] [ 0  1  9 34]] ******按列排序*****[[ 3  1  0 34] [ 9  7 12 45]] *****快速排序时间****5.470074892044067
*****堆排序时间*****6.988600015640259
*****归并排序时间****5.784327983856201
***根据字段排序的数组***[(b'raju', 21) (b'anil', 25) (b'ravi', 17) (b'amar', 27)]
***按 name 排序***[(b'amar', 27) (b'anil', 25) (b'raju', 21) (b'ravi', 17)]


在例子中,我们首先使用了默认的按横轴的快速排序算法,可以看到每个数组都是横向排序的。


接下来,我们多加了一个排序的参数,表示按纵轴排序,我们可以从结果中看到,两个数组中对应位置的元素都按照升序排列了。


接着我们随机生成了一个数据量大的多维数组,然后使用三种排序方式,打印了它们排序的时间,从结果中我们可以看到快速排序最快,其次是归并排序,最后是堆排序。需要注意一点的是,有些排序算法不稳定,可能会导致每次运行的结果不一样。另外,数据量也可能会影响不同排序算法排序的效率。


最后我们创建了一个带字段的数组,然后按照 name 字段排序。


numpy.argsort()


函数对输入数组沿给定轴执行间接排序,并使用指定排序类型返回数据的索引数组。这个索引数组用于构造排序后的数组。


我们来看实例:



import numpy as np
a = np.array([3, 4, 2])print("初始数组:")print(a)print('\n')
print(np.char.center('调用 argsort() 函数', 15, '*'))b = np.argsort(a)print(b)print('\n')
print(np.char.center('以排序后的顺序重构原数组', 15, '*'))print(a[b])print('\n')
# 返回初始数组:[3 4 2]
调用 argsort() 函数[2 0 1]
**以排序后的顺序重构原数组*[2 3 4]


在上面例子中,我们调用 argsort() 函数后,返回了初始数组的排序后的索引。然后我们用排序后的索引数组重构原数组,得到排序后的数组。


numpy.lexsort()


函数使用键序列执行间接排序。键可以看作是电子表格中的一列。该函数返回一个索引数组,使用它可以获得排序数据。注意,最后一个键恰好是 sort 的主键。


对于这个函数,我们假设一种场景:现在有语文和数学考试成绩以及总成绩,我们需要对成绩做个排序,排序原则为总分优先,总分相同则语文高的排前面。

实现的代码如下:




















import numpy as np
print(np.char.center('lexsort() 函数', 15, '*'))# 录入了四位同学的成绩math = (10, 20, 50, 10)chinese = (30, 50, 40, 60)total = (40, 70, 90, 70)# 将优先级高的项放在后面ind = np.lexsort((math, chinese, total))
for i in ind:    print(total[i], chinese[i], math[i])    # 返回**lexsort() 函数*40 30 1070 50 2070 60 1090 40 50

例子中我们将参数由优先级从低到高传入,优先级最高的放在最后。最后得到4个同学的成绩排序。

numpy.msort()

数组按第一个轴排序,返回排序后的数组副本。

这个排序相当于 numpy.sort(a, axis=0)。很好理解。我们直接来看实例:


import numpy as np
print(np.char.center('msort() 函数', 20, '*'))msa = np.array([[3, 7, 12, 45], [9, 1, 0, 34]])print(np.msort(msa))
# 返回*****msort() 函数*****[[ 3  1  0 34] [ 9  7 12 45]]


numpy.partition()


指定一个数,对数组进行分区。


通俗点说,就是指定一个数,以这个数为中心,将其他数分别放在这个数的两边。

我们来看实例:


import numpy as np
print(np.char.center('partition() 函数', 20, '*'))pta = np.array([3, 7, 12, 45, 15, 0])print(np.partition(pta, 2))print('\n')print(np.partition(pta, (2, 4)))print('\n')
# 返回***partition() 函数***[ 0  3  7 45 15 12][ 0  3  7 12 15 45]


在第一次排序时,我们选中了索引为2的数字7作为中心,将小于7的数放在左边,大于7的数放在右边。在第二次排序时,我们选择了索引为2的数字7和索引为4的数字45,将小于7的数放在左边,大于7小于45的数放在中间,大于45的数放在右边。


查找函数


下面我们来看几个常见的查找函数,这些函数用于在数组中查找特定条件的元素。


numpy.argmax()


返回沿给定轴的最大值索引。


注意,索引的值是从0开始计算的。


我们来看实例:




import numpy as np
a = np.array([[30, 40, 70], [80, 20, 10], [50, 90, 60]])print(np.char.center('初始数组', 20, '*'))print(a)print('\n')
print(np.char.center('调用 argmax() 函数', 20, '*'))print(np.argmax(a))print('\n')
print(np.char.center('展开数组', 20, '*'))print(a.flatten())print('\n')
print(np.char.center('沿0轴的最大索引', 20, '*'))print(np.argmax(a, 0))print('\n')
print(np.char.center('沿1轴的最大索引', 20, '*'))print(np.argmax(a, 1))print('\n')
# 返回********初始数组********[[30 40 70] [80 20 10] [50 90 60]]***调用 argmax() 函数***7********展开数组********[30 40 70 80 20 10 50 90 60]******沿0轴的最大索引******[1 2 0]******沿1轴的最大索引******[2 0 1]


numpy.argmin()


返回沿给定轴的最小值索引。


注意,索引的值是从0开始计算的。


我们来看实例:


import numpy as np
a = np.array([[30, 40, 70], [80, 20, 10], [50, 90, 60]])print(np.char.center('初始数组', 20, '*'))print(a)print('\n')
print(np.char.center('调用 argmin() 函数', 20, '*'))print(np.argmin(a))print('\n')
print(np.char.center('沿0轴的最小索引', 20, '*'))print(np.argmin(a, 0))print('\n')
print(np.char.center('沿1轴的最小索引', 20, '*'))print(np.argmin(a, 1))print('\n')
# 返回********初始数组********[[30 40 70] [80 20 10] [50 90 60]]***调用 argmin() 函数***5******沿0轴的最小索引******[0 1 1]******沿1轴的最小索引******[0 2 0]


numpy.nonzero()


返回输入数组中非零元素的索引。

  • 只有a中非零元素才会有索引值,那些零值元素没有索引值;
  • 返回的索引值数组是一个2维tuple数组,该tuple数组中包含一维的array数组。其中,一维array向量的个数与a的维数是一致的。
  • 索引值数组的每一个array均是从一个维度上来描述其索引值。比如,如果a是一个二维数组,则索引值数组有两个array,第一个 array 从行维度来描述索引值;第二个array从列维度来描述索引值。
  • 该np.transpose(np.nonzero(x)) 函数能够描述出每一个非零元素在不同维度的索引值。


我们来看实例:




import numpy as np
b = np.array([[30, 40, 0], [0, 20, 10], [50, 0, 60]])print(np.char.center('我们的数组是', 20, '*'))print(b)print(np.char.center('调用 nonzero() 函数', 20, '*'))c = np.nonzero(b)print(c)print(np.transpose(np.nonzero(b)))
# 返回*******我们的数组是*******[[30 40  0] [ 0 20 10] [50  0 60]]**调用 nonzero() 函数***(array([0, 0, 1, 1, 2, 2]), array([0, 1, 1, 2, 0, 2]))[[0 0] [0 1] [1 1] [1 2] [2 0] [2 2]]


我们通过 np.transpose() 方法转换后看起来比较直观,注意这里的索引是从0开始算的。


numpy.where()


返回输入数组中满足给定条件的元素的索引。

我们来看实例:



import numpy as np
b = np.array([[30, 40, 0], [0, 20, 10], [50, 0, 60]])
print(np.char.center('调用 where() 函数', 20, '*'))print(np.where(b > 20))print(np.transpose(np.where(b > 20)))
# 返回***调用 where() 函数****(array([0, 0, 2, 2]), array([0, 1, 0, 2]))[[0 0] [0 1] [2 0] [2 2]]


这里面我们输入的条件是大于20,数组中大于20的数的索引都被查找出来了。


numpy.extract()


根据某个条件从数组中抽取元素,返回满条件的元素。


我们来看实例:



import numpy as np
x = np.arange(9.).reshape(3,  3)print(np.char.center('我们的数组是', 20, '*'))print(x)# 定义条件, 选择偶数元素condition = np.mod(x, 2) == 0print(np.char.center('按元素的条件值', 20, '*'))print(condition)print(np.char.center('使用条件提取元素', 20, '*'))print(np.extract(condition, x))
# 返回*******我们的数组是*******[[0. 1. 2.] [3. 4. 5.] [6. 7. 8.]]******按元素的条件值*******[[ True False  True] [False  True False] [ True False  True]]******使用条件提取元素******[0. 2. 4. 6. 8.]


例子中,我们先定义了一个条件,就是选择偶数。然后我们可以打印这个数组每个元素是否满足条件。最后我们调用 extract() 方法返回满足条件的元素。注意这里返回的是元素,而不是元素的索引。


总结


本文向大家介绍了 NumPy 的排序与筛选函数,熟练掌握和运用这些函数可以很轻松地帮助我们达到特定的目标,而不用自己去重复造轮子。大家在后续的代码中遇到类似的情况应该要优先想到这些函数。


参考

https://numpy.org/devdocs/reference/routines.sort.html

文中示例代码:python-100-days


系列文章


第 87 天:Python Web开发 OAuth2.0 简介

第 86 天:Python SQLAlchemy

第 85 天:NumPy 统计函数

第 84 天:NumPy 数学函数

第 83 天:NumPy 字符串操作

第 82 天:Python Web 开发之 JWT 简介

第 81 天:NumPy Ndarray 对象及数据类型

从 0 学习 Python 0 - 80 大合集总结


目录
相关文章
|
1月前
|
Python
Numpy学习笔记(五):np.concatenate函数和np.append函数用于数组拼接
NumPy库中的`np.concatenate`和`np.append`函数,它们分别用于沿指定轴拼接多个数组以及在指定轴上追加数组元素。
30 0
Numpy学习笔记(五):np.concatenate函数和np.append函数用于数组拼接
|
2月前
|
机器学习/深度学习 搜索推荐 算法
NumPy 教程 之 NumPy 排序、条件筛选函数 8
NumPy提供了多种排序方法,包括快速排序、归并排序及堆排序,各有不同的速度、最坏情况性能、工作空间和稳定性特点。此外,NumPy还提供了`numpy.extract()`函数,可以根据特定条件从数组中抽取元素。例如,在一个3x3数组中,通过定义条件选择偶数元素,并使用该函数提取这些元素。示例输出为:[0., 2., 4., 6., 8.]。
26 8
|
2月前
|
机器学习/深度学习 搜索推荐 算法
NumPy 教程 之 NumPy 排序、条件筛选函数 5
NumPy中的排序方法及特性对比,包括快速排序、归并排序与堆排序的速度、最坏情况性能、工作空间及稳定性分析。并通过`numpy.argmax()`与`numpy.argmin()`函数演示了如何获取数组中最大值和最小值的索引,涵盖不同轴方向的操作,并提供了具体实例与输出结果,便于理解与实践。
26 5
|
2月前
|
算法 索引 Python
Numpy 的一些以 arg 开头的函数
Numpy 的一些以 arg 开头的函数
42 0
|
2月前
|
机器学习/深度学习 数据处理 Python
从NumPy到Pandas:轻松转换Python数值库与数据处理利器
从NumPy到Pandas:轻松转换Python数值库与数据处理利器
80 0
|
3月前
|
机器学习/深度学习 数据处理 计算机视觉
NumPy实践宝典:Python高手教你如何轻松玩转数据处理!
【8月更文挑战第22天】NumPy是Python科学计算的核心库,专长于大型数组与矩阵运算,并提供了丰富的数学函数。首先需安装NumPy (`pip install numpy`)。之后可通过创建数组、索引与切片、执行数学与逻辑运算、变换数组形状及类型、计算统计量和进行矩阵运算等操作来实践学习。NumPy的应用范围广泛,从基础的数据处理到图像处理都能胜任,是数据科学领域的必备工具。
60 0
|
24天前
|
存储 数据处理 Python
Python科学计算:NumPy与SciPy的高效数据处理与分析
【10月更文挑战第27天】在科学计算和数据分析领域,Python凭借简洁的语法和强大的库支持广受欢迎。NumPy和SciPy作为Python科学计算的两大基石,提供了高效的数据处理和分析工具。NumPy的核心功能是N维数组对象(ndarray),支持高效的大型数据集操作;SciPy则在此基础上提供了线性代数、信号处理、优化和统计分析等多种科学计算工具。结合使用NumPy和SciPy,可以显著提升数据处理和分析的效率,使Python成为科学计算和数据分析的首选语言。
29 3
|
25天前
|
存储 机器学习/深度学习 算法
Python科学计算:NumPy与SciPy的高效数据处理与分析
【10月更文挑战第26天】NumPy和SciPy是Python科学计算领域的两大核心库。NumPy提供高效的多维数组对象和丰富的数学函数,而SciPy则在此基础上提供了更多高级的科学计算功能,如数值积分、优化和统计等。两者结合使Python在科学计算中具有极高的效率和广泛的应用。
41 2
|
2月前
|
机器学习/深度学习 算法 数据可视化
8种数值变量的特征工程技术:利用Sklearn、Numpy和Python将数值转化为预测模型的有效特征
特征工程是机器学习流程中的关键步骤,通过将原始数据转换为更具意义的特征,增强模型对数据关系的理解能力。本文重点介绍处理数值变量的高级特征工程技术,包括归一化、多项式特征、FunctionTransformer、KBinsDiscretizer、对数变换、PowerTransformer、QuantileTransformer和PCA,旨在提升模型性能。这些技术能够揭示数据中的潜在模式、优化变量表示,并应对数据分布和内在特性带来的挑战,从而提高模型的稳健性和泛化能力。每种技术都有其独特优势,适用于不同类型的数据和问题。通过实验和验证选择最适合的变换方法至关重要。
47 5
8种数值变量的特征工程技术:利用Sklearn、Numpy和Python将数值转化为预测模型的有效特征
|
1月前
|
机器学习/深度学习 并行计算 大数据
【Python篇】NumPy完整指南(上篇):掌握数组、矩阵与高效计算的核心技巧2
【Python篇】NumPy完整指南(上篇):掌握数组、矩阵与高效计算的核心技巧
75 10