在知道多个列值时如何获取二维NumPy数组的行索引

8 投票
3 回答
12640 浏览
提问于 2025-04-16 11:18

假设我有一个二维的 numPy 数组,比如:

a = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]

我想知道如何找到某一行的索引,前提是我知道这行的多个值。例如,如果我知道第0列是2,第1列是5,我想知道满足这个条件的行索引(在这个例子中是第1行)。

在我的应用中,前两列是 (x,y) 坐标,第三列是关于这个坐标的信息。我想在列表中找到特定的坐标,以便我可以更改第三列的值。

编辑:为了更清楚,这里有一个非方形的例子:

a = [ [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18] ]

假设我知道我正在寻找的行在第0列是13,在第1列是14。我想返回那一行的索引。在这种情况下,我想返回索引2(第二行)。

或者更好的是,我想编辑那一行的第4列,这一行在第0列是13,在第1列是14。这里有一个我找到的解决方案(把值改成999):

a[(a[:,0]==13) & (a[:,1]==14), 3] = 999

结果是:

a = [ [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12], [13, 14, 15, 999, 17, 18] ]

如果这部分不清楚,我很抱歉。能不能有人指出我原始帖子中(编辑之前)哪里可以被不同理解,因为我有点看不明白。

谢谢。

编辑2:修正了第一次编辑中的错误(用粗体显示)

我现在明白我让这件事情变得混乱了。我的问题的解决方案在 eat 的解决方案的条件 b) 中描述得很好。谢谢。

3 个回答

2

按照unutbu的建议,使用

np.where(np.any(a==2,axis=0) & np.any(a==5,axis=0))

不会考虑到2在第0列,5在第1列的信息。所以,对于 a = np.array([[5, 2, 3], [2, 5, 6], [7, 8, 9]]),它会错误地返回 (array([0, 1]),)

相反,你可以使用

np.where((a[0]==2) & (a[1]==5))

来得到正确的结果 (array([1]),)

此外,如果你想编辑特定行的第2列,你可以跳过 np.where,直接用以下方式引用: a[2][(a[0]==2) & (a[1]==5)]。这样也可以进行赋值,比如 a[2][(a[0]==2) & (a[1]==5)] = 11

9
In [80]: a = np.array([ [1, 2, 3], [4, 5, 6], [7, 8, 9] ])
In [81]: a
Out[81]: 
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

a==2 会返回一个布尔类型的 numpy 数组,这个数组显示了条件为真(True)的位置:

In [82]: a==2
Out[82]: 
array([[False,  True, False],
       [False, False, False],
       [False, False, False]], dtype=bool)

你可以通过使用 np.any(...,axis=0) 来找到任何列中条件为真的地方:

In [83]: np.any(a==2,axis=0)
Out[83]: array([False,  True, False], dtype=bool)

In [84]: np.any(a==5,axis=0)
Out[84]: array([False,  True, False], dtype=bool)

如果你想找到同时满足两个条件的地方,可以使用 &

In [85]: np.any(a==2,axis=0) & np.any(a==5,axis=0)
Out[85]: array([False,  True, False], dtype=bool)

最后,你可以使用 np.where 找到那些同时满足条件的列的索引:

In [86]: np.where(np.any(a==2,axis=0) & np.any(a==5,axis=0))
Out[86]: (array([1]),)
4

这里有一些处理列或行条件的方法,灵感来自Python的设计理念。

In []: import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
...

所以根据第二条建议:
a) 对列的条件,应用到行上:

In []: a= arange(12).reshape(3, 4)
In []: a
Out[]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
In []: a[2, logical_and(1== a[0, :], 5== a[1, :])]+= 12
In []: a
Out[]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8, 21, 10, 11]])

b) 对行的条件,应用到列上:

In []: a= a.T
In []: a
Out[]:
array([[ 0,  4,  8],
       [ 1,  5, 21],
       [ 2,  6, 10],
       [ 3,  7, 11]])
In []: a[logical_and(1== a[:, 0], 5== a[:, 1]), 2]+= 12
In []: a
Out[]:
array([[ 0,  4,  8],
       [ 1,  5, 33],
       [ 2,  6, 10],
       [ 3,  7, 11]])

我希望这能让大家明白,在访问列和行时,始终要明确表达是很重要的。因为代码通常是由不同背景的人来阅读的。

撰写回答