如何在Numpy中就地扩展数组?

Han*_*Sun 31 python arrays numpy scipy

目前,我有一些像这样的代码

import numpy as np
ret = np.array([])
for i in range(100000):
  tmp =  get_input(i)
  ret = np.append(ret, np.zeros(len(tmp)))
  ret = np.append(ret, np.ones(fixed_length))
Run Code Online (Sandbox Code Playgroud)

我认为这个代码效率不高,因为np.append需要返回数组副本而不是修改ret就地

我想知道我是否可以使用extend像这样的numpy数组:

import numpy as np
from somewhere import np_extend
ret = np.array([])
for i in range(100000):
  tmp =  get_input(i)
  np_extend(ret, np.zeros(len(tmp)))
  np_extend(ret, np.ones(fixed_length))
Run Code Online (Sandbox Code Playgroud)

这样extend会更有效率.有没有人有这个想法?谢谢!

unu*_*tbu 35

想象一个numpy数组占用一个连续的内存块.现在想象一下其他对象,比如其他numpy数组,它们占用了我们numpy数组左右两侧的内存.没有空间可以附加或扩展我们的numpy数组.numpy数组中的基础数据总是占用连续的内存块.

因此,任何追加或扩展我们的numpy数组的请求只能通过分配一个全新的更大的内存块,将旧数据复制到新块然后追加或扩展来满足.

所以:

  1. 它不会就地发生.
  2. 它效率不高.

  • @Praxeolitic你的声明是有效的,但与我的声明并不矛盾:@unutbu声明“调整大小”永远不会就地发生并且永远不会有效。这是不正确的。如果使用“realloc”,它*可能*就地发生并且*可能*高效。这取决于内存管理实现。因此,从 python 的角度来看,无法做出 @unutbu 所做的声明。我对建议的分配方案的观点是,在效率和动态大小之间进行权衡的需要对我来说似乎总是人为的,尽管这可能不是“numpy”需要解决的问题。 (4认同)
  • 但是,如果在扩大内存块的方式中没有其他对象,它可能是有效的。我会说你的答案不完整,因为假设其他内存分配总是阻止就地调整大小是不正确的。例如在 C 中,你有 `realloc`。我对一个好的答案的期望是说明 `numpy` 是否也有一个 `realloc` 等效项,如果没有:为什么不呢?我也经常想知道为什么现代 64 位机器拥有大量的地址空间,为什么没有更多地使用智能分页方法来为此目的在分配之间留下虚拟空间。 (3认同)
  • 这很好,但是你必须重新实现链表上的所有numpy方法,同时透明地隐藏底层numpy数组不连续的事实.此外,一些numpy函数调用用C或Fortran编写的函数(例如LAPACK),这些函数利用了输入是连续的内存块这一事实.要将链接的非连续数据发送到这些函数,您必须分配和复制,因此它将是无效的. (2认同)
  • @Herbert Numpy 的 `.resize()` 确实在内部使用了 `realloc()`,但 Numpy 遵循自动内存管理的 Python 约定,因此直接公开像 `realloc()` 这样的东西是没有意义的。一般来说,“ndarray”适合具有静态大小的大型数组,而不是动态数组。调整性能大小并不是主要目标。Numpy 使用的“malloc”实现可以使用您建议的复杂分配方案,但这与 Numpy 无关。 (2认同)

pv.*_*pv. 14

您可以使用.resize()ndarrays 的方法.它要求内存不被其他数组/变量引用.

import numpy as np
ret = np.array([])
for i in range(100):
    tmp = np.random.rand(np.random.randint(1, 100))
    ret.resize(len(ret) + len(tmp)) # <- ret is not referred to by anything else,
                                    #    so this works
    ret[-len(tmp):] = tmp
Run Code Online (Sandbox Code Playgroud)

通过使用通常的阵列存储器叠加方案可以提高效率.


Bi *_*ico 10

处理此问题的常用方法是这样的:

import numpy as np
ret = []
for i in range(100000):
  tmp =  get_input(i)
  ret.append(np.zeros(len(tmp)))
  ret.append(np.zeros(fixed_length))
ret = np.concatenate(ret)
Run Code Online (Sandbox Code Playgroud)

由于其他答案已经进入的原因,通常不能在不复制数据的情况下扩展数组.