这里发生了一些事情:numpy的矢量操作,添加单轴和广播。
首先,您应该能够了解
==魔术的作用。
假设我们从一个简单的标签数组开始。
==行为以矢量化的方式进行,这意味着我们可以将整个数组与一个标量进行比较,并获得一个包含每个逐元素比较的值的数组。例如:
>>> labels = np.array([1,2,0,0,2])>>> labels == 0array([False, False, True, True, False], dtype=bool)>>> (labels == 0).astype(np.float32)array([ 0., 0., 1., 1., 0.], dtype=float32)
首先,我们得到一个布尔数组,然后强制转换为浮点数:Python中的False == 0,而True == 1。因此,我们得出一个数组,该数组为0
labels(不等于0)和1(为不等于0)。
但是比较0并没有什么特别的,我们可以比较1或2或3以获得类似的结果:
>>> (labels == 2).astype(np.float32)array([ 0., 1., 0., 0., 1.], dtype=float32)
实际上,我们可以遍历每个可能的标签并生成此数组。我们可以使用listcomp:
>>> np.array([(labels == i).astype(np.float32) for i in np.arange(3)])array([[ 0., 0., 1., 1., 0.], [ 1., 0., 0., 0., 0.], [ 0., 1., 0., 0., 1.]], dtype=float32)
但这并没有真正利用numpy。我们要做的是将每个可能的标签与每个元素进行比较,然后将IOW进行比较
>>> np.arange(3)array([0, 1, 2])
与
>>> labelsarray([1, 2, 0, 0, 2])
这就是numpy广播的神奇之处。现在,它
labels是形状(5,)的一维对象。如果我们将其做成形状为(5,1)的二维对象,则该操作将在最后一个轴上“广播”,并且将获得形状(5,3)的输出,并比较其中的每个条目标签每个元素的范围。
首先,我们可以
labels使用
None(或
np.newaxis)添加一个“额外”轴,更改其形状:
>>> labels[:,None]array([[1], [2], [0], [0], [2]])>>> labels[:,None].shape(5, 1)
然后我们可以进行比较(这是我们之前所看的安排的转置,但这并不重要)。
>>> np.arange(3) == labels[:,None]array([[False, True, False], [False, False, True], [ True, False, False], [ True, False, False], [False, False, True]], dtype=bool)>>> (np.arange(3) == labels[:,None]).astype(np.float32)array([[ 0., 1., 0.], [ 0., 0., 1.], [ 1., 0., 0.], [ 1., 0., 0.], [ 0., 0., 1.]], dtype=float32)
以numpy广播非常强大,值得一读。