You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于索引分段向下填充NumPy数组行

高效实现NumPy数组按指定索引行向下填充

Got it, you're dealing with large NumPy arrays and need an efficient way to fill rows down from specified indices without slow for loops—let's fix that with vectorized operations, which are way faster for big datasets.

核心方案1:用np.repeat直接生成结果

这是最简洁的方法,通过计算每个索引行需要重复的次数,一次性生成目标数组:

import numpy as np

# 原数组和索引列表
arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24], [25, 26, 27, 28], [29, 30, 31, 32], [33, 34, 35, 36], [37, 38, 39, 40]])
idx = [0, 2, 3, 5, 8, 9]

# 计算每个索引行的重复次数:前n-1个索引的次数是下一个索引减当前,最后一个到数组末尾
repeats = np.diff(idx, append=arr.shape[0])
# 按次数重复对应行,得到最终结果
result = np.repeat(arr[idx], repeats, axis=0)

原理说明:

  • np.diff(idx, append=arr.shape[0])会生成每个索引行需要重复的次数数组:[2, 1, 2, 3, 1, 1](对应idx中每个元素的重复次数)
  • np.repeat(arr[idx], repeats, axis=0)会把arr[idx]中的每一行按对应次数重复,直接输出目标数组。

核心方案2:用np.searchsorted构建索引映射

如果需要更灵活的索引控制(比如后续还要复用映射关系),可以用np.searchsorted快速构建目标索引数组,再直接索引原数组:

import numpy as np

arr = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24], [25, 26, 27, 28], [29, 30, 31, 32], [33, 34, 35, 36], [37, 38, 39, 40]])
idx = [0, 2, 3, 5, 8, 9]

# 生成原数组每行对应的目标索引
pos = np.searchsorted(idx, np.arange(arr.shape[0]), side='right') - 1
target_indices = idx[pos]
# 直接索引得到结果
result = arr[target_indices]

原理说明:

  • np.searchsorted(idx, np.arange(arr.shape[0]), side='right')会找到每个行号在idx中的插入位置,减1后得到该行对应的idx中的索引值
  • 最终target_indices是一个和原数组行数相同的数组,每个元素对应该行要填充的原索引,直接索引即可得到结果。

性能对比

这两种方法都是完全向量化操作,没有逐行循环,性能比嵌套循环或np.tile循环快几个数量级:

  • 对于100万行的数组,循环方法可能需要数秒,而向量化方法仅需几毫秒
  • 内存占用也更高效,避免了循环中的多次数组赋值

验证结果

打印result会得到你期望的数组:

[[ 1  2  3  4]
 [ 1  2  3  4]
 [ 9 10 11 12]
 [13 14 15 16]
 [13 14 15 16]
 [21 22 23 24]
 [21 22 23 24]
 [21 22 23 24]
 [33 34 35 36]
 [37 38 39 40]]

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

火山引擎 最新活动