用于编辑计数数组的单行解决方案?(蟒蛇)



我想创建一个numpy数组,其中包含一个值(1-3之间(在特定位置出现的次数。例如,如果我有:

a = np.array([[1,2,3], 
[3,2,1], 
[2,1,3], 
[1,1,1]])

我想像这样返回一个数组:

[[[ 1  0  0]
[ 0  1  0]
[ 0  0  1]]
[[ 0  0  1]
[ 0  1  0]
[ 1  0  0]]
[[ 0  1  0]
[ 1  0  0]
[ 0  0  1]]
[[ 1  0  0]
[ 1  0  0]
[ 1  0  0]]]

数组告诉我 1 在第一个位置出现一次,2 在第二个位置出现一次,3 在第三个位置出现一次,1 在第四个位置出现一次,依此类推。稍后,我将拥有更多相同维度的输入数组,我想将值的总数添加到此计数数组中。

我现在的代码是:

a = np.array([[1,2,3],
[3,2,1],
[2,1,3],
[1,1,1]])
cumulative = np.zeros((4,3,3))
for r in range(len(cumulative)):
for c in range(len(cumulative[0])):
cumulative[r, c, a[r,c]-1] +=1

这确实给了我想要的输出。但是,我想使用类似于下面的行将 for 循环压缩为一行:

cumulative[:, :, a[:, :]-1] +=1

这一行不起作用,我在网上找不到有关如何执行此操作的任何内容。有什么建议吗?

IIUC,你可以利用广播:

In [93]: ((a[:, None] - 1) == np.arange(3)[:, None]).swapaxes(2, 1).astype(int)
Out[93]: 
array([[[1, 0, 0],
[0, 1, 0],
[0, 0, 1]],
[[0, 0, 1],
[0, 1, 0],
[1, 0, 0]],
[[0, 1, 0],
[1, 0, 0],
[0, 0, 1]],
[[1, 0, 0],
[1, 0, 0],
[1, 0, 0]]])

从技术上讲,它不是单行,但如果您忽略 PEP 8 的最大行长度,则可以将其缩减为两行。

a = np.array([[1,2,3],
[3,2,1],
[2,1,3],
[1,1,1]])
out = np.zeros((a.shape[0], 1 + a.max() - a.min(), a.shape[1]), dtype=np.int8)
out[np.repeat(np.arange(a.shape[0]), a.shape[1]), np.subtract(
a, a.min())[:].flatten(), np.tile(np.arange(a.shape[1]), a.shape[0])] = 1
print(out)

哪些输出;

[[[1 0 0]
[0 1 0]
[0 0 1]]
[[0 0 1]
[0 1 0]
[1 0 0]]
[[0 1 0]
[1 0 0]
[0 0 1]]
[[1 0 0]
[1 0 0]
[1 0 0]]]

这可能不是最有益或最优雅的解决方案,不幸的是没有扩展到n维,但希望这(几乎是一行(对您来说足够矢量化。


非常沉重,所以我将简要介绍一下它是如何工作的。

  • 默认情况下,输出数组被创建为满零,"one-hot vectors"的总长度等于输入数组的范围(我假设这是您想要的,因为您的示例中没有给出的值零的行(。

  • np.tilenp.repeatnp.arange一起使用以生成第一个和最后一个索引数组,即a中每个元素的索引。

  • 花式指示用于将匹配数字的索引设置为 1。

np.concatenate((a==1,a==2,a==3),axis=1).reshape((4,3,3)).transpose(0,2,1) + 0

最新更新