NumPy广播到所有维度

3

I have a 3d numpy array build like this:

a = np.ones((3,3,3))

我希望能够从给定的坐标开始,在所有维度上广播数值,但维度的数量可能不同。

例如,如果我有坐标(1,1,1),我可以执行以下三个功能:

a[1,1,:] = 0
a[1,:,1] = 0
a[:,1,1] = 0

并且结果将会是我期望的输出,即:
array([[[1., 1., 1.],
        [1., 0., 1.],
        [1., 1., 1.]],

       [[1., 0., 1.],
        [0., 0., 0.],
        [1., 0., 1.]],

       [[1., 1., 1.],
        [1., 0., 1.],
        [1., 1., 1.]]])

如果我获得了坐标(0,1,0),对应的广播将是:

a[0,1,:] = 0
a[0,:,0] = 0
a[:,1,0] = 0

有没有一种方法可以在一个操作中完成这个过程,而不是分成3部分操作?我问这个问题是因为我正在处理的实际数组具有更多的维度,这使得代码看起来冗长而又冗余。 另外,如果维数发生变化,我将不得不重写代码。
编辑:它不需要一次性完成,我只需要以编程方式在所有维度上进行操作,这样,如果维数发生变化,代码将保持不变。
编辑2:关于这个逻辑,我不确定是否相关,但我正在通过坐标在地图上给出一个点的值,并基于此,我知道地图上整个行、列和高度的值(这就是我用0更新所有3个的原因)。 在其他情况下,地图是2维的,我仍然知道行和列的相同信息,但无法找到适用于多维度的函数。

你能详细解释一下这句话吗:“从给定坐标点开始,在所有维度上同时广播值”?“同时”指的是什么?Python 中并没有“同时”的概念。如果你是指一个函数,请明确说明。此外,你的输出逻辑是什么?请解释清楚。 - Mazdak
就像我在问题结尾处编辑中所说的那样 - 它不需要是单个操作或同时发生,但我至少想要像手动逐行执行我的3个广播操作一样跨越维度循环。有3个操作,因为数组有3个维度。如果它只有2个维度,我只需要2行。但是如果维度数量变化了,我该怎么办呢? - Ofer Sadan
@Kasramvd,我已经将这个逻辑作为问题的编辑添加进去了。 - Ofer Sadan
看起来你想要找到坐标长度为2的项的组合,并将它们用于索引(切片),是这样吗? - Mazdak
@Kasramvd 是的,我选择了使用切片的答案,但我仍然想知道您是否有更好的建议。 - Ofer Sadan
3个回答

2

这个方法使用np.repeatnp.fill_diagonal来构建切片。

a = np.ones((3,3,3))
target = (0, 1, 0)
slices = np.repeat([target], a.ndim, axis=0).astype(object)
np.fill_diagonal(slices, slice(None))

# slices
# array([[slice(None, None, None), 1, 0],
#       [0, slice(None, None, None), 0],
#       [0, 1, slice(None, None, None)]], dtype=object)

for t in slices:
    a[tuple(t)] = 0

array([[[0., 1., 1.],
        [0., 0., 0.],
        [0., 1., 1.]],

       [[1., 1., 1.],
        [0., 1., 1.],
        [1., 1., 1.]],

       [[1., 1., 1.],
        [0., 1., 1.],
        [1., 1., 1.]]])

np.repeat([target], a.ndim, axis=0) 重复了 (0, 1, 0) a.ndim 次,返回结果如下:

array([[0, 1, 0],
       [0, 1, 0],
       [0, 1, 0]])

然后,我们想要将每行的一部分更改为 slice(None)。我们不能直接这样做,因为 slice 对象的类型与 int 不同。因此,我们使用 astype(object) 来更改数组的类型。


请翻译以下与编程有关的内容,从英语到中文。仅返回已翻译的文本。 - mkrieger1
测试并且工作正常,也弄清了机制,非常好的答案! - Ofer Sadan
@OferSadan 感谢您的评论和验证。我很感激。 - Tai

2
你想要做的可以通过使用slice函数来实现。例如,可以使用slice对象进行编程操作,详细信息请参见《在程序中处理变量数量的索引》。请注意,保留html标记。
def broadcast_val(mat, val, indices):
    shape = mat.shape
    for i in len(indices):
        len_axis = shape[i]
        i_axis = slice(len_axis)
        index_tuple = *indices[:i], i_axis, *indices[i+1:]
        mat[index_tuple] = val

我想知道是否有可能使用单个赋值语句来实现您想要的内容...


我也很好奇... 我选择了另一个答案,因为它更易读,但还是感谢你的帮助,那个链接确实让我找到了正确的方向。 - Ofer Sadan

1
以下是一种生成与您当前使用的三行代码完全相同的字符串并执行它们的方法:
import numpy as np

a = np.ones([3,3,3])
coord = [1, 1, 1]

for i in range(len(coord)):
   temp = coord[:]
   temp[i] = ':'
   slice_str = ','.join(map(str, temp))
   exec("a[%s] = 0"%slice_str)

print a

这可能不是最好的方法,但至少很有趣。现在我们知道它可行,我们可以去寻找适当的语法来实现它,而不必生成字符串并执行它。例如,你可以使用 slice:
import numpy as np

a = np.ones([3,3,3])
coord = [1, 1, 1]

for i, length in enumerate(a.shape):
   temp = coord[:]
   temp[i] = slice(length)
   a[temp] = 0
print a

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