【问题标题】:Efficient way to fill NumPy array for independent entries?为独立条目填充 NumPy 数组的有效方法?
【发布时间】:2021-09-23 09:03:11
【问题描述】:

我目前正在尝试填充矩阵 K,其中矩阵中的每个条目只是一个应用于数组 x 的两个条目的函数。 目前,我正在使用最明显的方法,使用双 for 循环一次遍历行和列:

K = np.zeros((x.shape[0],x.shape[0]), dtype=np.float32)
for i in range(x.shape[0]):
    for j in range(x.shape[0]):
        K[i,j] = f(x[i],x[j])

虽然这可以正常工作,但生成的矩阵是 10,000 x 10,000 矩阵,并且需要很长时间来计算。我想知道 NumPy 中是否有更有效的方法来做到这一点?

编辑:这里讨论的函数是一个高斯核:

def gaussian(a,b,sigma):
    vec = a-b
    return np.exp(- np.dot(vec,vec)/(2*sigma**2))

我在计算矩阵之前提前设置了 sigma。 数组 x 是一个形状为 (10000, 8) 的数组。所以高斯中的标量积在两个 8 维向量之间。

【问题讨论】:

  • 提供一个真实的例子会很有用。您要应用哪种功能?请给出函数/输入/输出的例子。
  • 有。它被称为np.fromfunctionnumpy.org/doc/stable/reference/generated/…
  • 我已经为函数添加了一些细节。 np.fromfunction 仅将坐标作为输入,不是吗?不是来自另一个数组的行。
  • @user2640045,很容易误读fromfunction。它创建一组索引/网格点,并使用整个集合调用函数仅一次。它不是迭代器(或编译器)。
  • 只要f 只接受标量值(或更小的维度数组),您就无法避免循环。昂贵的步骤是多次评估该功能。为了获得numpy 的效率,该函数必须接受整个数组,幸运的是你的。

标签: python numpy


【解决方案1】:

您可以将单个for 循环与广播一起使用。这需要更改 gaussian 函数的实现以接受 2D 输入:

def gaussian(a,b,sigma):
    vec = a-b
    return np.exp(- np.sum(vec**2, axis=-1)/(2*sigma**2))


K = np.zeros((x.shape[0],x.shape[0]), dtype=np.float32)
for i in range(x.shape[0]):
    K[i] = gaussian(x[i:i+1], x)

理论上,即使没有任何 for 循环,您也可以再次使用广播来完成此操作,但这里将创建一个大小为 len(x)**2 * x.shape[1] 的中间数组,这可能会耗尽您的数组大小的内存:

K = gaussian(x[None, :, :], x[:, None, :])

【讨论】:

  • 谢谢!这让它快了很多!我正在使用的计算机有足够的 RAM 来应对 float32 的完整广播方法,最高可达 30,000**3。
猜你喜欢
  • 2021-06-03
  • 1970-01-01
  • 2017-05-02
  • 1970-01-01
  • 2021-08-28
  • 2015-09-25
  • 2021-06-24
  • 1970-01-01
  • 2022-01-20
相关资源
最近更新 更多