You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

numpy.argsort()会大幅增加数组内存吗?如何低内存高效排序?

问题描述

我有一个名为combinations的numpy数组(维度为37,933,056行×3列,类型为np.float32),还有一个一维数组err_np(共37,933,056个元素,类型为np.float16),用来存储每组3值组合的百分比误差。

我需要按绝对误差对combinations排序,执行了如下代码:

from sys import getsizeof as size
import numpy as np

# 此处省略其他操作

print(size(combinations)) # 120 - **数值过低**
print(len(combinations))  # 37,933,056
print(combinations)       # 数组内容正常

combinations = combinations[abs(err_np).argsort()] 

print(size(combinations)) # 455,196,792 - **数值过高**
print(len(combinations))  # 37,933,056
print(combinations)       # 数组已正确排序

我原本以为排序前的内存数值有误,但用的是sys.getsizeof(),且数组内容显示正常。

请问有没有方法能用更少内存对这个numpy数组排序?同时要尽可能高效,因为数组规模很大。排序后我会删除err_np,不需要保留它。


解决方案

先理清内存显示异常的原因

sys.getsizeof()仅返回numpy数组对象本身的大小,而非存储数据的总内存。排序前的数组如果是视图(view)而非独立副本,getsizeof()只会返回对象头的大小(比如120字节);而combinations[abs(err_np).argsort()]会创建数组的完整副本,此时getsizeof()才会返回数据+对象头的总大小,这就是数值突变的原因。

低内存排序的可行方案

1. 原地修改数组(最优内存效率)

如果内存能容纳原数组的大小,用np.take()配合out参数直接将排序结果写入原数组,避免额外内存开销:

# 生成排序索引
sorted_indices = abs(err_np).argsort()
# 原地替换,不创建新数组
np.take(combinations, sorted_indices, axis=0, out=combinations)

操作完成后,combinations直接变为排序后的结果,不会额外占用一倍内存。

2. 分块排序(内存紧张时)

若内存不足以容纳完整数组副本,可将数组拆分为小块分别排序后写入原数组:

block_size = 1_000_000  # 根据自身内存情况调整块大小
sorted_indices = abs(err_np).argsort()

# 逐块处理
for i in range(0, len(sorted_indices), block_size):
    idx_block = sorted_indices[i:i+block_size]
    combinations[i:i+block_size] = combinations[idx_block]

这种方法每次仅处理一小块数据,内存占用大幅降低,仅牺牲少量排序效率。

3. 结构化数组合并排序(逻辑直观)

将combinations与err_np合并为结构化数组,按误差列排序后拆分回原数组:

# 合并为带字段名的结构化数组
combined = np.rec.fromarrays(
    [combinations[:,0], combinations[:,1], combinations[:,2], abs(err_np)],
    names='col0,col1,col2,err'
)
# 按误差字段排序
combined.sort(order='err')
# 拆分回原数组格式
combinations = np.column_stack([combined.col0, combined.col1, combined.col2])
# 立即释放临时变量内存
del err_np, combined

内存开销与直接排序接近,但逻辑更清晰,适合关联数据排序场景。

额外优化建议

  • 排序后调用gc.collect()手动触发垃圾回收,释放err_np和临时索引数组的内存。
  • 生成排序索引后立即删除err_np,提前释放内存:
    sorted_indices = abs(err_np).argsort()
    del err_np
    # 再执行排序操作
    

内容的提问来源于stack exchange,提问作者LucianoSaldivia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 19:35:22