NumPy数组.resize() - 首个零

3
我可以使用array.resize(shape)来调整数组大小,并在未赋值的索引处添加零。如果我的数组是[1,2,3,4],并且我使用array.resize[5,0],则会得到[1,2,3,4,0]。如何在前面添加/填充零,使其变为[0,1,2,3,4]
我正在动态地尝试这样做:
array.resize(arrayb.shape)

我希望尽可能避免制作一个内存中的数组副本。也就是说,反转数组,调整大小,然后再次反转。使用视图最理想。


1
先反转,再填充,最后再反转? - Russell Borogove
@RussellBorogove 第一个反转需要制作一个新的内存副本,以便调整大小工作。如果数组很大,这并不理想。将更新问题以解决此问题。 - Jzl5325
1
这只是array.resize不工作的方式...没有前面填充选项...我相信这是由于在C级别上,它们正在执行realloc,该操作会将插槽附加到原始数组大小的末尾... - Joran Beasley
@JoranBeasley 还有其他选择吗? - Jzl5325
2
你无法“不惜一切代价”避免复制,因为resize方法可能需要进行复制。 - Fred Foo
2个回答

3
您可以尝试使用负步长对数组进行操作(虽然您无法确定调整大小是否需要拷贝):
_a = np.empty(0) # original array
a = _a[::-1] # the array you work with...

# now instead of a, resize the original _a:
del a # You need to delete it first. Or resize will want refcheck=False, but that
      # will be dangerous!
_a.resize(5)
# And update a to the new array:
a = _a[::-1]

如果有可能,我建议您将数组大小调整得足够大,这看起来并不美观,但我认为这是除了复制数据以外的唯一方法。您的数组还将具有负步幅,因此它不会是连续的,因此如果某个函数在其上使用必须进行复制,则您就会遇到麻烦。

另外,如果您对a_a进行切片,则必须进行copy或确保在调整大小之前删除它们。虽然您可以给出refcheck=False,但这似乎会使数据无效。


不错的技巧,但它确实依赖于相当数量的CPython实现细节。此外,ndarray.resize可能仍然会执行复制。 - Fred Foo
@larsmans numpy 在很大程度上仅限于 CPython,尽管我不确定 CPython 的哪些地方参与了,但ndarray.resize是关键点。reallocs 可能需要进行复制,除非数组足够大,否则这是无法避免的。 - seberg
“del”技巧依赖于CPython的引用计数垃圾回收机制。是的,NumPy目前与CPython绑定,但有尝试让它在PyPy上运行。我承认我不知道PyPy如何进行垃圾回收。 - Fred Foo

2

我相信你可以使用切片赋值来完成这个操作。我认为没有理由让numpy在像这样的操作中需要复制,只要它对重叠进行必要的检查(当然,正如其他人所指出的,resize本身可能需要分配新的内存块)。我用一个非常大的数组测试了这种方法,我没有看到内存使用量的增加。

>>> a = numpy.arange(10)
>>> a.resize(15)
>>> a[5:] = a[:10]
>>> a[0:5] = 0
>>> a
array([0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

以下演示了赋值操作的内存使用情况没有发生跳跃:
>>> a = numpy.arange(100000000)
>>> a.resize(150000000)
>>> a[50000000:] = a[:100000000]

我不知道更好的方法,这只是一种猜测。如果行不通,请告诉我。


最终我选择了这个解决方案。感谢您的建议和内存测试。从长远来看,看起来我会转向标量,因为我可以安全地丢弃一些数据,但现在这个解决方案运行得非常好! - Jzl5325

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接