Python NumPy实现数组排序与过滤示例分析讲解

发布时间:2026/10/8 19:37:43

Python NumPy实现数组排序与过滤示例分析讲解 前言NumPy 是第三方库不是标准库使用前需要pip install numpy。本机没有 Python 解释器也没有装 NumPy所以本文的示例无法在本机运行验证只能逐行人工推演函数签名、返回值和版本差异一律以 NumPy 官方文档为准。标题里的「排序与过滤」看着简单实际藏了几个高频陷阱。最典型的一个是numpy.sort返回的是排好序的副本而ndarray.sort方法是原地排序、返回None。用过list.sort()的人对「原地排序返回None」有印象但换成 NumPy 时又常常把它俩弄反——写成a np.sort(a)固然没错写成a a.sort()就会把a变成None然后在下游报一个和排序毫无关系的错误。第二个陷阱是过滤手段选错。where、extract、布尔索引三者的结果不完全一样尤其是where只有条件一个参数时它返回的是一个下标元组不是元素本身。第三个是清洗顺序。缺测值NaN如果不清掉就去排序或裁剪结果往往不是预期的——NaN 在排序里会被排到末尾而裁剪也「裁」不掉它。本文按「排序 → 取顺序 → 去重计数 → 过滤 → 清洗」的顺序把这几组常用接口放在一起讲清楚并给出可以对照官方文档的示例。一、排序numpy.sort是副本ndarray.sort是原地先看两者的签名和语义写法是否原地返回值说明numpy.sort(a, axis-1, kindNone, orderNone)否排好序的副本默认沿最后一根轴排序ndarray.sort(axis-1, kindNone, orderNone)是None直接改动数组本身注意两个地方一是默认排序轴是最后一根axis-1不是「把整个数组展平再排」——对二维数组默认是按行各排各的二是ndarray.sort的返回值是None官方的签名里就没有返回值的概念它就是原地操作。# 适用于 Python 3.8 且已安装 NumPy以官方文档为准import numpy as npa np.array([3, 1, 2])b np.sort(a) # 副本print(b) # [1 2 3]print(a) # [3 1 2] —— a 没变c np.array([3, 1, 2])ret c.sort() # 原地print(ret) # Noneprint(c) # [1 2 3]版本方面有两条值得记住numpy.sort与numpy.argsort的stable关键字是 NumPy 2.0.0 新增的用来要求稳定排序它等价于选kindstabledescending关键字是 NumPy 2.5.0 新增的用来直接要求降序。如果你的环境是更早的版本降序要靠切片反转np.sort(a)[::-1]或argsort的负数技巧不要写这两个关键字。另外kind的可选值包括quicksort默认、mergesort、heapsort、stable。官方文档说明稳定排序会保持相等元素的相对顺序对整数类型mergesort和stable会映射到基数排序。二、只想要「顺序」argsort、argpartition、lexsort大多数时候你并不想重排数据本身而是想要「谁排在前面」这个信息那就用返回下标的版本。numpy.argsort(a, axis-1, kindNone, orderNone, *, stableNone, descending)返回的是把数组排好序所需的下标stable与descending是关键字专用的可选参数descending带一个内部的哨兵默认值含义是「不指定」# 适用于 Python 3.8 且已安装 NumPy以官方文档为准import numpy as npa np.array([3, 1, 2])print(np.argsort(a)) # [1 2 0] —— a[1]1 最小a[2]2 次之a[0]3 最大print(a[np.argsort(a)]) # [1 2 3]用下标取回排序结果如果只需要「最小的前 k 个」用numpy.argpartition(a, kth, axis-1, kindintroselect)更划算它做的是部分排序保证第kth个位置上是「排好序后应该在那个位置」的元素且它左边的都不大于它、右边的都不小于它——左右两边内部是无序的。# 适用于 Python 3.8 且已安装 NumPy以官方文档为准import numpy as npa np.array([9, 1, 8, 2, 7, 3])idx np.argpartition(a, 3) # kth3print(a[idx[:3]]) # 最小的三个数内部无序多键排序用numpy.lexsort(keys, axis-1)。它最容易记错的一点是keys里最后一个键是主键其余键按从后往前的顺序作为次键。也就是说要让a做主键、b做次键得写成np.lexsort((b, a))——顺序是反过来的。# 适用于 Python 3.8 且已安装 NumPy以官方文档为准import numpy as npsurname np.array([2, 1, 2, 1])score np.array([90, 95, 85, 88])order np.lexsort((score, surname)) # 主键是 surname最后一个次键是 scoreprint(order) # [3 1 2 0]print(surname[order]) # [1 1 2 2]print(score[order]) # [88 95 85 90]三、去重与计数numpy.uniquenumpy.unique(ar, return_indexFalse, return_inverseFalse, return_countsFalse, axisNone, *, equal_nanTrue, sortedTrue)一个函数解决了「去重」「排序」「计数」三件事参数作用返回内容默认只返回排序后的唯一值一个数组return_indexTrue每个唯一值在原数组中首次出现的下标多返回一个数组return_inverseTrue用下标重建原数组所需的映射多返回一个数组return_countsTrue每个唯一值出现的次数多返回一个数组axis按行或按列去重默认为None即展平处理—# 适用于 Python 3.8 且已安装 NumPy以官方文档为准import numpy as npa np.array([3, 1, 3, 2, 1])print(np.unique(a)) # [1 2 3]vals, counts np.unique(a, return_countsTrue)print(vals) # [1 2 3]print(counts) # [2 1 2]注意默认行为里已经包含了「排序」——unique返回的值是按升序排好的。官方文档还给出两条版本说明一是从 1.21 起和numpy.sort一样NaN 会被排到末尾二是sorted与equal_nan这两个关键字是较新版本加入的equal_nan默认True表示把多个 NaN 视作同一个值来去重。不用这两个参数时不必关心但如果你要写跨版本兼容的代码最好显式确认。四、过滤布尔索引、numpy.where、numpy.extract布尔索引是最直接的过滤方式把一个布尔数组传进去得到满足条件的元素组成的新数组。# 适用于 Python 3.8 且已安装 NumPy以官方文档为准import numpy as npa np.array([1, 5, 3, 8])print(a 4) # [False True False True]print(a[a 4]) # [5 8]numpy.where有两种完全不同的用法签名写成where(condition, [x, y], /)两个参数是可选的三个参数条件 xy条件为真的位置取x否则取y返回同形状的新数组只有一个参数条件官方说明它等价于np.asarray(condition).nonzero()返回的是下标而且是一个元组。# 适用于 Python 3.8 且已安装 NumPy以官方文档为准import numpy as npa np.array([1, 5, 3, 8])print(np.where(a 4, a, 0)) # [0 5 0 8] —— 三参数按位置挑选print(np.where(a 4)) # (array([1, 3]),) —— 单参数返回下标元组这是最容易踩的一处单参数的where返回的是元组不是数组。想拿满足条件的元素要么用布尔索引a[a 4]要么用三参数where。官方也提示如果只是为了取下标直接用nonzero更清楚。numpy.extract(condition, arr)是另一个过滤函数语义上和arr[condition]接近返回一维结果。它在链式表达式中偶尔更顺手但不如布尔索引直观日常用布尔索引就够了。顺带记一个统计函数numpy.count_nonzero(a, axisNone, *, keepdimsFalse)用来数非零元素因为True在布尔数组里就是1所以np.count_nonzero(a 4)正好是「满足条件的元素个数」。五、清洗numpy.clip与numpy.isnan的组合numpy.clip把数值限制在区间内。官方说明它等价于但快于np.minimum(a_max, np.maximum(a, a_min))并且不检查a_min是否小于a_max。a_min a_max时的行为官方文档专门写了一条这时clip会返回一个所有值都等于a_max的数组。这个行为不太符合直觉但它是被明文规定的不是「未定义行为」所以不要去依赖它之外的任何东西。还有一个版本细节min和max这两个关键字参数是 NumPy 2.1.0 新增的它们是a_min/a_max的替代写法。写新代码可以用新名字但如果要兼容旧版本还是用a_min/a_max更保险。numpy.isnan(x, /, outNone, *, whereTrue, ...)是一个 ufunc返回与输入同形状的布尔数组标记每个位置是不是 NaN。注意它的第一个参数是仅位置参数签名里那个/的含义只能按位置传不能写成isnan(x...)。清洗的标准顺序是先去 NaN再裁剪反过来做会被 NaN 干扰# 适用于 Python 3.8 且已安装 NumPy以官方文档为准import numpy as npb np.array([1.0, np.nan, 5.0, 20.0, -3.0])print(np.isnan(b)) # [False True False False False]cleaned b[~np.isnan(b)] # 先用布尔索引剔掉 NaNclipped np.clip(cleaned, 0.0, 10.0)print(clipped) # [ 1. 5. 10. 0.]这里的关键点是~np.isnan(b)np.isnan给出「是 NaN」的掩码取反~才得到「不是 NaN」的位置。这一步不能省——因为clip并不会把 NaN 修掉np.maximum/np.minimum会传播 NaN所以 NaN 通常在裁剪后原样保留。如果你在一个含 NaN 的数组上直接clip再拿去算均值得到的还是 NaN。需要注意的是np.clip(b, 0.0, 10.0)里0.0和10.0是按位置传的顺序是「下界、上界」别写反。写反了虽然不会报错按上面的规则会得到全是上界的数组但结果毫无意义。常见坑点❌ 写a a.sort()以为拿到了排序结果。✅ndarray.sort是原地排序、返回None这行会让a变成None要副本用a np.sort(a)要原地就直接a.sort()。❌ 认为np.sort(a)会改动a。✅np.sort返回副本只有ndarray.sort方法才原地修改。❌ 对二维数组调用np.sort(a)期待得到整个数组的全局排序。✅ 默认axis-1是沿最后一根轴排序要全局排序先a.ravel()或传axisNone。❌ 用np.where(a 4)拿元素然后对返回结果做数组运算。✅ 单参数where返回的是下标元组取元素用布尔索引a[a 4]或改用三参数where。❌ 写np.lexsort((primary, secondary))以为第一个键是主键。✅最后一个键才是主键主键是a、次键是b时应写np.lexsort((b, a))。❌ 在含有 NaN 的数组上直接clip以为缺口会被顺带处理掉。✅clip不会修掉 NaN先用b[~np.isnan(b)]剔除再裁剪顺序不能反。❌ 以为clip会检查下界是否小于上界或者依赖「下界大于上界」时的某种直觉行为。✅ 官方明确不检查两者大小关系且当a_min a_max时返回的数组所有值都等于a_max别把参数写反。❌ 在旧版本 NumPy 上用np.sort(a, stableTrue)或descendingTrue。✅stable是 NumPy 2.0.0 新增、descending是 2.5.0 新增旧版本请用kindstable或切片反转。总结需求该用关键点排序并保留原数组np.sort(a)返回副本默认沿最后一轴原地排序a.sort()返回None要排序后的下标np.argsort(a)结果用于a[idx]只要前 k 小np.argpartition(a, k)只保证第k个位置正确两侧无序多键排序np.lexsort((次键, 主键))最后一个键是主键去重 计数np.unique(a, return_countsTrue)结果已排序NaN 排末尾按条件取元素a[a 4]布尔索引返回副本不是视图按条件替换np.where(cond, x, y)单参数形式返回下标元组限制取值范围np.clip(a, 下界, 上界)不检查上下界大小min/max关键字需 2.1.0处理缺测值np.isnan 布尔索引先去 NaN 再裁剪这几组接口的共同点是它们大多返回新数组而不是就地改。所以写代码时先问一句「这个调用返回什么、我把它接到哪里了」就能避开本文里大半的坑——尤其是sort方法返回None、单参数where返回元组这两个。至于清洗记住「先剔缺测、再裁剪、最后统计」的顺序NaN 就不会再悄悄污染你的结果。参考numpy.sort、numpy.argsort、numpy.argpartition、numpy.lexsort、numpy.unique、numpy.where、numpy.extract、numpy.clip、numpy.isnan、numpy.count_nonzero的签名与版本说明均以 NumPy 官方文档为准NumPy 为第三方库需pip install numpy本文代码未在本机运行仅作人工推演。
延伸阅读

