如何在NumPy的outer函数中省略轴。

huangapple go评论101阅读模式
英文:

how omit axis on outer substaract numpy

问题

我正在计算欧几里德(或其他)距离的表格。这是一个空间距离的查找表。对于二维点,查找表格如下 table[x1, y1, x2, y2]。例如 table[0, 0, 0, 10] 应该等于 10table[0, 0, 10, 10] 应该是 14.142135623730951

我有一个可工作的示例,我想重写它,使其适用于具有任意维度的点。这段代码仅适用于二维情况。

  1. import numpy as np
  2. to = np.indices((5, 5)).T
  3. x_shape, y_shape, n_dim = to.shape
  4. x_sub = np.subtract.outer(to[..., 0], to[..., 0])
  5. y_sub = np.subtract.outer(to[..., 1], to[..., 1])
  6. distances = np.sqrt(x_sub ** 2 + y_sub ** 2)
  7. n_test = 5
  8. for i in np.random.choice(x_shape, n_test):
  9. for j in np.random.choice(y_shape, n_test):
  10. for k in np.random.choice(x_shape, n_test):
  11. for l in np.random.choice(y_shape, n_test):
  12. d = np.sqrt((i - k) ** 2 + (j - l) ** 2)
  13. assert (distances[i, j, k, l] == d)
  14. print('3[92m TEST PASSES')

现在,我可以简单地运行一个循环,并在每个维度上执行 np.subtract.outer,但我想知道是否有一种方法可以直接在索引上执行外部减法(就像 np.subtract.outer(to, to))。当我尝试这样做时,结果的形状是 (5, 5, 2, 5, 5, 2),而我需要的是 (5, 5, 5, 5, 2)。有人知道如何做到这一点吗?

从被接受的答案派生的解决方案:

  1. import numpy as np
  2. to = np.indices((5, 5, 5)).T
  3. sh = list(to.shape)
  4. n_dims = sh[-1]
  5. t = to.reshape(sh[:-1] + [1] * n_dims + [n_dims]) - to.reshape([1] * n_dims + sh[:-1] + [n_dims])
  6. distances = np.sqrt(np.sum(np.power(t, 2), axis=-1))
  7. n_test = 100
  8. idxs = np.indices(distances.shape).T.reshape(-1, n_dims * 2)
  9. for idx in np.random.permutation(idxs)[:n_test]:
  10. assert distances[tuple(idx)] == np.linalg.norm(idx[:n_dims] - idx[n_dims:])
  11. print('3[92m TEST PASSES')
英文:

I am computing a table of euclidean (or other) distances. This is a lookup for distances in a space. For 2-d points the lookup is done thusly table[x1,y1,x2,y2]. For instance table[0,0,0,10] should equal 10 and table[0,0,10,10] would be 14.142135623730951.

I have a working example that I would like to rewrite so that it works on points with an arbitrary number of dimensions. This code works only for two.

  1. import numpy as np
  2. to = np.indices((5, 5)).T
  3. x_shape, y_shape, n_dim = to.shape
  4. x_sub = np.subtract.outer(to[..., 0], to[..., 0])
  5. y_sub = np.subtract.outer(to[..., 1], to[..., 1])
  6. distances = np.sqrt(x_sub ** 2 + y_sub ** 2)
  7. n_test = 5
  8. for i in np.random.choice(x_shape, n_test):
  9. for j in np.random.choice(y_shape, n_test):
  10. for k in np.random.choice(x_shape, n_test):
  11. for l in np.random.choice(y_shape, n_test):
  12. d = np.sqrt((i - k) ** 2 + (j - l) ** 2)
  13. assert (distances[i, j, k, l] == d)
  14. print('3[92m TEST PASSES')

Now, I could simply run a loop and do np.subtract.outer on each dimm, but I would like to know if there is a way to do outer subtract on the indices directly. (As in np.subtract.outer(to, to))
When I try this the result has a shape of (5, 5, 2, 5, 5, 2) while what i need is (5, 5, 5, 5, 2). Anyone know how to do this?

Solution derived from accepted answer:

  1. import numpy as np
  2. to = np.indices((5, 5, 5)).T
  3. sh = list(to.shape)
  4. n_dims = sh[-1]
  5. t = to.reshape(sh[:-1] + [1] * n_dims + [n_dims]) - to.reshape([1] * n_dims + sh[:-1] + [n_dims])
  6. distances = np.sqrt(np.sum(np.power(t, 2), axis=-1))
  7. n_test = 100
  8. idxs = np.indices(distances.shape).T.reshape(-1, n_dims * 2)
  9. for idx in np.random.permutation(idxs)[:n_test]:
  10. assert distances[tuple(idx)] == np.linalg.norm(idx[:n_dims] - idx[n_dims:])
  11. print('3[92m TEST PASSES')

答案1

得分: 0

I'll illustrate with a (3,4) array:

在一个 (3,4) 的数组中进行演示:

In [9]: x = np.arange(12).reshape(3,4)
在 [9]: x = np.arange(12).reshape(3,4)

In [10]: np.subtract.outer(x,x).shape
在 [10]: np.subtract.outer(x,x).shape

Out[10]: (3, 4, 3, 4)
Out[10]: (3, 4, 3, 4)

But with broadcasting, we can do an 'outer' on first dimensions, while "sharing" the second. That can be generalized.

但是通过 broadcasting,我们可以在第一维上执行 'outer',同时"共享"第二维。这可以泛化。

In [11]: (x[:,None,:]-x[None,:,:]).shape
在 [11]: (x[:,None,:]-x[None,:,:]).shape

Out[11]: (3, 3, 4)
Out[11]: (3, 3, 4)

'outer' can be done with 'broadcasting'

'outer' 可以使用 'broadcasting' 完成

In [12]: np.allclose(np.subtract.outer(x,x), x[:,:,None,None]-x[None,None,:,:])
在 [12]: np.allclose(np.subtract.outer(x,x), x[:,:,None,None]-x[None,None,:,:])

Out[12]: True
Out[12]: True

英文:

I'll illustrate with a (3,4) array:

  1. In [9]: x = np.arange(12).reshape(3,4)
  2. In [10]: np.subtract.outer(x,x).shape
  3. Out[10]: (3, 4, 3, 4)

But with broadcasting, we can do an 'outer' on first dimensions, while "sharing" the second. That can be generalized.

  1. In [11]: (x[:,None,:]-x[None,:,:]).shape
  2. Out[11]: (3, 3, 4)

outer can be done with broadcasting

  1. In [12]: np.allclose(np.subtract.outer(x,x), x[:,:,None,None]-x[None,None,:,:])
  2. Out[12]: True

huangapple
  • 本文由 发表于 2023年3月1日 12:13:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/75599502.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定