欢迎光临
我们一直在努力

Python NumPy - 数组的排序 sort 函数与 argsort 函数

在这里插入图片描述

👋 大家好,欢迎来到我的技术博客! 📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。 🎯 本文将围绕NumPy这个话题展开,希望能为你带来一些启发或实用的参考。 🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!


文章目录

  • Python NumPy – 数组的排序:sort 函数与 argsort 函数详解 🚀
    • 🔍 什么是 NumPy 排序?
    • 📊 sort 函数详解
      • 基本用法
      • 多维数组排序参数详解
      • 不同排序算法的选择
      • 自定义排序顺序
    • 🎯 argsort 函数详解
      • 基本概念和用法
      • 实际应用场景
        • 场景1: 同步排序多个相关数组
        • 场景2: 找到最大/最小的N个元素
      • 多维数组中的 argsort
    • 🔄 sort 与 argsort 的对比分析
      • 性能对比测试
    • 🛠️ 高级应用技巧
      • 条件排序
      • 多级排序
      • 处理特殊值的排序
    • 📈 实际应用案例
      • 数据分析中的排序应用
      • 机器学习中的特征排序
      • 统计分析中的百分位数计算
    • 🔧 实用工具函数封装
    • 🎯 性能优化建议
    • 🌐 相关资源和扩展阅读
    • 📝 总结

Python NumPy – 数组的排序:sort 函数与 argsort 函数详解 🚀

在数据科学和数值计算的世界中,排序是一个基础而重要的操作。无论是处理实验数据、分析用户行为,还是进行机器学习预处理,我们都需要对数据进行有效的排序。Python 的 NumPy 库为我们提供了强大的数组排序功能,其中 sort 和 argsort 函数是最常用的两个工具。

🔍 什么是 NumPy 排序?

NumPy 是 Python 中用于科学计算的基础库,它提供了高效的多维数组对象和各种操作函数。在 NumPy 中,排序指的是将数组元素按照特定顺序重新排列的过程。这种排序可以是升序、降序,也可以根据自定义规则进行。

import numpy as np

# 创建一个简单的数组
arr = np.array([3, 1, 4, 1, 5, 9, 2, 6])
print("原始数组:", arr)

# 使用 sort 函数进行排序
sorted_arr = np.sort(arr)
print("排序后数组:", sorted_arr)

输出结果:

原始数组: [3 1 4 1 5 9 2 6]
排序后数组: [1 1 2 3 4 5 6 9]

📊 sort 函数详解

基本用法

np.sort() 函数返回数组的排序副本,而不修改原始数组。这是它与列表的 sort() 方法的主要区别之一。

import numpy as np

# 一维数组排序
arr1d = np.array([64, 34, 25, 12, 22, 11, 90])
print("原始数组:", arr1d)
print("排序后的数组:", np.sort(arr1d))
print("原数组未改变:", arr1d)

# 二维数组排序
arr2d = np.array([[64, 34, 25],
[12, 22, 11],
[90, 88, 77]])
print("\\n原始二维数组:")
print(arr2d)
print("默认排序(按行):")
print(np.sort(arr2d))

# 按列排序
print("按列排序:")
print(np.sort(arr2d, axis=0))

输出结果:

原始数组: [64 34 25 12 22 11 90]
排序后的数组: [11 12 22 25 34 64 90]
原数组未改变: [64 34 25 12 22 11 90]

原始二维数组:
[[64 34 25]
[12 22 11]
[90 88 77]]
默认排序(按行):
[[25 34 64]
[11 12 22]
[77 88 90]]
按列排序:
[[12 22 11]
[64 34 25]
[90 88 77]]

多维数组排序参数详解

在处理多维数组时,axis 参数决定了沿着哪个轴进行排序:

import numpy as np

# 创建三维数组
arr3d = np.array([[[3, 1, 2],
[6, 4, 5]],
[[9, 7, 8],
[12, 10, 11]]])

print("原始三维数组:")
print(arr3d)

# axis=None – 展平后排序
print("\\naxis=None (展平后排序):")
print(np.sort(arr3d, axis=None))

# axis=0 – 沿着第一个轴排序
print("\\naxis=0 (沿着第一个轴排序):")
print(np.sort(arr3d, axis=0))

# axis=1 – 沿着第二个轴排序
print("\\naxis=1 (沿着第二个轴排序):")
print(np.sort(arr3d, axis=1))

