与numpy repeat

时间:2016-06-28 20:14:38

标签: python arrays performance numpy scientific-computing

我有两个不等长 val1 val2 的数组,我试图以等长数组定义的特定方式编织在一起mult1 mult2 。一般来说,我的数组很长(~1e6元素),这在我的计算中是一个性能关键的瓶颈,所以我不能做一个python-for循环,所以我试图利用Numpy中的向量化函数。为了明确:

mult1 = np.array([0, 1, 2, 1, 0])
mult2 = np.array([1, 0, 1, 1, 0])

val1 = np.array([1, 2, 3, 4])
val2 = np.array([-1, -2, -3])

desired_final_result = np.array([-1, 1, 2, 3, -2, 4, -3])

val1 val2 的编织由 mult1 mult2 <的索引通过以下逐元素处理来定义/ em>的。两个 mult 数组的每个条目定义了从相应的 val 数组中选择的元素数量。我们通过 mult 数组以元素方式进行; mult1 [i] 的值确定我们从 val1 中选择的条目数,然后我们继续使用 mult2 [i] 的值来选择适当数量的 val2 条目,始终为每个索引i选择 val1 条目。

请注意 len(val1)= mult1.sum() len(val2)= mult2.sum(),所以我们总是以最终数组结束 len(desired_final_result)= len(val1)+ len(val2)

最小例子的明确解释

  • 由于 mult1 i = 0 条目 0 ,我们从< 0 条目中选择 0 条目em> val1 并继续进入 mult2 i = 0 1 ,因此我们选择 1 val2 的条目。这解释了为什么desired_final_result的第一个条目是-1。

  • 由于 mult1 i = 1 条目 1 ,我们从< 1 条目中选择 1 条目em> val1 并继续进入 mult2 i = 1 0 ,因此选择 0 < / strong>来自 val2 的条目。这解释了为什么desired_final_result的第二个条目是1.

  • 由于 mult1 i = 2 条目 2 ,我们选择下一个 2 条目从 val1 继续进入 mult2 i = 2 1 ,所以我们选择下一个来自 val2 1 条目。这解释了为什么desired_final_result的条目2-4是2,3,-2。

  • 由于 mult1 i = 3 1 ,我们选择下一个 1 条目从 val1 继续进入 mult2 i = 3 ,这也是 1 ,所以我们选择来自 val2 的下一个 1 条目。这解释了为什么desired_final_result的条目5-6是4,-3。

  • 最后,由于 mult1 mult2 i = 4 0 ,我们没有什么可做的,我们的阵列已经填满。

问题

有没有办法使用矢量化函数,如 np.repeat 和/或 np.choose 来解决我的问题?或者我是否需要在C中编写此计算并将其包装到python中?

2 个答案:

答案 0 :(得分:4)

在结果数组中创建布尔索引:

mult = np.array([mult1, mult2]).ravel('F')
tftf = np.tile([True, False], len(mult1))
mask = np.repeat(tftf, mult)

result = np.empty(len(val1) + len(val2), int)
result[ mask] = val1
result[~mask] = val2

编辑 - 我相信这也有效:

idx = np.repeat(mult1.cumsum(), mult2)
result = np.insert(val1, idx, val2)

很简短,但可能不会更快。

答案 1 :(得分:2)

这可以通过NumPy例程来完成,但我提出的最好的是非常笨拙的:

reps = numpy.empty([len(mult1)*2], dtype=int)
reps[::2] = mult1
reps[1::2] = mult2

to_repeat = numpy.empty_like(reps)
to_repeat[::2] = -1   # Avoid using 0 and 1 in case either of val1 or val2 is empty
to_repeat[1::2] = -2

indices = numpy.repeat(to_repeat, reps)
indices[indices==-1] = numpy.arange(len(val1))
indices[indices==-2] = numpy.arange(len(val1), len(val1) + len(val2))

final_result = numpy.concatenate([val1, val2])[indices]