
NumPy 新增descending参数numpy.partition与numpy.argpartition降序分区完整指南【免费下载链接】numpyThe fundamental package for scientific computing with Python.项目地址: https://gitcode.com/gh_mirrors/nu/numpy本文基于 NumPy 仓库中的特性变更文档31511.new_feature.rst展开系统介绍 NumPy 2.6.0 起为numpy.partition与numpy.argpartition新增的descending关键字参数包括参数语义、NaN 特殊处理规则、dtype 支持范围、底层 C 实现原理与测试验证。读完本文你将能够直接使用descendingTrue完成各类数值、字符串、日期时间、对象数组的降序分区并理解该特性与既有sort/argsort降序能力的实现关系及性能注意事项。特性背景与核心内容在 NumPy 2.6.0 之前numpy.partition与numpy.argpartition只支持升序分区。与sort/argsort早已支持descending不同分区操作若要降序只能先整体反转数组或借助负的kth等变通手段。本次特性为二者新增了统一的descending关键字参数用户可以通过descendingTrue让numpy.partition与numpy.argpartition按降序对数组进行分区NaN 值无论升降序都分区到数组末尾NaN-at-end 语义保持不变该特性适用于所有内建 dtype但void与generic除外需要注意分区操作的 SIMD 优化目前不适用于降序路径因此降序分区性能可能比升序更慢。参数语义descending的取值与默认行为从函数签名与文档字符串可以看到完整的参数定义见 fromnumeric.py 中partition与argpartition的实现def partition(a, kth, axis-1, kindnp._NoValue, orderNone, descendingnp._NoValue): def argpartition(a, kth, axis-1, kindnp._NoValue, orderNone, descendingnp._NoValue):descending : bool, optional的语义如下官方文档原话Sort order. IfTrue, the array will be partitioned in descending order. IfFalseorNone, the array will be partitioned in ascending order. Values that are NaN are partitioned towards the end of the array regardless of order. Default:None.即取值行为True按降序分区False按升序分区None默认按升序分区与旧版本行为完全一致descending对kth的语义也做了镜像调整在返回数组中第kth个元素会处于其在排序数组中应有的位置所有大于该元素的值降序时被移动到它之前所有小于等于它的值被移动到它之后两侧分区内部的元素顺序不定。升序场景则相反。该参数在两个函数中均标注为.. versionadded:: 2.6.0。在实现层面partition与argpartition都通过“向后兼容消毒”逻辑处理该参数见 fromnumeric.py 与 fromnumeric.py只有当descending不等于np._NoValue时才将其写入kwargs随后透传给ndarray.partition/ndarray.argpartition方法或通过_wrapfunc分发因此默认行为与旧版本完全兼容不会破坏既有调用。基础用法示例一维数组降序分区 import numpy as np a np.array([7, 1, 7, 7, 1, 5, 7, 2, 3, 2, 6, 2, 3, 0]) # 升序分区默认行为 np.partition(a, 4) array([0, 1, 2, 1, 2, 5, 2, 3, 3, 6, 7, 7, 7, 7]) # may vary # 降序分区 np.partition(a, 4, descendingTrue) array([7, 7, 7, 7, 6, 2, 2, 2, 3, 3, 5, 1, 1, 0]) # may vary在降序示例中p[4]为 6p[:4]中的元素全部大于等于p[4]p[5:]中的元素全部小于等于p[4]。与升序一样每个分区内部元素的顺序是不确定的# may vary。多个kth值kth同样支持序列一次性将多个位置的元素放到其排序后的正确位置上 p2 np.partition(a, (4, 8), descendingTrue)多维数组与argpartitionaxis参数继续生效默认沿最后一个轴分区axisNone时先将数组展平再分区。argpartition返回索引数组降序用法与升序一致 x np.array([[3, 4, 2], [1, 3, 1]]) index_array np.argpartition(x, kth1, axis-1, descendingTrue) np.take_along_axis(x, index_array, axis-1) array([[4, 3, 2], [3, 1, 1]])对于一维数组a[index_array]即可得到分区后的数组更高维度下np.take_along_axis(a, index_array, axisaxis)始终等价于np.partition(a, kth, axisaxis)。NaN 处理升降序一致的“末尾”语义该特性文档明确强调NaN values, if present, are partitioned to the end of the array in both ascending and descending sorts.也就是说无论升序还是降序NaN 都一律被移动到数组末尾。这一点与sort/argsort的descending行为保持一致也避免了“降序时 NaN 被排到最前”这类反直觉结果。测试代码中对此有专门断言见 test_multiarray.pyif nan is not None: # nans sort to the end regardless of sort order expected np.concatenate((expected[~np.isnan(expected)], expected[np.isnan(expected)]))dtype 支持范围与限制官方变更文档给出的支持范围是This feature is available for all built-in dtypes exceptvoidandgeneric.即除void结构化/无类型 void dtype与generic抽象基类 dtype外其余所有内建 dtype 均支持降序分区。这在底层实现中也有直接体现npy_sort.c中的排序循环会从cmps数组中取出对应升/降序的比较器若降序比较器为NULL即该 dtype 未注册降序比较函数则会抛出ValueError: descending sort not supported for this DType见 npy_sort.c。具体覆盖的内建 dtype 类型从测试参数化中可以完整看到有符号整数int8 / int16 / int32 / int64无符号整数uint8 / uint16 / uint32 / uint64浮点float16 / float32 / float64 / longdouble含 NaN 场景复数complex64 / complex128 / clongdouble含 NaN 与字典序场景字符串str / bytes / unicode日期时间datetime64 / timedelta64对象object对应的测试方法命名清晰可循test_partition_descending_*与test_argpartition_descending_*系列见 test_multiarray.py此外 test_custom_dtypes.py 中还验证了自定义 dtype 的partition/argpartition降序支持。底层实现原理从 Python 到 C 的完整链路1. Python 层参数消毒与透传numpy.partition在接收descending后将其放入kwargs并调用数组方法a.partition(kth, axisaxis, orderorder, **kwargs)numpy.argpartition则通过_wrapfunc(a, argpartition, kth, axisaxis, orderorder, **kwargs)完成方法分发。这样既保持了array_function分发协议两个函数都带有对应的 dispatcher又确保了descending的向后兼容默认值。2. C 层标志位与比较器选择在 C 实现中降序并非单独实现一套排序算法而是通过标志位 比较器索引复用同一套算法骨架。核心代码位于 npy_sort.cPyArrayMethod_SortParameters *sort_params (PyArrayMethod_SortParameters *)context-parameters; int descending (sort_params-flags NPY_SORT_DESCENDING) ! 0; PyArray_CompareFunc *cmp cmps[descending];cmps是一个长度为 2 的比较器数组{ascending, descending}按NPY_SORT_DESCENDING标志位索引见 npy_sort.h。降序入口cmps[1]允许为NULL——此时请求降序排序会直接报错这正是void、generic等 dtype 无法降序分区的机制根源。3. 通用快速排序模板reverse模板参数对于数值类型降序分区走通用快速排序模板Quick见 quicksort_generic.hpp// NUMERIC SORTS // reversetrue performs a descending sort using the same comparator, // preserving NaN-at-end semantics for floating-point inputs. template bool reverse false, typename T inline void Quick(T *start, SSize num)reversetrue通过同一套比较器Cmpreverse执行降序并保持浮点输入的 NaN 在末尾语义——这正是“升降序 NaN 都到末尾”的底层保证。partition/argpartition内部同样使用基于快速排序思想的introselect选择算法kind目前仅支持introselect最坏情况复杂度 O(n)不稳定工作空间 O(1)。4. SIMD 优化路径说明仓库中存在独立的 SIMD 加速排序实现见 x86_simd_qsort.dispatch.cpp 与 x86_simd_argsort.dispatch.cpp用于对常见数值 dtype 的升序排序/分区进行向量化加速。但正如变更文档明确提示的Note that SIMD optimizations for partitioning are currently not available for descending order, so performance may be slower.即降序分区的 SIMD 优化尚未实现因此降序分区会回退到通用标量路径性能可能明显慢于同规模下的升序分区。这是官方文档承认的已知限制在追求极致性能的场景下需要权衡若数据规模很大且对顺序方向敏感可考虑升序分区后自行反转处理或等待后续版本补齐降序 SIMD 支持。测试验证特性正确性的保障该特性在仓库测试套件中覆盖充分。以 test_multiarray.py 的核心校验逻辑为例测试对每个 dtype 组合k ∈ {2, 15, 50, 95}与descending ∈ {True, False}进行验证同时包含原始有序输入与随机打乱输入两类场景part np.partition(a, k, descendingdescending) before, after np.split(part, [k]) before.sort(descendingdescending) after.sort(descendingdescending) ... assert_equal(before, expected[:k], msg) assert_equal(after, expected[k:], msg)校验思路是对分区结果的k两侧分别做同方向完整排序再与期望的前缀/后缀比较——既验证了“第 k 个位置就位”又验证了“两侧元素相对全集正确”同时通过 NaN 注入a[::10] nan验证了 NaN 恒定置尾规则。使用注意事项小结默认兼容不传descending时行为与旧版本完全一致可放心在升级后保留旧代码。NaN 位置升降序中 NaN 都被推到数组末尾做“取 Top-K”时如需排除 NaN 仍需自行过滤。dtype 边界void与generic不支持降序分区会抛出ValueError。性能权衡降序分区暂无 SIMD 加速大数组降序场景可评估升序分区 反转的替代方案。算法本质不变kind仍仅支持introselect不保证稳定分区两侧内部顺序未定义。该特性与sort/argsort的descending参数形成完整闭环——现在 NumPy 的排序与分区两大操作族均原生支持升降序双向控制相关文档可进一步参阅 fromnumeric.py 中partition、argpartition、sort、argsort的完整 docstring。【免费下载链接】numpyThe fundamental package for scientific computing with Python.项目地址: https://gitcode.com/gh_mirrors/nu/numpy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考