# axis=2 – 沿着第三个轴排序
print("\\naxis=2 (沿着第三个轴排序):")
print(np.sort(arr3d, axis=2))

让我们通过 mermaid 图表来更好地理解不同 axis 参数的效果:

#mermaid-svg-ZN4p6FTf9Nb7v2hH{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZN4p6FTf9Nb7v2hH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .error-icon{fill:#552222;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .marker.cross{stroke:#333333;}#mermaid-svg-ZN4p6FTf9Nb7v2hH svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZN4p6FTf9Nb7v2hH p{margin:0;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .cluster-label text{fill:#333;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .cluster-label span{color:#333;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .cluster-label span p{background-color:transparent;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .label text,#mermaid-svg-ZN4p6FTf9Nb7v2hH span{fill:#333;color:#333;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .node rect,#mermaid-svg-ZN4p6FTf9Nb7v2hH .node circle,#mermaid-svg-ZN4p6FTf9Nb7v2hH .node ellipse,#mermaid-svg-ZN4p6FTf9Nb7v2hH .node polygon,#mermaid-svg-ZN4p6FTf9Nb7v2hH .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .rough-node .label text,#mermaid-svg-ZN4p6FTf9Nb7v2hH .node .label text,#mermaid-svg-ZN4p6FTf9Nb7v2hH .image-shape .label,#mermaid-svg-ZN4p6FTf9Nb7v2hH .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .rough-node .label,#mermaid-svg-ZN4p6FTf9Nb7v2hH .node .label,#mermaid-svg-ZN4p6FTf9Nb7v2hH .image-shape .label,#mermaid-svg-ZN4p6FTf9Nb7v2hH .icon-shape .label{text-align:center;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .node.clickable{cursor:pointer;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .arrowheadPath{fill:#333333;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZN4p6FTf9Nb7v2hH .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZN4p6FTf9Nb7v2hH .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZN4p6FTf9Nb7v2hH .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .cluster text{fill:#333;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .cluster span{color:#333;}#mermaid-svg-ZN4p6FTf9Nb7v2hH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZN4p6FTf9Nb7v2hH rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .icon-shape,#mermaid-svg-ZN4p6FTf9Nb7v2hH .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .icon-shape p,#mermaid-svg-ZN4p6FTf9Nb7v2hH .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .icon-shape .label rect,#mermaid-svg-ZN4p6FTf9Nb7v2hH .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZN4p6FTf9Nb7v2hH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZN4p6FTf9Nb7v2hH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZN4p6FTf9Nb7v2hH :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

原始三维数组

axis=None展平后排序

axis=0沿第一轴排序

axis=1沿第二轴排序

axis=2沿第三轴排序

一维有序数组

保持三维结构第一轴有序

保持三维结构第二轴有序

保持三维结构第三轴有序

不同排序算法的选择

NumPy 提供了多种排序算法,可以通过 kind 参数指定:

import numpy as np
import time

# 创建大型数组进行性能测试
large_arr = np.random.randint(0, 10000, 10000)

# 测试不同排序算法的性能
algorithms = ['quicksort', 'mergesort', 'heapsort', 'stable']

for algo in algorithms:
start_time = time.time()
sorted_arr = np.sort(large_arr, kind=algo)
end_time = time.time()
print(f"{algo:>10}: {end_time start_time:.6f} 秒")

# 查看算法特性
print("\\n算法特性说明:")
print("quicksort: 最快的平均性能,不稳定排序")
print("mergesort: 稳定排序,O(n log n)最坏情况")
print("heapsort: O(n log n)最坏情况,内存使用少")
print("stable: 稳定排序,默认为 mergesort")

自定义排序顺序

虽然 NumPy 主要支持升序排序,但我们可以通过一些技巧实现降序排序:

import numpy as np

arr = np.array([3, 1, 4, 1, 5, 9, 2, 6])
print("原始数组:", arr)

# 方法1: 对排序结果取反
desc_sorted1 = np.sort(arr)[::1]
print("方法1 – 降序:", desc_sorted1)

# 方法2: 先取负数再排序后还原
desc_sorted2 = np.sort(arr)
print("方法2 – 降序:", desc_sorted2)

# 方法3: 使用切片反转
desc_sorted3 = np.sort(arr)[1::1]
print("方法3 – 降序:", desc_sorted3)

🎯 argsort 函数详解

