用位于 Mx2 numpy 数组中的元素替换 Nx3x2 numpy 数组中的元素

Replace elements in an Nx3x2 numpy array with elements located in an Mx2 numpy array

我有以下 xy 代表一些三角形顶点位置的 numpy 数组:

array([[[ 0.30539728, 49.82845203],
        [ 0.67235022, 49.95042185],
        [ 0.268982  , 49.95195348]],
       [[ 0.268982  , 49.95195348],
        [ 0.67235022, 49.95042185],
        [ 0.27000135, 50.16334035]],
       ...
       [[ 1.00647459, 50.25958169],
        [ 0.79479121, 50.3010079 ],
        [ 0.67235022, 49.95042185]],
       [[ 0.79479121, 50.3010079 ],
        [ 0.6886783 , 50.25867683],
        [ 0.67235022, 49.95042185]]])

在这里,它是一个形状为 (10, 3, 2) 的数组,但它也可以是 (5, 3, 2)(18, 3, 2),随你便。在任何情况下,它的形状都是 (N, 3, 2)。 我有另一个形状 (4, 2) 的 numpy 数组 to_replace 但它也可以是 (6, 2)(7, 2),但总是形状 (M, 2):

array([[ 1.08267406, 49.88690993],
       [ 1.1028248 , 50.01440407],
       [ 0.74114309, 49.73183549],
       [ 1.08267406, 49.88690993]])

它表示可以在我的第一个数组中找到的坐标对的位置。请注意,这些对中的每一对在 xy 中至少出现一次,但也可能出现不止一次。 最后,我有第三个数组 replace_by,其形状为 (8,)(或根据上面的指示形状为 (M*2)),其值旨在准确替换 [=19= 中包含的值] 在我的第一个 xy 数组中。它看起来像这样:

array([ 0.87751214, 49.91866589,  0.88758751, 49.98241296,  0.70674665, 49.84112867,  0.87751214, 49.91866589])

所以基本上 xy 中的所有对 [1.08267406, 49.88690993] 都应该替换为 [0.87751214, 49.91866589] 例如。

我当前的代码看起来像这样,但只有当 to_replacereplace_by 的形状严格为 (2, 2).

时它才有效
indices = (xy == to_replace[:, None][:, None])[0]
xy[indices] = replace_by

at a of answers 并且实际上受到了其中一些的启发,但我仍然无法让它发挥作用。

您可以使用 numpy.isclose 比较行,然后使用 .all(axis=2) 查找所有最后一行的相同之处。 Numpy 将广播每一行以适应 xy 形状。

import numpy as np
xy = np.array([[[ 0.30539728, 49.82845203],
        [ 0.67235022, 49.95042185],
        [ 0.268982  , 49.95195348]],
       [[ 0.268982  , 49.95195348],
        [ 0.67235022, 49.95042185],
        [ 0.27000135, 50.16334035]],
       [[ 1.00647459, 50.25958169],
        [ 0.79479121, 50.3010079 ],
        [ 0.67235022, 49.95042185]],
       [[ 0.79479121, 50.3010079 ],
        [ 0.6886783 , 50.25867683],
        [ 0.67235022, 49.95042185]]])
xy_start = xy.copy()


to_replace = np.array([[ 1.08267406, 49.88690993],
       [ 1.1028248 , 50.01440407],
       # [ 0.74114309, 49.73183549],
       [ 0.6886783 , 50.25867683],
       [ 1.08267406, 49.88690993]])

replace_by = np.array([ 0.87751214, 49.91866589,  0.88758751, 49.98241296,  0.70674665, 49.84112867,  0.87751214, 49.91866589])
replace_by_reshaped = replace_by.reshape(-1, 2)

for i, row in enumerate(to_replace):
    xy[np.isclose(xy, row).all(axis=2)] = replace_by_reshaped[i]
print(xy_start)
# [[[ 0.30539728 49.82845203]
#   [ 0.67235022 49.95042185]
#   [ 0.268982   49.95195348]]

#  [[ 0.268982   49.95195348]
#   [ 0.67235022 49.95042185]
#   [ 0.27000135 50.16334035]]

#  [[ 1.00647459 50.25958169]
#   [ 0.79479121 50.3010079 ]
#   [ 0.67235022 49.95042185]]

#  [[ 0.79479121 50.3010079 ]
#   [ 0.6886783  50.25867683]
#   [ 0.67235022 49.95042185]]]
print(xy)
# [[[ 0.30539728 49.82845203]
#   [ 0.67235022 49.95042185]
#   [ 0.268982   49.95195348]]

#  [[ 0.268982   49.95195348]
#   [ 0.67235022 49.95042185]
#   [ 0.27000135 50.16334035]]

#  [[ 1.00647459 50.25958169]
#   [ 0.79479121 50.3010079 ]
#   [ 0.67235022 49.95042185]]

#  [[ 0.79479121 50.3010079 ]
#   [ 0.70674665 49.84112867]
#   [ 0.67235022 49.95042185]]]

编辑

.all(axis=2) shrink axis=2 to True if all values along axis=2 are True and False else.我认为 2d 的小例子清楚地说明了这里发生的事情。

>>> import numpy as np
>>> a = np.array([[0, 1], [0, 2], [3, 4]])
>>> a
array([[0, 1],
       [0, 2],
       [3, 4]])
>>> np.isclose(a, [0, 1])
array([[ True,  True],
       [ True, False],
       [False, False]])
>>> np.isclose(a, [0, 1]).all(axis=1)
array([ True, False, False])
>>> a[np.isclose(a, [0, 1]).all(axis=1)]
array([[0, 1]])
>>> a[np.isclose(a, [0, 1]).all(axis=1)] = [12, 14]
>>> a
array([[12, 14],
       [ 0,  2],
       [ 3,  4]])

numpy-indexed 包(免责声明:我是其作者)包含以矢量化和优雅的方式解决此问题的功能。

鉴于您定义的数组,这一行应该可以解决问题:

import numpy_indexed as npi    
npi.remap(xy.reshape(-1, 2), to_replace, replace_by.reshape(-1, 2)).reshape(-1, 3, 2)