NumPy 排序、条件筛选函数(完整指南)

NumPy 排序与条件筛选函数:数据处理的两大利器

在处理科学计算、数据分析或机器学习任务时,我们常常需要对大量数值数据进行整理和提取。NumPy 作为 Python 中最核心的数值计算库,提供了强大的排序和条件筛选功能,能让我们高效地完成这些操作。今天,我们就来深入聊聊 NumPy 的排序与条件筛选函数,带你从零开始掌握它们的核心用法。

想象一下,你有一堆学生的考试成绩数据,现在需要找出高于 80 分的同学,或者按分数从高到低排序。如果手动一个个判断或排序,效率极低。而 NumPy 的排序与条件筛选函数,就像一个自动化的“数据整理员”,几行代码就能搞定。

创建数组与初始化

在开始之前,先导入 NumPy 库。这是所有操作的基础。

import numpy as np

接下来,我们创建一个简单的二维数组,模拟学生成绩表。每行代表一个学生,每列代表一门科目。

scores = np.array([
    [85, 90, 78],
    [92, 88, 95],
    [76, 80, 82],
    [98, 94, 91],
    [67, 75, 70]
])

print("原始成绩数组:")
print(scores)

输出结果:

原始成绩数组:
[[85 90 78]
 [92 88 95]
 [76 80 82]
 [98 94 91]
 [67 75 70]]

这个数组就像一个电子表格,每一行是一个学生,每一列是一门课。接下来,我们就要用 NumPy 的功能来“加工”它。

NumPy 排序函数详解

排序是数据处理中最常见的需求之一。NumPy 提供了多种排序方式,满足不同场景。

使用 sort() 函数进行原地排序

np.sort() 是最常用的排序函数,它会返回一个排序后的新数组,原数组不变。

sorted_scores = np.sort(scores, axis=1)

print("按每行升序排序后:")
print(sorted_scores)

输出:

按每行升序排序后:
[[78 85 90]
 [88 92 95]
 [76 80 82]
 [91 94 98]
 [67 70 75]]

注意:axis=1 表示按列方向(横向)排序,即每行内部排序。如果设置 axis=0,则按行方向(纵向)排序,即每列内部排序。

使用 argsort() 获取排序索引

有时我们不仅想知道排序后的结果,还想保留原始位置信息。这时 argsort() 就派上用场了。

row_indices = np.argsort(scores, axis=1)

print("每行排序的原始索引:")
print(row_indices)

输出:

每行排序的原始索引:
[[2 0 1]
 [1 0 2]
 [0 1 2]
 [2 1 0]
 [0 2 1]]

比如第一行 [85, 90, 78] 排序后是 [78, 85, 90],对应原始位置是第 2 个、第 0 个、第 1 个元素。这在后续定位原始数据时非常有用。

条件筛选函数:精准提取数据

如果说排序是“整理”,那条件筛选就是“精准定位”。NumPy 的布尔索引机制,让条件筛选变得异常灵活。

基本布尔索引用法

我们可以直接用条件表达式生成布尔数组,然后用它来筛选原始数据。

high_scores = scores > 80

print("大于 80 的位置标记:")
print(high_scores)

filtered_scores = scores[high_scores]

print("所有大于 80 的成绩:")
print(filtered_scores)

输出:

大于 80 的位置标记:
[[ True  True False]
 [ True  True  True]
 [False  True  True]
 [ True  True  True]
 [False False False]]
所有大于 80 的成绩:
[85 90 92 88 95 80 82 98 94 91]

注意:scores > 80 返回的是一个布尔数组,形状与原数组一致。当用它作为索引时,NumPy 会提取所有 True 对应位置的元素,形成一维数组。

多条件筛选:使用逻辑运算符

实际场景中,我们常需要多个条件。NumPy 支持 &(与)、|(或)、~(非)等逻辑运算符。

condition = (scores > 80) & (scores < 90)

print("大于 80 且小于 90 的位置:")
print(condition)

filtered = scores[condition]

print("符合条件的成绩:")
print(filtered)

输出:

大于 80 且小于 90 的位置:
[[ True False False]
 [False False True]
 [False True True]
 [False False False]
 [False False False]]
符合条件的成绩:
[85 88 80 82]

注意:括号 () 是必须的,因为 & 的优先级高于 ><,不加括号会报错。

按行或列筛选:结合 axis 参数

有时候我们想筛选整行或整列。比如找出“所有科目都高于 80”的学生。

all_high = np.all(scores > 80, axis=1)

print("所有科目都大于 80 的学生:")
print(all_high)

top_students = scores[all_high]

print("这些学生的成绩:")
print(top_students)

输出:

所有科目都大于 80 的学生:
[False False False  True False]
这些学生的成绩:
[[98 94 91]]

这里 axis=1 表示按行判断,np.all() 要求该行所有元素都满足条件才返回 True。这在“全勤奖”、“全优生”这类筛选中非常实用。

实际应用案例:成绩分析系统

我们来整合前面的知识,构建一个简单的成绩分析功能。

np.random.seed(42)  # 保证结果可复现
student_scores = np.random.randint(60, 100, size=(10, 3))

print("学生原始成绩(10 人,3 门课):")
print(student_scores)

avg_per_subject = np.mean(student_scores, axis=0)
sorted_subjects = np.argsort(avg_per_subject)

print(f"\n按平均分从低到高排序的科目:{sorted_subjects}")
print(f"平均分:{avg_per_subject}")

total_scores = np.sum(student_scores, axis=1)
high_achievers = total_scores > 250

print(f"\n总分超过 250 的学生编号:{np.where(high_achievers)[0]}")
print(f"这些学生的总分:{total_scores[high_achievers]}")

two_high = np.sum(student_scores > 90, axis=1) >= 2
excellent_students = student_scores[two_high]

print(f"\n至少两门课超过 90 的学生:")
print(excellent_students)

这个案例展示了如何结合排序和条件筛选,完成一个完整的分析流程:从数据准备到条件提取,再到结果输出。

总结与进阶建议

NumPy 的排序与条件筛选函数,是数据处理的基石。掌握它们,不仅能提升代码效率,还能让你在数据分析和机器学习项目中游刃有余。

排序方面,np.sort() 用于生成新数组,argsort() 用于获取位置索引,适合需要追踪原始位置的场景。条件筛选则依赖布尔索引,通过 &|~ 实现复杂逻辑,配合 np.all()np.any() 可完成行列级判断。

建议初学者从简单数组开始练习,逐步尝试多维数组和组合条件。记住:NumPy 的核心优势在于向量化操作,避免使用 Python 的 for 循环,这样才能真正发挥其性能优势。

最后,当数据量增大时,这些函数的高效性会愈发明显。无论是处理百万级数据,还是构建自动化分析流水线,NumPy 的排序与条件筛选函数都将是你的得力助手。