np.argsort() 函数返回的是排序后的索引数组,而不是排序后的值本身。这个函数在需要保持原始数据关联性时非常有用。

基本概念和用法

import numpy as np

# 基本用法示例
arr = np.array([64, 34, 25, 12, 22, 11, 90])
print("原始数组:", arr)

# 获取排序索引
indices = np.argsort(arr)
print("排序索引:", indices)

# 使用索引获取排序后的数组
sorted_by_indices = arr[indices]
print("通过索引排序:", sorted_by_indices)
print("直接排序比较:", np.sort(arr))
print("两者是否相等:", np.array_equal(sorted_by_indices, np.sort(arr)))

输出结果:

原始数组: [64 34 25 12 22 11 90]
排序索引: [5 3 4 2 1 0 6]
通过索引排序: [11 12 22 25 34 64 90]
直接排序比较: [11 12 22 25 34 64 90]
两者是否相等: True

实际应用场景

场景1: 同步排序多个相关数组

import numpy as np

# 学生姓名和对应成绩
names = np.array(['Alice', 'Bob', 'Charlie', 'David', 'Eve'])
scores = np.array([85, 92, 78, 96, 88])

print("原始数据:")
for i in range(len(names)):
print(f"{names[i]}: {scores[i]}分")

# 按成绩排序,同时保持姓名对应关系
sorted_indices = np.argsort(scores)
sorted_names = names[sorted_indices]
sorted_scores = scores[sorted_indices]

print("\\n按成绩排序后:")
for i in range(len(sorted_names)):
print(f"{sorted_names[i]}: {sorted_scores[i]}分")

输出结果:

原始数据:
Alice: 85分
Bob: 92分
Charlie: 78分
David: 96分
Eve: 88分

按成绩排序后:
Charlie: 78分
Alice: 85分
Eve: 88分
Bob: 92分
David: 96分

场景2: 找到最大/最小的N个元素

import numpy as np

# 随机生成学生成绩
np.random.seed(42)
student_scores = np.random.randint(60, 100, 20)
student_ids = np.arange(1, 21)

print("所有学生成绩:")
for i in range(len(student_scores)):
print(f"学生{student_ids[i]:2d}: {student_scores[i]}分")

# 找到前5名学生的ID和成绩
top5_indices = np.argsort(student_scores)[5:]
top5_students = student_ids[top5_indices]
top5_scores = student_scores[top5_indices]

print("\\n前5名学生:")
for i in range(len(top5_students)1, 1, 1): # 从高到低显示
rank = len(top5_students) i
print(f"第{rank}名: 学生{top5_students[i]:2d}, {top5_scores[i]}分")

# 找到最后3名学生的ID和成绩
bottom3_indices = np.argsort(student_scores)[:3]
bottom3_students = student_ids[bottom3_indices]
bottom3_scores = student_scores[bottom3_indices]

print("\\n后3名学生:")
for i in range(len(bottom3_students)):
print(f"倒数第{i+1}名: 学生{bottom3_students[i]:2d}, {bottom3_scores[i]}分")

多维数组中的 argsort

import numpy as np

# 二维数组示例
matrix = np.array([[64, 34, 25],
[12, 22, 11],
[90, 88, 77]])

print("原始矩阵:")
print(matrix)

# 按行排序的索引
row_sort_indices = np.argsort(matrix, axis=1)
print("\\n每行排序索引:")
print(row_sort_indices)

# 根据索引重构排序后的矩阵
sorted_matrix_rows = np.take_along_axis(matrix, row_sort_indices, axis=1)
print("\\n按行排序后的矩阵:")
print(sorted_matrix_rows)

# 按列排序的索引
col_sort_indices = np.argsort(matrix, axis=0)
print("\\n每列排序索引:")
print(col_sort_indices)

# 根据索引重构排序后的矩阵
sorted_matrix_cols = np.take_along_axis(matrix, col_sort_indices, axis=0)
print("\\n按列排序后的矩阵:")
print(sorted_matrix_cols)

🔄 sort 与 argsort 的对比分析

为了更好地理解这两个函数的区别和联系,让我们进行详细的对比分析:

import numpy as np

def compare_sort_functions():
"""比较 sort 和 argsort 函数的功能差异"""

# 创建测试数据
original_data = np.array([5, 2, 8, 1, 9, 3])

