当前位置:首页>python>【一起学Python】第85天:NumPy排序与选择全攻略,数据清洗必备神器

【一起学Python】第85天:NumPy排序与选择全攻略,数据清洗必备神器

  • 2026-10-11 07:57:24
【一起学Python】第85天:NumPy排序与选择全攻略,数据清洗必备神器

📌 写在前面

大家好!

欢迎来到**【一起学Python】**的第85天!🎉

前84天,我们从环境安装一路学到统计函数,已经掌握了NumPy的“基本功”。但在实际数据分析中,我们经常遇到这样的需求:

  • 📊 找出排名前10的数据
  • 🔍 筛选出符合条件的样本
  • 📉 把乱序的实验数据整理好
  • 替换异常值或缺失标记

今天,我们就来解锁NumPy的排序与选择功能!掌握它们,你的数据清洗效率将提升10倍!🚀

一、数组排序:让数据“各就各位” 📊

NumPy提供了灵活高效的排序工具,既能返回新数组,也能原地修改,还能获取排序索引。

1.1 np.sort() vs arr.sort()

import numpy as npscores = np.array([85, 92, 78, 95, 60])# 方式1:np.sort() → 返回新数组,原数组不变 ✅ 推荐用于需保留原始数据的场景sorted_new = np.sort(scores)print("新数组:", sorted_new)      # [60 78 85 92 95]print("原数组:", scores)          # [85 92 78 95 60](未变)# 方式2:arr.sort() → 原地排序,节省内存  适合超大数据集scores.sort()print("原地排序后:", scores)       # [60 78 85 92 95]
核心区别:

方法

是否修改原数组

内存开销

适用场景

np.sort(arr)

❌ 否

额外分配新数组

需保留原始数据、链式调用

arr.sort()

✅ 是

原地操作,省内存

大数据集、明确不需要原数据

1.2 np.argsort():排序索引(数据分析神器!)

不直接排序数据,而是返回排序后的位置索引。这在“按A列排序,同时重排B列”时极其有用!

ids = np.array([101, 102, 103, 104, 105])scores = np.array([85, 92, 78, 95, 60])# 获取从小到大排序的索引sorted_idx = np.argsort(scores)print("排序索引:", sorted_idx)  # [4 2 0 1 3]# 用索引同时重排学号和成绩print("按成绩排序后的学号:", ids[sorted_idx])   # [105 103 101 102 104]print("按成绩排序后的分数:", scores[sorted_idx]) # [60 78 85 92 95]

1.3 多维数组排序:axis 参数

matrix = np.array([[3, 1, 2],                    [9, 7, 8],                    [6, 4, 5]])# 按行排序(axis=1)print("按行排序:\n", np.sort(matrix, axis=1))# 按列排序(axis=0)print("按列排序:\n", np.sort(matrix, axis=0))

二、条件选择与过滤:精准定位目标数据 🎯

当需要按条件提取或替换数据时,where 和 nonzero 是你的最佳搭档。

2.1 np.where():条件选择的“瑞士军刀”

np.where() 有两种常用模式,千万别混淆!

🔹 模式1:返回满足条件的索引

data = np.array([10, 20, 30, 40, 50])condition = data > 30indices = np.where(condition)print("满足条件的索引:", indices)  # (array([3, 4]),)print("满足条件的元素:", data[indices])  # [40 50]

🔹 模式2:类似Excel的IF函数(条件替换)

# 格式:np.where(条件, 条件为真时的值, 条件为假时的值)grades = np.array([85, 55, 92, 48, 76])result = np.where(grades >= 60, "及格", "不及格")print("评级结果:", result)  # ['及格' '不及格' '及格' '不及格' '及格']# 数值替换:小于0的补0,大于100的截断为100clipped = np.where(grades < 0, 0, np.where(grades > 100, 100, grades))

2.2 np.nonzero():提取非零/True元素的索引

arr = np.array([0, 5, 0, 8, 0, 3])# 返回非零元素的索引nz_idx = np.nonzero(arr)print("非零索引:", nz_idx)  # (array([1, 3, 5]),)print("非零元素:", arr[nz_idx])  # [5 8 3]# 💡 等价于布尔索引:arr[arr != 0]# 但 nonzero() 返回的是索引,适合需要定位原始位置的场景

2.3 布尔索引 vs where vs nonzero

data = np.array([15, 25, 35, 45, 55])# 1. 布尔索引(最简洁,推荐日常使用)print(data[data > 30])  # [35 45 55]# 2. np.where(condition)(返回索引元组)print(np.where(data > 30))  # (array([2, 3, 4]),)# 3. np.nonzero(condition)(与where返回索引等价)print(np.nonzero(data > 30))  # (array([2, 3, 4]),)

选择建议:

  • 只需提取数据 → 直接用 data[condition]
  • 需要知道原始位置 → 用 np.where() 或 np.nonzero()
  • 需要按条件赋值 → 用 np.where(cond, x, y)

三、实战演练:排序+选择的组合拳 🥊

场景:学生成绩分析系统

