pin_drop当前位置:知识文库 ❯ 图文
NumPy数组排序详解 - sort/argsort/partition
一、概述
NumPy提供了多种排序函数,支持沿指定轴排序、部分排序、稳定排序等。np.sort()返回排序后的副本,np.argsort()返回排序索引,np.partition()用于部分排序(如找前K个最小值)。
理解不同排序函数的特点和参数,可以在不同场景下选择最优方案。例如Top-K问题使用partition比全排序效率更高。
二、语法与常用函数
代码示例
np.sort(a, axis=-1, kind='quicksort')
np.argsort(a, axis=-1, kind='quicksort')
np.partition(a, kth, axis=-1)
np.argpartition(a, kth, axis=-1)
np.searchsorted(a, v)
arr.sort() # 原地排序三、参数说明
np.sort参数
排序算法
四、基本排序
np.sort()返回排序后的数组副本,不修改原数组。arr.sort()原地排序,直接修改原数组。
代码示例
import numpy as np
arr = np.array([42, 15, 8, 23, 16, 4, 31])
# np.sort:返回排序副本
sorted_arr = np.sort(arr)
print(f"原数组: {arr}")
print(f"排序后: {sorted_arr}")
# 降序排序
sorted_desc = np.sort(arr)[::-1]
print(f"降序: {sorted_desc}")
# 原地排序
arr2 = np.array([42, 15, 8, 23, 16])
arr2.sort()
print(f"原地排序: {arr2}")输出结果:
代码示例
原数组: [42 15 8 23 16 4 31]
排序后: [ 4 8 15 16 23 31 42]
降序: [42 31 23 16 15 8 4]
原地排序: [ 8 15 16 23 42]五、多维数组排序与argsort
多维数组排序可通过axis参数指定排序方向。axis=0沿列排序,axis=1沿行排序,axis=None展平后排序。argsort()返回排序后的索引数组,可用于对关联数组进行同步排序。
代码示例
import numpy as np
arr = np.array([[3, 1, 4], [1, 5, 9], [2, 6, 5]])
print(f"原数组:\n{arr}")
# 沿行排序(每行内部排序)
print(f"\naxis=1(每行排序):\n{np.sort(arr, axis=1)}")
# 沿列排序(每列内部排序)
print(f"\naxis=0(每列排序):\n{np.sort(arr, axis=0)}")
# 展平排序
print(f"\n展平排序: {np.sort(arr, axis=None)}")
# argsort:获取排序索引
arr1d = np.array([30, 10, 20])
indices = np.argsort(arr1d)
print(f"\n原数组: {arr1d}")
print(f"排序索引: {indices}")
print(f"通过索引排序: {arr1d[indices]}")输出结果:
代码示例
原数组:
[[3 1 4]
[1 5 9]
[2 6 5]]
axis=1(每行排序):
[[1 3 4]
[1 5 9]
[2 5 6]]
axis=0(每列排序):
[[1 1 4]
[2 5 5]
[3 6 9]]
展平排序: [1 1 2 3 4 5 5 6 9]
原数组: [30 10 20]
排序索引: [1 2 0]
通过索引排序: [10 20 30]六、部分排序与搜索
partition()只保证第k个位置是正确的,前k个元素小于等于第k个,后面的元素大于等于第k个,但不保证有序。这种方式时间复杂度为O(n),比全排序O(n log n)更快,适合Top-K问题。
代码示例
import numpy as np
arr = np.array([42, 15, 8, 23, 16, 4, 31, 5, 19, 34])
# partition:找前3个最小值(不保证顺序)
part = np.partition(arr, 3)
print(f"原数组: {arr}")
print(f"partition(3): {part}")
print(f"前3个最小值: {sorted(part[:3])}")
# argpartition:找前3个最小值的索引
indices = np.argpartition(arr, 3)
print(f"前3个最小值索引: {indices[:3]}")
print(f"前3个最小值: {arr[indices[:3]]}")
# searchsorted:在已排序数组中查找插入位置
sorted_arr = np.sort(arr)
values = [10, 25, 40]
positions = np.searchsorted(sorted_arr, values)
print(f"\n已排序数组: {sorted_arr}")
print(f"查找值: {values}")
print(f"插入位置: {positions}")输出结果:
代码示例
原数组: [42 15 8 23 16 4 31 5 19 34]
partition(3): [ 4 5 8 15 16 23 31 42 19 34]
前3个最小值: [4, 5, 8]
前3个最小值索引: [5 7 2]
前3个最小值: [4 5 8]
已排序数组: [ 4 5 8 15 16 19 23 31 34 42]
查找值: [10, 25, 40]
插入位置: [3 7 9]小贴士
searchsorted基于二分查找实现,要求输入数组必须是已排序的。side='left'返回第一个大于等于插入值的位置,side='right'返回第一个大于插入值的位置,默认为'left'。
七、实际应用场景
-
场景1:数据分析中,使用sort对数据排序,使用argsort获取排名,如对成绩排序后获取学生排名
-
场景2:推荐系统中,使用argpartition找Top-K推荐项,避免全量排序,大幅提升性能
-
场景3:搜索算法中,使用searchsorted在有序数组中快速查找插入位置,时间复杂度O(log n)
八、注意事项
注意:np.sort()返回副本不修改原数组,arr.sort()原地排序修改原数组。根据是否需要保留原始数据选择使用。
注意:partition只保证第k个位置是正确的,前k个和后面的元素不保证有序。如果需要有序的前k个元素,需要对partition结果的前k个再次排序。
注意:searchsorted要求输入数组必须是已排序的,否则结果无意义。使用前务必确认数组已排序。
九、排序函数对比
十、练习题
练习1
创建一个包含20个随机整数的数组,分别使用np.sort()和arr.sort()排序,验证前者不修改原数组
练习2
创建一个学生成绩数组,使用argsort获取排名,并按排名输出学生姓名和成绩
练习3
创建一个包含1000个随机数的数组,使用partition找出前10个最小值,对比与全排序的性能差异
常见问题
np.sort()和arr.sort()有什么区别?
np.sort()返回排序后的副本,原数组不变;arr.sort()原地排序,直接修改原数组。如果后续还需要原始数据,使用np.sort();如果不需要原始数据且要节省内存,使用arr.sort()。
partition和sort哪个更快?
当只需要前K个最小值或最大值时,partition的时间复杂度是O(n),sort是O(n log n)。数据量越大,partition的性能优势越明显。但如果需要完整排序,只能使用sort。
什么是排序稳定性?为什么它重要?
稳定排序保证相等元素的相对顺序不变。例如按成绩排序后,相同成绩的学生保持原来的先后顺序。这在多级排序中很重要,如先按学号排序再按成绩排序。
argsort如何实现多列排序?
对于多维数据排序,可以使用lexsort函数实现多列排序。lexsort从最后一个键开始排序,优先级从右到左递减。例如先按成绩降序,成绩相同按学号升序。
本文涉及AI创作
内容由AI创作,请仔细甄别