更多相关文章

2026/10/8 19:37:43

【人工智能】知识库是你的消化系统

【人工智能】知识库是你的消化系统摘要:知识库不是仓库,而是你的消化系统——存进去的东西必须真正变成你自己的血肉。本文对比了「仓库式」与「消化系统式」两种用法,说明往知识库中丢什么、如何逼自己想清楚,并针对学生、上班族…

2026/10/8 20:48:03

递归自改进与有限自细化:从刷分陷阱到可控的AI自我进化工程

上个月我跑了一个小小的递归自改进实验:用一个大模型当“优化器”,去改另一个模型的系统提示词,目标很简单,把代码生成通过率从60%抬到80%。第一轮和第二轮确实在涨,到第五轮就出现了诡异的变化:模型开始在…

2026/10/8 20:48:03

GTC 2026前瞻与英伟达驱动排障实战:从报错到环境优化

GTC 2026要来了,但我翻了翻后台留言和各个群里最近的讨论,发现大家关心的事跑了偏:新卡什么时候出、DLSS还能怎么吹,这些反倒是其次。真正让大多数人头疼的,是驱动。0x80070002报错、安装包损坏、桌面图标凭空消失、De…

2026/10/8 20:48:03

从AutoResearch看科研自动化:当LLM成为软件的基本执行单元