import numpy as np# 模拟数据:5名学生,3门课成绩students = np.array(["张三", "李四", "王五", "赵六", "孙七"])scores = np.array([    [85, 92, 78],  # 张三    [60, 55, 70],  # 李四    [95, 98, 96],  # 王五    [45, 50, 48],  # 赵六    [88, 90, 85]   # 孙七])# 1. 计算总分total_scores = np.sum(scores, axis=1)print("总分:", total_scores)  # [255 185 289 143 263]# 2. 找出总分前3的学生(降序排序索引)top3_idx = np.argsort(total_scores)[::-1][:3]print("前3名索引:", top3_idx)  # [2 4 0]print("前3名学生:", students[top3_idx])  # ['王五' '孙七' '张三']# 3. 标记不及格(任意一科<60)fail_mask = np.any(scores < 60, axis=1)print("需补考学生:", students[fail_mask])  # ['李四' '赵六']# 4. 将低于60的成绩替换为60(平时分保护政策)protected_scores = np.where(scores < 60, 60, scores)print("保护后成绩:\n", protected_scores)

📝 核心技巧总结:

  • np.argsort()[::-1] → 快速实现降序排名
  • np.any()/np.all() + 布尔索引 → 多条件组合筛选
  • np.where() 嵌套 → 复杂条件赋值

今日作业

基础题 ⭐

  • 创建数组 [3, 1, 4, 1, 5, 9, 2, 6],分别用 np.sort() 和 arr.sort() 排序,观察区别。
  • 使用 np.argsort() 找出原数组中最大值的索引。
  • 用 np.where() 将数组中小于3的元素替换为0,其余保持不变。

进阶题 ⭐⭐

  • 创建一个4×5的随机整数矩阵(0~100),按列降序排序。
  • 使用 np.nonzero() 提取矩阵中大于80的元素的行列坐标。
  • 模拟体温数据,将 <36.0 或 >37.5 的值标记为“异常”,其余标记为“正常”。

挑战题 ⭐⭐⭐

  • Top-K高效解法:生成100万个随机数,对比 np.sort()[-10:] 和 np.partition()[-10:] 的耗时(提示:partition 适合找前K大/小)。
  • 多条件筛选:从二维数组中筛选出“第一列>50 且 第二列<30”的行。
  • 成绩等级映射:将分数数组按 [0,60,75,85,100] 分段,映射为 ['D','C','B','A'](提示:用 np.digitize 或多次 where)。

💡 参考代码(挑战题-Top-K对比):

import numpy as npimport timedata = np.random.rand(1_000_000)# 方法1:全排序start = time.time()top10_sort = np.sort(data)[-10:]print(f"sort耗时: {time.time()-start:.4f}s")# 方法2:局部排序(更高效)start = time.time()top10_part = np.partition(data, -10)[-10:]print(f"partition耗时: {time.time()-start:.4f}s")

🎓 明日预告

第86天:NumPy文件读写与数据持久化

你将学到:

  • 🔸 np.save / np.load 高效保存二进制数组
  • 🔸 np.savetxt / np.loadtxt 读写CSV/文本文件
  • 🔸 二进制格式 vs 文本格式的优劣对比
  • 🔸 实战:数据预处理后的持久化存储与跨平台共享

敬请期待! 📂

学习小贴士

  1. 排序性能:
    • 小数组:sort() 足够快
    • 找Top-K:优先用 np.partition()(时间复杂度 O(n) vs O(n log n))
    • 需保留原数据:用 np.sort() 或先 .copy()
  2. 选择函数避坑:
    • np.where(cond) 返回的是元组,取索引用 indices[0]
    • 布尔索引 arr[mask] 返回的是副本,修改不影响原数组
    • 多维条件筛选时,注意 &(与)、|(或)要用括号包裹:arr[(arr>0) & (arr<10)]
  3. 调试技巧:
    • 排序后对不上?检查是否混用了 axis=0 和 axis=1
    • 筛选结果为空?打印 condition.sum() 看有多少True
    • 内存爆满?大数据集优先用原地操作 arr.sort() 和视图切片

📚 学习路线图

第74天:NumPy安装 ✓第75天:ndarray对象 ✓第76天:数据类型 ✓第77天:数组属性 ✓第78天:创建数组 ✓第79天:切片和索引 ✓第80天:高级索引 ✓第81天:数组运算 ✓第82天:数组操作 ✓第83天:数学函数 ✓第84天:统计函数 ✓第85天:排序与选择 ✓ ← 你今天在这里第86天:文件读写第87天:与pandas结合...

💬 写在最后

排序与选择是数据分析的**“导航仪”和“过滤器”**。掌握它们,你就能:

✅ 快速定位关键数据,告别手动翻找✅ 灵活处理排名、筛选、替换等高频需求✅ 写出简洁、高效、可读性强的数据清洗代码

今天重点掌握:

  • ✅ sort() 与 argsort() 的场景选择
  • ✅ np.where() 的两种模式(索引返回 vs 条件赋值)
  • ✅ 布尔索引与 nonzero() 的配合使用

如果觉得有用,记得:

  • 👍 点赞支持一下
  • ⭐ 收藏方便复习
  • 📤 分享给更多小伙伴

完成作业的同学,欢迎在评论区打卡! 💪

【一起学Python】每天进步一点点,365天后遇见更优秀的自己!

👉 关注公众号,不错过每天的学习内容!

🎯 今日金句:

"排序让数据有序,选择让价值显现。掌握它们,混乱的数据也将为你让路!" ️✨

明天见!

最新文章

随机文章