print("=" * 50)
print("📊 sort vs argsort 功能对比")
print("=" * 50)

print(f"原始数据: {original_data}")

# 使用 sort 函数
sorted_data = np.sort(original_data)
print(f"\\nnp.sort() 结果: {sorted_data}")
print(f"原始数据是否改变: {not np.array_equal(original_data, sorted_data)}")

# 使用 argsort 函数
sort_indices = np.argsort(original_data)
print(f"\\nnp.argsort() 结果: {sort_indices}")
reconstructed_sorted = original_data[sort_indices]
print(f"通过索引重建排序: {reconstructed_sorted}")
print(f"两种方法结果一致: {np.array_equal(sorted_data, reconstructed_sorted)}")

# 内存使用情况演示
print("\\n🧠 内存使用对比:")
print("np.sort(): 返回新的排序数组,不修改原数组")
print("np.argsort(): 返回索引数组,可用于多种后续操作")

compare_sort_functions()

性能对比测试

import numpy as np
import time

def performance_comparison():
"""性能对比测试"""

# 创建不同大小的测试数组
sizes = [1000, 10000, 100000]

print("\\n🚀 性能对比测试")
print("-" * 40)

for size in sizes:
test_array = np.random.randint(0, size*10, size)

# 测试 sort 性能
start_time = time.time()
sorted_result = np.sort(test_array)
sort_time = time.time() start_time

# 测试 argsort 性能
start_time = time.time()
indices = np.argsort(test_array)
argsort_time = time.time() start_time

print(f"数组大小: {size:>6}")
print(f" sort 时间: {sort_time:.6f} 秒")
print(f" argsort 时间: {argsort_time:.6f} 秒")
print()

performance_comparison()

🛠️ 高级应用技巧

条件排序

有时我们需要根据某些条件进行排序,这可以通过组合使用排序函数来实现:

import numpy as np

def conditional_sorting_example():
"""条件排序示例"""

# 创建包含姓名、年龄、分数的数据
data = np.array([
('Alice', 25, 85),
('Bob', 30, 92),
('Charlie', 22, 78),
('David', 28, 96),
('Eve', 24, 88)
], dtype=[('name', 'U10'), ('age', 'i4'), ('score', 'i4')])

print("原始数据:")
for record in data:
print(f" {record['name']}: 年龄{record['age']}, 分数{record['score']}")

# 按分数排序
score_sorted_indices = np.argsort(data['score'])
score_sorted_data = data[score_sorted_indices]

print("\\n按分数排序:")
for record in score_sorted_data:
print(f" {record['name']}: 年龄{record['age']}, 分数{record['score']}")

# 按年龄排序
age_sorted_indices = np.argsort(data['age'])
age_sorted_data = data[age_sorted_indices]

print("\\n按年龄排序:")
for record in age_sorted_data:
print(f" {record['name']}: 年龄{record['age']}, 分数{record['score']}")

conditional_sorting_example()

多级排序

当需要根据多个字段进行排序时,可以使用以下方法:

import numpy as np

def multi_level_sorting():
"""多级排序示例"""

# 创建包含多个属性的数据
students = np.array([
('Alice', 85, 25),
('Bob', 85, 30),
('Charlie', 92, 22),
('David', 85, 28),
('Eve', 92, 24)
], dtype=[('name', 'U10'), ('score', 'i4'), ('age', 'i4')])

print("原始数据:")
for student in students:
print(f" {student['name']}: 分数{student['score']}, 年龄{student['age']}")

# 方法1: 使用 lexsort 进行多级排序
# 先按年龄排序,再按分数排序(注意顺序是从最后一个开始)
indices = np.lexsort((students['age'], students['score']))
sorted_students = students[indices]

print("\\n多级排序结果(先按分数,再按年龄):")
for student in sorted_students:
print(f" {student['name']}: 分数{student['score']}, 年龄{student['age']}")

# 方法2: 使用 argsort 的稳定排序特性
# 先按次要键排序,再按主要键排序
age_indices = np.argsort(students['age'], kind='stable')
temp_sorted = students[age_indices]
score_indices = np.argsort(temp_sorted['score'], kind='stable')
final_sorted = temp_sorted[score_indices]

print("\\n使用稳定排序的多级排序:")
for student in final_sorted:
print(f" {student['name']}: 分数{student['score']}, 年龄{student['age']}")

multi_level_sorting()

处理特殊值的排序

