Python 广播2d数组的一列与多列的比较

Python 广播2d数组的一列与多列的比较,python,arrays,numpy,array-broadcasting,Python,Arrays,Numpy,Array Broadcasting,在2d数组中比较一列和其他列的正确numpy语法是什么 在阅读了阵列广播之后,我仍然不太确定这样做的正确方法是什么 示例:假设在每场比赛(列)中,每个玩家(行)都有一个2d进球数组 我想知道的是,在最后一场比赛中,球员是否取得了个人记录,进球数超过了以往任何一场比赛,忽略了她没有出现的比赛(表示为nan)。我希望True仅适用于阵列中的第一个和最后一个玩家 仅编写goals[:,2]>goals[:,:2]返回ValueError:操作数无法与形状(5,)(5,2)一起广播 我尝试的内容:我知道

在2d数组中比较一列和其他列的正确numpy语法是什么

在阅读了阵列广播之后,我仍然不太确定这样做的正确方法是什么

示例:假设在每场比赛(列)中,每个玩家(行)都有一个2d进球数组

我想知道的是,在最后一场比赛中,球员是否取得了个人记录,进球数超过了以往任何一场比赛,忽略了她没有出现的比赛(表示为
nan
)。我希望
True
仅适用于阵列中的第一个和最后一个玩家

仅编写
goals[:,2]>goals[:,:2]
返回
ValueError:操作数无法与形状(5,)(5,2)一起广播

我尝试的内容:我知道我可以使用
np.newaxis
手动将
(5,)
拉伸到
(5,2)
。所以这是可行的:

with np.errstate(invalid='ignore'):
  personalBest= ( np.isnan(goals[:,:2]) | 
                  (goals[:,2][:,np.newaxis] > goals[:,:2] ) 
                 ).all(axis=1)

print(personalBest) # returns desired solution

有没有一种不那么粗俗、更惯用的方式来写这篇文章?

你可以这样做-

np.flatnonzero((goals[:,None,-1] > goals[:,:-1]).any(1))
让我们一步一步地看一遍

步骤#1:我们将在最后一个列切片版本上引入一个新轴,以保持其为
2D
,最后一个轴是一个单一维度/轴。其思想是将其每个元素与该行中除元素本身之外的所有元素进行比较:

In [3]: goals[:,None,-1]
Out[3]: 
array([[  1.],
       [  0.],
       [ nan],
       [  1.],
       [  1.]])

In [4]: goals[:,None,-1].shape # Check the shapes for broadcasting alignment
Out[4]: (5, 1)

In [5]: goals.shape
Out[5]: (5, 3)
步骤#2:下一步,我们实际上是对跳过最后一列本身的数组的所有列执行比较,因为这是前面获得的切片版本的一部分-

In [7]: goals[:,None,-1] > goals[:,:-1]
Out[7]: 
array([[False,  True],
       [False, False],
       [False, False],
       [False, False],
       [ True,  True]], dtype=bool)
第3步:然后,我们检查每行是否有匹配项-

In [8]: (goals[:,None,-1] > goals[:,:-1]).any(axis=1)
Out[8]: array([ True, False, False, False,  True], dtype=bool)
第4步:最后,使用
np.flatnonzero
-

In [9]: np.flatnonzero((goals[:,None,-1] > goals[:,:-1]).any(axis=1))
Out[9]: array([0, 4])

只需关注
newaxis
位:

In [332]: goals = np.arange(12).reshape(3,4)
In [333]: goals[:,2]>goals[:,:2]
...
ValueError: operands could not be broadcast together with shapes (3,) (3,2)
因此,目标是制作第一个形状数组(3,1),以便可以针对(3,2)进行广播:

我们可以使用列表或切片进行索引:
goals[:,2:3]
也可以

In [334]: goals[:,[2]]>goals[:,:2]
Out[334]: 
array([[ True,  True],
       [ True,  True],
       [ True,  True]], dtype=bool)
我们可以显式添加
newaxis
(通用)

我们可以将这两种索引操作结合起来(这并不常见)

我们可以明确地重塑:

In [339]: goals[:,2].reshape(-1,1)>goals[:,:2]
Out[339]: 
array([[ True,  True],
       [ True,  True],
       [ True,  True]], dtype=bool)
我认为执行时间差别不大。这些都是好的
numpy
code

========


如果这两个数组是(3,)和(2,3),我们就不需要这些了。numpy广播自动将第一个扩展到(1,3)。实际上,
x[None,:]
是自动的,但
x[:,None]
不是。

很好的解释-这个答案指向了我读到的:
*numpy.newaxis:*newaxis对象可以在所有切片操作中使用,以创建长度为1的轴。:const:newaxis是“None”的别名,可以使用“None”来代替它,结果相同。
@C8H10N4O2当然!因此,有了这个理论,我们也可以做
goals[:,-1,None]
,但随着切片,最后一个轴消失了,因此实际上它与
goals[:,None,-1]
相同,无论哪种方式,都会给我们留下一个作为单体的最后一个轴
np.newaxis
正是为了这样的目的而提供的。
In [335]: goals[:,2][:,None]>goals[:,:2]
Out[335]: 
array([[ True,  True],
       [ True,  True],
       [ True,  True]], dtype=bool)
In [336]: goals[:,2,None]>goals[:,:2]
Out[336]: 
array([[ True,  True],
       [ True,  True],
       [ True,  True]], dtype=bool)
In [339]: goals[:,2].reshape(-1,1)>goals[:,:2]
Out[339]: 
array([[ True,  True],
       [ True,  True],
       [ True,  True]], dtype=bool)