前阵子我在刷信息流的时候,被 Karpathy 在 GitHub 上公开的 AutoResearch 实验报告链接勾住了。本来想着扫一眼就划走,结果一口气读了两遍,又顺着他把他在 X 上关于 "software is changing" 的讨论全部翻了出来。这几年号称“AI 科…

2026/10/8 20:48:03

AI大模型API聚合平台:2026年工程落地的确定性基础设施

1. 为什么2026年团队集体转向聚合平台——不是跟风,是API对接成本崩盘后的理性自救2026年春天,我帮三家不同行业的客户做AI大模型集成方案:一家做工业质检的制造企业,一家做服装AI试穿的电商公司,还有一家做古玩鉴定的…

2026/10/8 20:48:03

SSM高校考勤管理系统毕业设计:需求、实现与答辩全攻略

每年毕业季,Java方向的选题里,“SSM高校考勤管理系统”几乎是出镜率最高的题目之一。原因很简单:它既有Spring、SpringMVC、MyBatis这套SSM框架的完整应用,又有学生、教师、管理员三种角色的权限区分,还有签到、请假、…

2026/10/8 10:03:18

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/8 10:03:20

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/8 6:05:44

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 0:02:17

自然数立方等于连续奇数之和:从证明到编程验证

十几年来我一直游走在数学科普和编程教学这两块内容之间,对“看起来像魔法、拆开全是数学”的结论总是格外敏感。最近翻资料时又撞见一句话:任何一个自然数 m 的立方,都可以写成 m 个连续奇数之和。2 的立方等于 3 加 5,3 的立方等…

2026/10/8 0:02:17

C#上位机SSH连接实战:用SSH.NET补齐超时、批量与密钥认证

简介:这是一份基于 C# 开发的 SSH 连接功能半成品工程,原本作为另一个主项目的子功能模块,现独立打包分享。工程采用 WinForms 界面,包含源码、解决方案、安装部署工程、NuGet 依赖包及说明文档,适合正在做远程连接、网…

2026/10/8 0:02:17

Java SpringBoot一体化智能售后系统设计与实现全解析

毕业设计年年做,Java Web 方向的题目翻来覆去就那么几个,但“一体化智能售后系统”这个题,每次看到我都觉得值得认真聊一聊。它不是一个简单 curd 堆出来的管理系统,而是把客户、工单、派单、处理、回访、统计整条链路串起来的一套…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