在实际应用中,我们经常遇到包含 NaN 或无穷大值的数组,需要特殊处理:

import numpy as np

def special_value_sorting():
"""特殊值排序处理"""

# 包含 NaN 和无穷大的数组
arr_with_nan = np.array([3.0, 1.0, np.nan, 4.0, 2.0, np.inf, np.inf])
print("包含特殊值的数组:", arr_with_nan)

# 默认排序会把 NaN 放在最后
default_sorted = np.sort(arr_with_nan)
print("默认排序结果:", default_sorted)

# 使用 argsort 获取索引
indices = np.argsort(arr_with_nan)
print("排序索引:", indices)
print("通过索引排序:", arr_with_nan[indices])

# 将 NaN 放在前面的排序
nan_first_sorted = np.concatenate([
arr_with_nan[np.isnan(arr_with_nan)], # NaN 值
np.sort(arr_with_nan[~np.isnan(arr_with_nan)]) # 非 NaN 值排序
])
print("NaN 在前的排序:", nan_first_sorted)

# 只对有限值排序
finite_values = arr_with_nan[np.isfinite(arr_with_nan)]
finite_sorted = np.sort(finite_values)
print("只排序有限值:", finite_sorted)

special_value_sorting()

📈 实际应用案例

数据分析中的排序应用

import numpy as np

def data_analysis_sorting():
"""数据分析中的排序应用"""

# 模拟销售数据
np.random.seed(42)
products = np.array([f'产品{i:03d}' for i in range(1, 21)])
sales = np.random.randint(1000, 10000, 20)
profits = sales * np.random.uniform(0.1, 0.3, 20)

print("📊 销售数据分析")
print("=" * 50)

# 显示原始数据
print("原始销售数据:")
for i in range(len(products)):
print(f" {products[i]}: 销售额 {sales[i]:,}元, 利润 {profits[i]:.2f}元")

# 按销售额排序
sales_indices = np.argsort(sales)
sorted_products_by_sales = products[sales_indices]
sorted_sales = sales[sales_indices]
sorted_profits = profits[sales_indices]

print("\\n📈 按销售额排序(前5名):")
for i in range(1, 6, 1): # 从最高到最低
idx = i + len(sorted_products_by_sales)
print(f" {sorted_products_by_sales[idx]}: 销售额 {sorted_sales[idx]:,}元, "
f"利润 {sorted_profits[idx]:.2f}元")

# 计算利润率并排序
profit_rates = profits / sales * 100
rate_indices = np.argsort(profit_rates)
sorted_products_by_rate = products[rate_indices]
sorted_profit_rates = profit_rates[rate_indices]

print("\\n💰 按利润率排序(前5名):")
for i in range(1, 6, 1):
idx = i + len(sorted_products_by_rate)
print(f" {sorted_products_by_rate[idx]}: 利润率 {sorted_profit_rates[idx]:.2f}%")

data_analysis_sorting()

机器学习中的特征排序

import numpy as np

def ml_feature_sorting():
"""机器学习中的特征重要性排序"""

# 模拟特征名称和重要性分数
features = np.array([
'年龄', '收入', '教育程度', '工作经验',
'婚姻状况', '房产拥有', '信用评分', '负债比率'
])

# 模拟特征重要性分数(随机生成)
np.random.seed(123)
importance_scores = np.random.rand(8)

print("🤖 机器学习特征重要性分析")
print("=" * 40)

print("特征重要性原始数据:")
for i in range(len(features)):
print(f" {features[i]}: {importance_scores[i]:.4f}")

# 按重要性排序
importance_indices = np.argsort(importance_scores)
sorted_features = features[importance_indices]
sorted_importance = importance_scores[importance_indices]

print("\\n📊 特征按重要性排序(从高到低):")
for i in range(len(sorted_features)1, 1, 1):
rank = len(sorted_features) i
print(f" 第{rank}重要: {sorted_features[i]} ({sorted_importance[i]:.4f})")

# 选择最重要的前3个特征
top3_indices = importance_indices[3:]
top3_features = features[top3_indices]
top3_scores = importance_scores[top3_indices]

print("\\n🏆 最重要的3个特征:")
for i in range(len(top3_features)1, 1, 1):
print(f" ⭐ {top3_features[i]}: {top3_scores[i]:.4f}")

ml_feature_sorting()

统计分析中的百分位数计算

import numpy as np

