
本文介绍一种高效方法:仅需一次 np.argsort() 操作,即可对 NumPy 数组按另一数组定义的顺序执行累积求和,避免冗余的二次排序,显著提升性能。
本文介绍一种高效方法:仅需一次 `np.argsort()` 操作,即可对 numpy 数组按另一数组定义的顺序执行累积求和,避免冗余的二次排序,显著提升性能。
在数据处理中,常需按某个“索引映射数组”(如 arr2)所定义的逻辑顺序,对目标数组(如 arr1)进行累积运算。直观做法是先用 np.argsort(arr2) 获取排序索引,再对 arr1 重排并累加,最后将结果“还原回原位置”——但若错误地对索引数组再次调用 np.argsort(),不仅冗余,还易引发理解偏差。
实际上,关键在于理解 sorting_indices 的双重角色:
- 它是
arr2的升序排列索引,即arr2[sorting_indices]是有序的; - 同时,它也是从“排序后位置”到“原始位置”的逆映射——也就是说,
result[i]应填入最终结果中第sorting_indices[i]个位置。
因此,正确流程为三步(仅一次 argsort):
- 获取
arr2的排序索引:idx = np.argsort(arr2); - 按该索引重排
arr1并计算累积和:cum_sorted = np.cumsum(arr1[idx]); - 将累积和按
idx“放回”原始位置:cum_sorted[idx]—— 注意此处不是np.argsort(idx),因为idx本身已承载位置映射关系。
以下是完整可运行示例:
import numpy as np arr1 = np.array([1, 4, 2, 5, 6, 3, 2]) arr2 = np.array([1, 0, 2, 4, 3, 6, 5]) # ✅ 单次 argsort,高效实现 idx = np.argsort(arr2) result = np.cumsum(arr1[idx])[idx] print(result) # 输出: [ 5 4 7 18 13 23 20]
验证逻辑:
-
arr2 = [1,0,2,4,3,6,5]→np.argsort(arr2) = [1,0,2,4,3,6,5](最小值0在索引1,次小1在索引0,依此类推); -
arr1[idx] = [4,1,2,6,5,2,3]; -
np.cumsum(arr1[idx]) = [4,5,7,13,18,20,23]; - 最后
cumsum_result[idx]将第0个累积值4放入结果的idx[0]=1位,第1个值5放入idx[1]=0位……最终得到[5,4,7,18,13,23,20],完全匹配预期。
注意事项:
- 此方法依赖
arr2元素互异;若存在重复值,np.argsort()仍有效(稳定排序),但语义上“顺序定义”需额外约定; - 时间复杂度为 O(n log n),由单次排序主导,空间复杂度 O(n),优于两次排序的隐式开销;
- 切勿误用
np.argsort(idx)——因idx是排列,其argsort恰好等于idx自身(恒等映射),但逻辑上无意义且易造成混淆。
该技巧体现了对 NumPy 索引机制的深入理解,是优化科学计算代码的典型实践。










