我认为我在numpy中误解了索引。
我有一个形状为(dim_x, dim_y, dim_z)
的3D-numpy数组,我希望沿第三轴(dim_z)
找到最大值,并将其值设置为1,将其他所有值设置为零。
问题在于,即使值不同,我最终会在同一行中使用多个1。
以下是代码:
>>> test = np.random.rand(2,3,2)
>>> test
array([[[ 0.13110146, 0.07138861],
[ 0.84444158, 0.35296986],
[ 0.97414498, 0.63728852]],
[[ 0.61301975, 0.02313646],
[ 0.14251848, 0.91090492],
[ 0.14217992, 0.41549218]]])
>>> result = np.zeros_like(test)
>>> result[:test.shape[0], np.arange(test.shape[1]), np.argmax(test, axis=2)]=1
>>> result
array([[[ 1., 0.],
[ 1., 1.],
[ 1., 1.]],
[[ 1., 0.],
[ 1., 1.],
[ 1., 1.]]])
我期待以:
结束array([[[ 1., 0.],
[ 1., 0.],
[ 1., 0.]],
[[ 1., 0.],
[ 0., 1.],
[ 0., 1.]]])
可能我在这里遗漏了一些东西。根据我的理解,0:dim_x, np.arange(dim_y)
会返回dim_x
个dim_y
元组,np.argmax(test, axis=dim_z)
的形状为(dim_x, dim_y)
,因此如果索引的形式为[x, y, z]
{1}}一对[x, y]
不应该出现两次。
有人能解释我哪里错了吗?提前谢谢。
答案 0 :(得分:1)
我们在寻找什么
我们沿最后一轴获得argmax指数 -
idx = np.argmax(test, axis=2)
对于给定的样本数据,我们有idx
:
array([[0, 0, 0],
[0, 1, 1]])
现在,idx
涵盖第一和第二轴,同时获得argmax
个索引。
要在输出中指定相应的那些,我们需要为前两个轴创建范围数组,覆盖长度和根据idx
的形状对齐。现在,idx
是一个2D
形状(m,n)
数组,其中m = test.shape[0]
和n = test.shape[1]
。
因此,用于分配到前两个输出轴的范围数组必须是 -
X = np.arange(test.shape[0])[:,None]
Y = np.arange(test.shape[1])
注意,需要将第一个范围数组扩展到2D
,以使其与idx
的行对齐,而Y
将与idx
的列对齐 -
In [239]: X
Out[239]:
array([[0],
[1]])
In [240]: Y
Out[240]: array([0, 1, 2])
示意放 -
idx :
Y array
--------->
x x x | X array
x x x |
v
原始代码中的错误
您的代码是 -
result[:test.shape[0], np.arange(test.shape[1]), ..
这基本上是:
result[:, np.arange(test.shape[1]), ...
因此,您选择沿第一轴的所有元素,而不是仅选择对应于idx
索引的相应元素。在这个过程中,您选择的元素多于分配所需的元素,因此您在1s
数组中看到的不仅仅是result
所需的内容。
更正
因此,唯一需要的修正是使用范围数组索引到第一个轴,并且工作解决方案将是 -
result[np.arange(test.shape[0])[:,None], np.arange(test.shape[1]), ...
备选方案
或者,使用之前使用X
和Y
-
result[X,Y,idx] = 1
获取X,Y
的另一种方法是使用np.mgrid
-
m,n = test.shape[:2]
X,Y = np.ogrid[:m,:n]
答案 1 :(得分:0)
这是一种更简单的方法:
>>> test == test.max(axis=2, keepdims=1)
array([[[ True, False],
[ True, False],
[ True, False]],
[[ True, False],
[False, True],
[False, True]]], dtype=bool)
...如果你真的想要它作为浮点1.0和0.0,那么转换它:
>>> (test==test.max(axis=2, keepdims=1)).astype(float)
array([[[ 1., 0.],
[ 1., 0.],
[ 1., 0.]],
[[ 1., 0.],
[ 0., 1.],
[ 0., 1.]]])
这是一种方法,每行只有一个获胜者 - 列组合(即没有关系,如评论中所述):
rowmesh, colmesh = np.meshgrid(range(test.shape[0]), range(test.shape[1]), indexing='ij')
maxloc = np.argmax(test, axis=2)
flatind = np.ravel_multi_index( [rowmesh, colmesh, maxloc ], test.shape )
result = np.zeros_like(test)
result.flat[flatind] = 1
阅读hpaulj的答案后更新:
rowmesh, colmesh = np.ix_(range(test.shape[0]), range(test.shape[1]))
是我meshgrid
调用的一种更高效,更简洁的替代方案(其余代码保持不变)
为什么你的方法失败的问题很难解释,但这里有一个直觉可以开始的地方:你的切片方法说“所有行,所有列的次数,时间是一定层次的” 。这个切片总共有多少个元素?相比之下,您实际想要将多少个元素设置为1?查看您尝试分配给的切片的相应test
值时,可以看到所获得的值,这是有益的:
>>> test[:, :, maxloc].shape
(2, 3, 2, 3) # oops! it's because maxloc itself is 2x3
>>> test[:, :, maxloc]
array([[[[ 0.13110146, 0.13110146, 0.13110146],
[ 0.13110146, 0.07138861, 0.07138861]],
[[ 0.84444158, 0.84444158, 0.84444158],
[ 0.84444158, 0.35296986, 0.35296986]],
[[ 0.97414498, 0.97414498, 0.97414498],
[ 0.97414498, 0.63728852, 0.63728852]]],
[[[ 0.61301975, 0.61301975, 0.61301975],
[ 0.61301975, 0.02313646, 0.02313646]],
[[ 0.14251848, 0.14251848, 0.14251848],
[ 0.14251848, 0.91090492, 0.91090492]],
[[ 0.14217992, 0.14217992, 0.14217992],
[ 0.14217992, 0.41549218, 0.41549218]]]]) # note the repetition, because in maxloc you're repeatedly asking for layer 0 sometimes, and sometimes repeatedly for layer 1
答案 2 :(得分:0)
我认为混合基本(切片)和高级索引存在问题。从数组中选择值比使用此赋值更容易看到;但它可能导致转置轴。对于这样的问题,最好使用ix_
In [24]: test = np.random.rand(2,3,2)
In [25]: idx=np.argmax(test,axis=2)
In [26]: idx
Out[26]:
array([[1, 0, 1],
[0, 1, 1]], dtype=int32)
基础和高级:
In [31]: res1 = np.zeros_like(test)
In [32]: res1[:, np.arange(test.shape[1]), idx]=1
In [33]: res1
Out[33]:
array([[[ 1., 1.],
[ 1., 1.],
[ 0., 1.]],
[[ 1., 1.],
[ 1., 1.],
[ 0., 1.]]])
高级:
In [35]: I,J = np.ix_(range(test.shape[0]), range(test.shape[1]))
In [36]: I
Out[36]:
array([[0],
[1]])
In [37]: J
Out[37]: array([[0, 1, 2]])
In [38]: res2 = np.zeros_like(test)
In [40]: res2[I, J , idx]=1
In [41]: res2
Out[41]:
array([[[ 0., 1.],
[ 1., 0.],
[ 0., 1.]],
[[ 1., 0.],
[ 0., 1.],
[ 0., 1.]]])
进一步考虑,如果目标是设置或找到6个argmax值,则使用第一维的切片是错误的
In [54]: test
Out[54]:
array([[[ 0.15288242, 0.36013289],
[ 0.90794601, 0.15265616],
[ 0.34014976, 0.53804266]],
[[ 0.97979479, 0.15898605],
[ 0.04933804, 0.89804999],
[ 0.10199319, 0.76170911]]])
In [55]: test[I, J, idx]
Out[55]:
array([[ 0.36013289, 0.90794601, 0.53804266],
[ 0.97979479, 0.89804999, 0.76170911]])
In [56]: test[:, J, idx]
Out[56]:
array([[[ 0.36013289, 0.90794601, 0.53804266],
[ 0.15288242, 0.15265616, 0.53804266]],
[[ 0.15898605, 0.04933804, 0.76170911],
[ 0.97979479, 0.89804999, 0.76170911]]])
使用切片,它从test
(或res
)中选择(2,3,2)一组值,而不是预期的(2,3)。还有2行。