def percentile_analysis():
"""使用排序计算百分位数"""

# 生成学生成绩数据
np.random.seed(456)
student_scores = np.random.normal(75, 15, 1000) # 平均75,标准差15
student_scores = np.clip(student_scores, 0, 100) # 限制在0-100之间

print("📊 学生成绩统计分析")
print("=" * 30)

print(f"样本数量: {len(student_scores)}")
print(f"平均分: {np.mean(student_scores):.2f}")
print(f"标准差: {np.std(student_scores):.2f}")

# 计算各种百分位数
percentiles = [10, 25, 50, 75, 90]
percentile_values = np.percentile(student_scores, percentiles)

print("\\n📈 百分位数分析:")
for i, p in enumerate(percentiles):
print(f" {p}百分位数: {percentile_values[i]:.2f}分")

# 手动计算中位数验证
sorted_scores = np.sort(student_scores)
manual_median = sorted_scores[len(sorted_scores)//2]
numpy_median = np.median(student_scores)

print(f"\\n🔍 中位数验证:")
print(f" 手动计算: {manual_median:.2f}")
print(f" NumPy函数: {numpy_median:.2f}")
print(f" 差异: {abs(manual_median numpy_median):.6f}")

percentile_analysis()

🔧 实用工具函数封装

为了在项目中更方便地使用这些排序功能,我们可以封装一些实用的工具函数:

import numpy as np

class SortingUtils:
"""排序工具类"""

@staticmethod
def safe_sort(arr, reverse=False):
"""
安全排序函数,处理包含 NaN 的数组

Parameters:
arr: 输入数组
reverse: 是否降序排列

Returns:
排序后的数组
"""
if not isinstance(arr, np.ndarray):
arr = np.array(arr)

# 分离 NaN 和非 NaN 值
nan_mask = np.isnan(arr)
finite_values = arr[~nan_mask]

# 对有限值进行排序
sorted_finite = np.sort(finite_values)
if reverse:
sorted_finite = sorted_finite[::1]

# 如果有 NaN 值,在末尾添加
if np.any(nan_mask):
nan_values = arr[nan_mask]
result = np.concatenate([sorted_finite, nan_values])
else:
result = sorted_finite

return result

@staticmethod
def sort_with_indices(values, *arrays_to_sync, reverse=False):
"""
同步排序多个数组

Parameters:
values: 用于排序的主数组
*arrays_to_sync: 需要同步排序的其他数组
reverse: 是否降序排列

Returns:
排序后的数组元组
"""
if reverse:
indices = np.argsort(values)[::1]
else:
indices = np.argsort(values)

result = [values[indices]]
for array in arrays_to_sync:
result.append(array[indices])

return tuple(result)

@staticmethod
def get_top_n_indices(arr, n, largest=True):
"""
获取前 N 个最大或最小值的索引

Parameters:
arr: 输入数组
n: 要获取的数量
largest: True 表示获取最大的,False 表示获取最小的

Returns:
索引数组
"""
if largest:
return np.argpartition(arr, n)[n:][::1]
else:
return np.argpartition(arr, n)[:n]

# 使用示例
def demonstrate_utils():
"""演示工具函数的使用"""

print("🔧 排序工具函数演示")
print("=" * 30)

# 演示安全排序
arr_with_nan = np.array([3.0, 1.0, np.nan, 4.0, 2.0])
print("原始数组(含 NaN):", arr_with_nan)
print("安全排序(升序):", SortingUtils.safe_sort(arr_with_nan))
print("安全排序(降序):", SortingUtils.safe_sort(arr_with_nan, reverse=True))

# 演示同步排序
names = np.array(['Alice', 'Bob', 'Charlie', 'David'])
ages = np.array([25, 30, 22, 28])
scores = np.array([85, 92, 78, 88])

print("\\n同步排序演示:")
print("原始数据:")
for i in range(len(names)):
print(f" {names[i]}: 年龄{ages[i]}, 分数{scores[i]}")

sorted_names, sorted_ages, sorted_scores = SortingUtils.sort_with_indices(
scores, names, ages, reverse=True
)

print("\\n按分数降序排序:")
for i in range(len(sorted_names)):
print(f" {sorted_names[i]}: 年龄{sorted_ages[i]}, 分数{sorted_scores[i]}")

# 演示获取前 N 个索引
data = np.array([64, 34, 25, 12, 22, 11, 90, 88])
top3_indices = SortingUtils.get_top_n_indices(data, 3, largest=True)
bottom2_indices = SortingUtils.get_top_n_indices(data, 2, largest=False)

print(f"\\n数组: {data}")
print(f"前3个最大值的索引: {top3_indices}")
print(f"对应的值: {data[top3_indices]}")
print(f"前2个最小值的索引: {bottom2_indices}")
print(f"对应的值: {data[bottom2_indices]}")

demonstrate_utils()

🎯 性能优化建议

在处理大规模数据时,合理的性能优化可以显著提升程序效率:

import numpy as np
import time

def performance_optimization_tips():
"""性能优化建议演示"""

print("⚡ 排序性能优化建议")
print("=" * 30)

# 1. 选择合适的排序算法
large_array = np.random.randint(0, 100000, 50000)

algorithms = {
'quicksort': '快速排序(默认)',
'mergesort': '归并排序(稳定)',
'heapsort': '堆排序(内存友好)'
}

print("1. 不同排序算法性能对比:")
for algo_name, algo_desc in algorithms.items():
start_time = time.time()
_ = np.sort(large_array.copy(), kind=algo_name)
elapsed_time = time.time() start_time
print(f" {algo_desc}: {elapsed_time:.6f} 秒")

# 2. 使用 argpartition 进行部分排序
print("\\n2. 部分排序 vs 完全排序:")

# 获取前10个最大值 – 完全排序方法
start_time = time.time()
fully_sorted = np.sort(large_array)
top10_full = fully_sorted[10:]
full_sort_time = time.time() start_time

# 获取前10个最大值 – 部分排序方法
start_time = time.time()
partitioned_indices = np.argpartition(large_array, 10)[10:]
top10_partial = np.sort(large_array[partitioned_indices])
partial_sort_time = time.time() start_time

print(f" 完全排序时间: {full_sort_time:.6f} 秒")
print(f" 部分排序时间: {partial_sort_time:.6f} 秒")
print(f" 性能提升: {(full_sort_time/partial_sort_time):.2f}倍")

# 3. 内存优化 – 原地排序
print("\\n3. 原地排序 vs 新数组排序:")

# 创建副本进行排序(额外内存)
arr_copy = large_array.copy()
start_time = time.time()
sorted_copy = np.sort(arr_copy)
copy_sort_time = time.time() start_time

# 直接修改原数组
arr_inplace = large_array.copy()
start_time = time.time()
arr_inplace.sort() # 注意这里是 ndarray.sort() 方法
inplace_sort_time = time.time() start_time

print(f" 新数组排序时间: {copy_sort_time:.6f} 秒")
print(f" 原地排序时间: {inplace_sort_time:.6f} 秒")

performance_optimization_tips()

🌐 相关资源和扩展阅读

对于想要深入了解 NumPy 排序功能的读者,以下是一些有价值的参考资料:

  • NumPy 官方文档 – 排序 提供了关于排序函数的完整技术文档
  • SciPy Lecture Notes 包含了 NumPy 基础知识的详细讲解
  • Python Data Science Handbook 是一本优秀的数据科学实践指南

📝 总结

NumPy 的 sort 和 argsort 函数为我们提供了强大而灵活的数组排序能力。通过本文的详细介绍和丰富的代码示例,我们了解了:

  • 基本用法:两个函数的核心功能和使用方法
  • 高级特性:多维数组排序、不同算法选择、特殊值处理
  • 实际应用:数据分析、机器学习、统计计算等多个领域的应用
  • 性能优化:如何选择合适的排序策略以获得最佳性能
  • 掌握这些排序技巧不仅能提高编程效率,还能帮助我们在数据处理和科学计算中做出更好的决策。记住,选择合适的排序方法取决于具体的应用场景和性能要求。在实际开发中,建议根据数据规模、内存限制和精度要求来选择最适合的方案。

    排序作为数据处理的基础操作,其重要性不言而喻。随着数据量的不断增长,高效、稳定的排序算法将成为我们处理大数据的关键工具。希望本文能够帮助您更好地理解和运用 NumPy 的排序功能!✨


    🙌 感谢你读到这里! 🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。 💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友! 💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿 🔔 关注我,不错过下一篇干货!我们下期再见!✨

    赞(0)
    未经允许不得转载:171主机测评 » Python NumPy - 数组的排序 sort 函数与 argsort 函数
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址